using System; using System.Collections.Generic; using DG.DemiEditor; using Framework; using Gameplay.Utils; using PhxhSDK; using UnityEditor; using UnityEngine; namespace CharacterBuilder { public class CharacterBuilderWindow : EditorWindow { [MenuItem("Tools/*角色工具/角色构建器", false, (int)NLDMenuID.CharacterBuilder)] public static void ShowWindow() { var window = GetWindow(); window.titleContent = new UnityEngine.GUIContent("角色构建器"); window.Show(); } // [MenuItem("Test/测试")] // public static void TestFunc() // { // } private Vector2 _scrollPos1; private Vector2 _scrollPos2; private Vector2 _scrollPos3; private GUIStyle _styleNormal; private GUIStyle _styleError; private List _characterBuildDataList; private List _monsterBuildDataList; private List _npcBuildDataList; private Dictionary _animclipMap; private void _CheckAllConfigs() { // 加载指定路径下的所有animationclip文件 var allAnimationClips = AssetDatabase.FindAssets("t:AnimationClip", new[] { "Assets/Art/Animations/Battle/Motion", "Assets/Art/Animations/Battle/Skill" }); var dictAnimationClips = new Dictionary(); for (int i = 0; i < allAnimationClips.Length; i++) { var guid = allAnimationClips[i]; var path = AssetDatabase.GUIDToAssetPath(guid); var clip = AssetDatabase.LoadAssetAtPath(path); var clipName = clip.name; if (!dictAnimationClips.TryAdd(clipName, clip)) { Debug.LogError("重复的动画文件:" + clipName); continue; } } _animclipMap = dictAnimationClips; for (int i = 0; i < _characterBuildDataList.Count; i++) { var buildData = _characterBuildDataList[i]; buildData.errorInfo = null; if (buildData.weaponConfigList.Count == 0) { buildData.errorInfo = "未配置武器组"; continue; } if (buildData.skins.Count == 0) { buildData.errorInfo = "未配置皮肤"; continue; } for (int j = 0; j < buildData.skins.Count; j++) { var skinConfig = buildData.skins[j]; var prefabPath = PathEx.GetCharacterSrcModelPath(skinConfig.NameID); if (string.IsNullOrEmpty(prefabPath)) { buildData.errorInfo = "皮肤" + skinConfig.Name + "未配置预制体"; continue; } var loadPrefab = AssetDatabase.LoadAssetAtPath(prefabPath); if (loadPrefab == null) { buildData.errorInfo = "预制体" + prefabPath + "不存在"; break; } } if (buildData.errorInfo != null) { continue; } var checkAnim = buildData.CheckAnims(dictAnimationClips); if (!string.IsNullOrEmpty(checkAnim)) { buildData.errorInfo = checkAnim; continue; } } for (int i = 0; i < _monsterBuildDataList.Count; i++) { var buildData = _monsterBuildDataList[i]; buildData.errorInfo = null; var weaponConfig = EditorTableManager.instance.tables.WeaponConfig.Get(buildData.mainConfig.WeaponId); if (weaponConfig == null) { buildData.errorInfo = "无效的武器ID:" + buildData.mainConfig.WeaponId; continue; } if (string.IsNullOrEmpty(weaponConfig.GroupName)) { buildData.errorInfo = "未配置武器组"; continue; } var checkAnim = buildData.CheckAnims(dictAnimationClips); if (!string.IsNullOrEmpty(checkAnim)) { buildData.errorInfo = checkAnim; continue; } } for (int i = 0; i < _npcBuildDataList.Count; i++) { var buildData = _npcBuildDataList[i]; buildData.errorInfo = null; var weaponConfig = EditorTableManager.instance.tables.WeaponConfig.Get(buildData.mainConfig.WeaponId); if (weaponConfig == null) { buildData.errorInfo = "无效的武器ID:" + buildData.mainConfig.WeaponId; continue; } if (string.IsNullOrEmpty(weaponConfig.GroupName)) { buildData.errorInfo = "未配置武器组"; continue; } var checkAnim = buildData.CheckAnims(dictAnimationClips); if (!string.IsNullOrEmpty(checkAnim)) { buildData.errorInfo = checkAnim; continue; } } } private void _BuildDatas() { _characterBuildDataList = new List(); var characterConfigList = EditorTableManager.instance.tables.CharacterAttri.DataList; for (int i = 0; i < characterConfigList.Count; i++) { var cConfig = characterConfigList[i]; var buildData = new CharacterBuildData(cConfig); _characterBuildDataList.Add(buildData); } _monsterBuildDataList = new List(); var monsterClassDataList = EditorTableManager.instance.tables.MonsterClass.DataList; for (int i = 0; i < monsterClassDataList.Count; i++) { var cConfig = monsterClassDataList[i]; if (cConfig.EnemyType != 1) { continue; } var buildData = new MonsterBuildData(cConfig); _monsterBuildDataList.Add(buildData); } _npcBuildDataList = new List(); var npcDataList = EditorTableManager.instance.tables.FightNPCConfig.DataList; for (int i = 0; i < npcDataList.Count; i++) { var cConfig = npcDataList[i]; var buildData = new NpcBuildData(cConfig); _npcBuildDataList.Add(buildData); } _CheckAllConfigs(); _styleNormal = GUI.skin.label.Clone(); _styleNormal.normal.textColor = Color.white; _styleNormal.focused.textColor = Color.white; _styleNormal.hover.textColor = Color.white; _styleNormal.active.textColor = Color.white; _styleError = GUI.skin.label.Clone(); _styleError.normal.textColor = Color.red; _styleError.focused.textColor = Color.red; _styleError.hover.textColor = Color.red; _styleError.active.textColor = Color.red; } private void OnGUI() { if (_characterBuildDataList == null) { _BuildDatas(); } if (_characterBuildDataList == null) { return; } GUILayout.BeginHorizontal(); GUILayout.Label($"当前共有角色配置:{_characterBuildDataList.Count} 个, " + $"敌人配置:{_monsterBuildDataList.Count} 个, " + $"NPC配置:{_npcBuildDataList.Count} 个"); if (GUILayout.Button("刷新")) { EditorTableManager.instance.ForceReload(); _characterBuildDataList = null; GUILayout.EndHorizontal(); return; } GUILayout.EndHorizontal(); _ShowCharacters(); _ShowNpcs(); _ShowMonsters(); if (GUILayout.Button("开始构建")) { _Build(); } } private void _ShowNpcs() { GUILayout.Label("NPC配置"); var totalHeight = _npcBuildDataList.Count * 40; var maxHeight = 200; if (totalHeight < maxHeight) { maxHeight = totalHeight; } _scrollPos3 = EditorGUILayout.BeginScrollView(_scrollPos3, GUILayout.Height(maxHeight)); GUILayout.BeginVertical(); for (int i = 0; i < _npcBuildDataList.Count; i++) { var buildData = _npcBuildDataList[i]; var isError = !string.IsNullOrEmpty(buildData.errorInfo); var style = isError ? _styleError : _styleNormal; GUILayout.BeginHorizontal(); buildData.isChecked = GUILayout.Toggle(buildData.isChecked, "", GUILayout.Width(20)); var isChecked = buildData.isChecked; var cConfig = buildData.mainConfig; GUILayout.Label("ID:" + cConfig.NameId, GUILayout.Width(80)); GUILayout.Label("名称:" + cConfig.NameRead, style, GUILayout.Width(90)); GUILayout.Label("使用武器:" + buildData.weaponIdsStr); GUILayout.EndHorizontal(); _ShowEmojiInfo(buildData); if (isError && isChecked) { GUILayout.BeginHorizontal(); GUILayout.Space(100); GUILayout.Label(buildData.errorInfo, style); GUILayout.EndHorizontal(); } } GUILayout.EndVertical(); EditorGUILayout.EndScrollView(); GUILayout.BeginHorizontal(); if (GUILayout.Button("全选")) { for (var i = 0; i < _npcBuildDataList.Count; ++i) { _npcBuildDataList[i].isChecked = true; } } if (GUILayout.Button("全不选")) { for (var i = 0; i < _npcBuildDataList.Count; ++i) { _npcBuildDataList[i].isChecked = false; } } GUILayout.EndHorizontal(); } private void _ShowMonsters() { GUILayout.Label("敌人配置"); var totalHeight = _monsterBuildDataList.Count * 40; var maxHeight = 200; if (totalHeight < maxHeight) { maxHeight = totalHeight; } _scrollPos2 = EditorGUILayout.BeginScrollView(_scrollPos2, GUILayout.Height(maxHeight)); GUILayout.BeginVertical(); for (int i = 0; i < _monsterBuildDataList.Count; i++) { var buildData = _monsterBuildDataList[i]; var isError = !string.IsNullOrEmpty(buildData.errorInfo); var style = isError ? _styleError : _styleNormal; GUILayout.BeginHorizontal(); buildData.isChecked = GUILayout.Toggle(buildData.isChecked, "", GUILayout.Width(20)); var isChecked = buildData.isChecked; var cConfig = buildData.mainConfig; GUILayout.Label("ID:" + cConfig.NameId, GUILayout.Width(80)); GUILayout.Label("名称:" + cConfig.Name, style, GUILayout.Width(120)); GUILayout.Label("使用武器:" + buildData.weaponIdsStr); GUILayout.EndHorizontal(); _ShowEmojiInfo(buildData); if (isError && isChecked) { GUILayout.BeginHorizontal(); GUILayout.Space(100); GUILayout.Label(buildData.errorInfo, style); GUILayout.EndHorizontal(); } } GUILayout.EndVertical(); EditorGUILayout.EndScrollView(); GUILayout.BeginHorizontal(); if (GUILayout.Button("全选")) { for (var i = 0; i < _monsterBuildDataList.Count; ++i) { _monsterBuildDataList[i].isChecked = true; } } if (GUILayout.Button("全不选")) { for (var i = 0; i < _monsterBuildDataList.Count; ++i) { _monsterBuildDataList[i].isChecked = false; } } GUILayout.EndHorizontal(); } private void _ShowCharacters() { GUILayout.Label("角色配置"); var totalHeight = _characterBuildDataList.Count * 40; var maxHeight = 200; if (totalHeight < maxHeight) { maxHeight = totalHeight; } _scrollPos1 = EditorGUILayout.BeginScrollView(_scrollPos1, GUILayout.Height(maxHeight)); GUILayout.BeginVertical(); for (int i = 0; i < _characterBuildDataList.Count; i++) { var buildData = _characterBuildDataList[i]; var isError = !string.IsNullOrEmpty(buildData.errorInfo); var style = isError ? _styleError : _styleNormal; GUILayout.BeginHorizontal(); buildData.isChecked = GUILayout.Toggle(buildData.isChecked, "", GUILayout.Width(20)); var isChecked = buildData.isChecked; var cConfig = buildData.mainConfig; GUILayout.Label("ID:" + cConfig.NameID, GUILayout.Width(80)); GUILayout.Label("名称:" + cConfig.NameRead, style, GUILayout.Width(90)); GUILayout.Label("皮肤数量:" + buildData.skins.Count, GUILayout.Width(80)); GUILayout.Label("使用武器:" + buildData.weaponIdsStr); GUILayout.EndHorizontal(); _ShowEmojiInfo(buildData); if (isError && isChecked) { GUILayout.BeginHorizontal(); GUILayout.Space(100); GUILayout.Label(buildData.errorInfo, style); GUILayout.EndHorizontal(); } } GUILayout.EndVertical(); EditorGUILayout.EndScrollView(); GUILayout.BeginHorizontal(); if (GUILayout.Button("全选")) { for (var i = 0; i < _characterBuildDataList.Count; ++i) { _characterBuildDataList[i].isChecked = true; } } if (GUILayout.Button("全不选")) { for (var i = 0; i < _characterBuildDataList.Count; ++i) { _characterBuildDataList[i].isChecked = false; } } GUILayout.EndHorizontal(); } private void _ShowEmojiInfo(BaseRoleBuildData buildData) { GUILayout.BeginHorizontal(); GUILayout.Space(100); GUILayout.Label("默认表情:" + buildData.emojiExt.emojiId, GUILayout.Width(120)); var eyebowsColorStr = buildData.emojiExt.eyebowsColor; var eyebowsColor = ColorUtils.FromHex(eyebowsColorStr, Color.black); var myStyle = new GUIStyle(GUI.skin.label); myStyle.normal.textColor = eyebowsColor; GUILayout.Label("眉毛颜色:" + buildData.emojiExt.eyebowsColor, myStyle, GUILayout.Width(120)); var eyesColorStr = buildData.emojiExt.eyesColor; var eyesColor = ColorUtils.FromHex(eyesColorStr, Color.black); myStyle.normal.textColor = eyesColor; GUILayout.Label("眼睛颜色:" + buildData.emojiExt.eyesColor, myStyle, GUILayout.Width(120)); GUILayout.EndHorizontal(); } private void _Build() { for (int i = 0; i < _characterBuildDataList.Count; i++) { var buildData = _characterBuildDataList[i]; if (!buildData.isChecked) { continue; } buildData.RebuildAll(_animclipMap); } for (int i = 0; i < _monsterBuildDataList.Count; i++) { var buildData = _monsterBuildDataList[i]; if (!buildData.isChecked) { continue; } buildData.RebuildAll(_animclipMap); } for (int i = 0; i < _npcBuildDataList.Count; i++) { var buildData = _npcBuildDataList[i]; if (!buildData.isChecked) { continue; } buildData.RebuildAll(_animclipMap); } AssetDatabase.Refresh(); } } }