using Cal; using ET; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Options; using Sirenix.OdinInspector; using Sirenix.Utilities; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; #if UNITY_EDITOR using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; #endif namespace CalEditor { using CalEditor.Cal.DataTable; #if UNITY_EDITOR #region Config using ET; using MongoDB.Bson.Serialization.Attributes; namespace Cal.DataTable { [Config] public partial class SkillConfigCategory : ACategory { public static SkillConfigCategory Instance; public SkillConfigCategory() { Instance = this; } } public partial class SkillConfig : IConfig { [BsonId] public long Id { get; set; } public string Name; public string Desc; public int CD; public int CastType; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float CastValue; public int PreSkillId; public int MaxLevel; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args0; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args1; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args2; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args3; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args4; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args5; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args6; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args7; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args8; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args9; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args10; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args11; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args12; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args13; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args14; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args15; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args16; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args17; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args18; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args19; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args20; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args29; [BsonRepresentation(MongoDB.Bson.BsonType.Double, AllowTruncation = true)] public float Args30; public int SkillType; public int LearnLevel; public int EffectId; public int DelayTime; public int HurtEffectId; public string Icon; } } #endregion [CreateAssetMenu] public class SkillAndModifierSObject : Sirenix.OdinInspector.SerializedScriptableObject { public static SkillAndModifierSObject Instance; private void OnEnable() { Instance = this; //LoadConfig(); } private void LoadConfig() { SkillConfigCategory.Instance = new SkillConfigCategory(); SkillConfigCategory.Instance.LoadAsync(); } [FolderPath()] [LabelText("SO保存路径"), PropertyOrder(120)] public string soDir = "Assets/XNodeDemo/Assets/Skill"; public string soDataPath = "Assets/XNodeDemo/Assets/SOData/nodes.json"; [FolderPath(AbsolutePath = true)] [LabelText("存档保存路径"), PropertyOrder(120)] public string path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/CTT/Skill/Skill"; [FolderPath(AbsolutePath = true)] [LabelText("日志保存路径"), PropertyOrder(120)] public string logPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/CTT/Skill/Logs"; [LabelText("文件名"), PropertyOrder(120)] public string fileName = "SkillLogicConfig.json"; [LabelText("二进制文件名"), PropertyOrder(120)] public string fileBytesName = "SkillLogicConfig.bytes"; [Button("重置"), PropertyOrder(-1)] [ButtonGroup] public void ReSet() { loop = 0; RegisterMongo(); string str = File.ReadAllText(soDataPath); NodeDataUtil.dic = MongoHelper.FromJson>(str); Deserilize(); AssetDatabase.Refresh(); Log.Info($"加载完毕:{str.Length / 1000}K " + DateTime.Now); } private List GetSkills() { var arr = Utility.FileOpation.GetFiles(soDir, "*.asset", SearchOption.AllDirectories); List list = new List(); foreach (var item in arr) { var asset = AssetDatabase.LoadAssetAtPath(Utility.Path.DataPathToAssetPath(item.FullName)); list.Add(asset.Id); } Utility.FileOpation.DeleteDirectory(soDir,true); return list; } void Deserilize() { try { foreach (var skillGraphKV in NodeDataUtil.dic) { var deserilizedGraph = skillGraphKV.Value; var _skillNodeGraph = CreateInstance(); _skillNodeGraph.name = skillGraphKV.Key.ToString(); AssetDatabase.CreateAsset(_skillNodeGraph,Path.Combine(soDir,_skillNodeGraph.name)+".asset"); try { foreach (SkillNode node in deserilizedGraph.nodes) { try { SkillNode oldNode = _skillNodeGraph.nodes.Find(t => t.As().uniqeId == node.uniqeId) as SkillNode; if (oldNode == null) { GeanerateNotExistNode(_skillNodeGraph, deserilizedGraph.nodes.Find(t => t.As().uniqeId == node.uniqeId) as SkillNode, node.uniqeId); } } catch (Exception) { Log.Error($"[1]skill has error in dic which id = {_skillNodeGraph.Id}"); throw; } } } catch (Exception) { Log.Error($"[2]skill has error in dic which id = {_skillNodeGraph.Id}"); throw; } foreach (SkillNode node in deserilizedGraph.nodes) { SkillNode oldNode = _skillNodeGraph.nodes.Find(t => t.As().uniqeId == node.uniqeId) as SkillNode; if (oldNode == null) { Log.Error($"oldNode == null where id = {node.uniqeId}"); continue; } switch (oldNode) { default: break; case RootNode rootNode: rootNode.skillLogic = node.As().skillLogic; break; case SkillEventConditionNode rootNode: rootNode.condition = node.As().condition; break; case ModifierNode rootNode: rootNode.modifier = node.As().modifier; break; case ModifierEventConditionNode rootNode: rootNode.condition = node.As().condition; break; case SkillOptionBase rootNode: int index = _skillNodeGraph.nodes.IndexOf(oldNode); _skillNodeGraph.nodes[index] = oldNode = node.As().Clone(rootNode); break; } oldNode.position = node.position; if (node.nextIds != null) foreach (var kv in node.nextIds) { var outPut = oldNode.GetOutputPort(kv.Key); outPut.ClearConnections(); foreach (var uniqeId in kv.Value) { SkillNode targetNode = _skillNodeGraph.GetNode(uniqeId); if (targetNode == null) { Log.Error($"this is wrong when id = {uniqeId}"); targetNode = GeanerateNotExistNode(_skillNodeGraph, deserilizedGraph.nodes.Find(t => t.As().uniqeId == uniqeId) as SkillNode, uniqeId); } outPut.Connect(targetNode.GetInputPort("input")); } } } EditorUtility.SetDirty(_skillNodeGraph); AssetDatabase.SaveAssets(); } Log.Info($"反序列化成功 {DateTime.Now:MM_dd+HH_mm_ss}"); } catch (Exception e) { Log.Info($"反序列化失败 {DateTime.Now:MM_dd+HH_mm_ss}"); Log.Error($"{e}"); } AssetDatabase.Refresh(); } private void SetSkillLogicInfo(SkillLogicConfig skillLogic) { int skillId = skillLogic.skillId; SkillConfig skillConfig = SkillConfigCategory.Instance.Get(skillId * 100); skillLogic.CD = skillConfig.CD; skillLogic.maxLevel = skillConfig.MaxLevel; skillLogic.cast = new CastParam { skillCastType = (SkillCastType)skillConfig.CastType, skillCast = skillConfig.CastValue, castBaseType =(SkillCastType)skillConfig.CastType == SkillCastType.消耗精力? CastBaseType.Level: CastBaseType.Max }; } private SkillNode GeanerateNotExistNode(SkillNodeGraph skillGraph, SkillNode skillNode, int uniqeId) { SkillNode node = skillGraph.AddNodeWithId(skillNode.GetType(), uniqeId) as SkillNode; switch (node) { default: break; case RootNode rootNode: rootNode.skillLogic = skillNode.As().skillLogic; break; case SkillEventConditionNode rootNode: rootNode.condition = skillNode.As().condition; break; case ModifierNode rootNode: rootNode.modifier = skillNode.As().modifier; break; case ModifierEventConditionNode rootNode: rootNode.condition = skillNode.As().condition; break; case SkillOptionBase rootNode: int index = skillGraph.nodes.IndexOf(node); node.position = skillNode.position; skillGraph.nodes[index] = node = skillNode.As().Clone(rootNode); break; } node.name = skillNode.name; AssetDatabase.AddObjectToAsset(node, skillGraph); return node; } void LoadAllAsync(SkillLogicConfigCollection data) { foreach (var item in data.skillDic) { var logic = item.Value; string assetPath = $"{soDir}/{item.Key}.asset"; SkillNodeGraph so = CreateInstance(); AssetDatabase.CreateAsset(so, assetPath); RootNode root = so.AddNode(); root.name = "Root"; root.position = so.GetEmptyNodePos(); AssetDatabase.AddObjectToAsset(root, so); root.skillLogic = logic; Dictionary modifierNodeDic = new Dictionary(); if (logic.modifierDic != null) { foreach (var modifier in logic.modifierDic) { ModifierNode modifierNode = so.AddNode(); modifierNode.name = "Modifier"; modifierNode.position = so.GetEmptyNodePos(); AssetDatabase.AddObjectToAsset(modifierNode, so); modifierNode.modifier = modifier.Value; modifierNodeDic.Add(modifier.Key, modifierNode); } } foreach (var modifierKV in modifierNodeDic) { if (modifierKV.Value.modifier.modifierEventDic != null) foreach (var modifierEvent in modifierKV.Value.modifier.modifierEventDic) { ModifierEventConditionNode skillEventConditionNode = so.AddNode(); skillEventConditionNode.name = "ModifierEventCondition"; skillEventConditionNode.position = so.GetEmptyNodePos(); AssetDatabase.AddObjectToAsset(skillEventConditionNode, so); modifierKV.Value.GetOutputPort("result").Connect(skillEventConditionNode.GetInputPort("input")); skillEventConditionNode.condition = modifierEvent.Key; CreateSkillOption(so, skillEventConditionNode.GetOutputPort("result"), modifierNodeDic, modifierEvent.Value); } } if (logic.skillEventDic != null) foreach (var skillEvent in logic.skillEventDic) { SkillEventConditionNode skillEventConditionNode = so.AddNode(); skillEventConditionNode.name = "SkillEventCondition"; skillEventConditionNode.position = so.GetEmptyNodePos(); AssetDatabase.AddObjectToAsset(skillEventConditionNode, so); root.GetOutputPort("result").Connect(skillEventConditionNode.GetInputPort("input")); skillEventConditionNode.condition = skillEvent.Key; CreateSkillOption(so, skillEventConditionNode.GetOutputPort("result"), modifierNodeDic, skillEvent.Value); } EditorUtility.SetDirty(so); AssetDatabase.SaveAssets(); } void CreateSkillOption(SkillNodeGraph so, XNode.NodePort lastNode, Dictionary modifierNodeDic, SkillOptionBase[] options) { if (options == null) return; AvoidLoop(); foreach (var option in options) { Type type = option.GetType(); SkillOptionBase skillOptionNode = so.AddNode(type) as SkillOptionBase; skillOptionNode.name = type.Name; skillOptionNode.position = so.GetEmptyNodePos(); AssetDatabase.AddObjectToAsset(skillOptionNode, so); lastNode.Connect(skillOptionNode.GetInputPort("input")); skillOptionNode = option.Clone(skillOptionNode); foreach (var fieldInfo in type.GetFields()) { if (fieldInfo.FieldType == typeof(SkillOptionBase[])) { SkillOptionBase[] arr = fieldInfo.GetValue(option) as SkillOptionBase[]; CreateSkillOption(so, skillOptionNode.GetNodePort(fieldInfo.Name), modifierNodeDic, arr); } else if (fieldInfo.FieldType == typeof(ModifierId)) { ModifierId id = (ModifierId)fieldInfo.GetValue(option); if (modifierNodeDic == null) { Log.Error($"modifierNodeDic == null skillId = {so.nodes.Find(t => t.name.Equals("Root")).As().skillLogic.skillId}"); continue; } if (modifierNodeDic.TryGetValue(id, out var modifierNode)) { skillOptionNode.GetOutputPort("result").Connect(modifierNode.GetInputPort("input")); } } else if (fieldInfo.FieldType == typeof(ModifierId[])) { ModifierId[] ids = (ModifierId[])fieldInfo.GetValue(option); if (modifierNodeDic == null) { Log.Error($"modifierNodeDic == null skillId = {so.nodes.Find(t => t.name.Equals("Root")).As().skillLogic.skillId}"); continue; } foreach (var id in ids) { if (modifierNodeDic.TryGetValue(id, out var modifierNode)) { skillOptionNode.GetOutputPort("result").Connect(modifierNode.GetInputPort("input")); } } } } } } } private int loop; private void AvoidLoop() { loop++; if (loop > 1000) throw new Exception("stack overflow"); } public static void RegisterMongo() { RootNode.RegisterMongo(); } } #endif }