using Cal; using ET; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; using Sirenix.OdinInspector; using Sirenix.Serialization; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using UnityEditor; using UnityEngine; using XNode; public static class NodeDataUtil { public static Dictionary dic; } public class RootNode : SkillNode { // Use this for initialization protected override void Init() { base.Init(); skillGraph = base.graph as SkillNodeGraph; } [LabelText("修改技能Id")] [LabelWidth(80)] [InlineButton("ChangeSkillId", "确定")] public int skillId; void ChangeSkillId() { skillLogic.skillId = skillId; } [SerializeField] public Cal.SkillLogicConfig skillLogic; [PropertySpace(15, 12)] [LabelText("技能事件条件")] [BsonIgnore] [Output] public float result; // GetValue should be overridden to return a value for any specified output port public override object GetValue(NodePort port) { return null; } public override void OnCreateConnection(NodePort from, NodePort to) { if (to.node == this) { } else if (!(to.node is SkillEventConditionNode)) { from.Disconnect(to); } } static string saveSODataDir = "Assets/XNodeDemo/Assets/SOData/"; static string soDir = "Assets/XNodeDemo/Assets/Skill/"; [LabelText("存档保存路径"), PropertyOrder(120)] static string path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/CTT/Skill/Skill"; [FolderPath(AbsolutePath = true)] [LabelText("日志保存路径"), PropertyOrder(120)] static string logPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/CTT/Skill/Logs"; [LabelText("文件名"), PropertyOrder(120)] static string fileName = "SkillLogicConfig.json"; [LabelText("二进制文件名"), PropertyOrder(120)] static string fileBytesName = "SkillLogicConfig.bytes"; static string logDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/CTT/Nodes/Logs"; static string configDir = "Assets/Download/Config/"; 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); } return list; } //[Button("Test")] //[ButtonGroup] void TestModify() { var arr = GetSkills(); foreach (var asset in arr) { var rootNode = asset.nodes.Find(t => t is RootNode)as RootNode; if (rootNode != null) { var param = rootNode.skillLogic.cast; if(param.skillCastType == SkillCastType.消耗精力) { param.skillCast /= 10f; rootNode.skillLogic.cast = param; EditorUtility.SetDirty(asset); } } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Log.Info($"修改{DateTime.Now:MM_dd+HH_mm_ss}"); } #region Serialize [Button("序列化")] [ButtonGroup] void Serilize() { RegisterMongo(); var arr = GetSkills(); StringBuilder sb = new StringBuilder(); sb.AppendLine("["); foreach (var asset in arr) { asset.nodes.ForEach(t => { int id = t.As().uniqeId; if (id >= asset.maxUniqeId) asset.maxUniqeId = ++id; if(t is ModifierNode modifierNode) { int modifierId = modifierNode.modifier.Id.Value % 100; if (modifierId >= asset.maxModifierId) asset.maxModifierId = ++modifierId; } }); foreach (SkillNode node in asset.nodes) { GenerateNestIds(node); } EditorUtility.SetDirty(asset); sb.Append($"[{asset.Id},{ MongoHelper.ToJson(asset)}],\n"); } sb.AppendLine("]"); string path = Path.Combine(saveSODataDir, $"nodes.json"); string logPath = Path.Combine(logDir, $"nodes_{DateTime.Now:MM_dd+HH_mm_ss}.json"); string str = sb.ToString(); Utility.FileOpation.Delete(path); Utility.FileOpation.CreateDirectory(logDir); File.WriteAllText(path, str); File.WriteAllText(logPath, str); SerilizeToConfig(arr); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Log.Info($"保存成功{DateTime.Now:MM_dd+HH_mm_ss} {str.Length / 1024f:f1}K"); } private void SerilizeToConfig(List arr) { string configPath = Path.Combine(configDir, "SkillLogicConfig.json"); Utility.FileOpation.CreateDirectory(path); string newpath = Path.GetFullPath(Path.Combine(path, fileName)); Utility.FileOpation.Delete(newpath); string saveath = logPath; Utility.FileOpation.CreateDirectory(saveath); saveath += $"/SkillLogicConfig+{DateTime.Now:MM-dd + HH-mm-ss}.json"; SkillLogicConfigCollection data = new SkillLogicConfigCollection(); foreach (var skillNodeGraph in arr) { int id = skillNodeGraph.Id; SkillLogicConfig skillLogicConfig = new SkillLogicConfig(); RootNode rootNode = skillNodeGraph.Root; rootNode.skillLogic.Clone(skillLogicConfig); data.skillDic.Add(id, skillLogicConfig); SerilizeSkillEvent(rootNode, skillLogicConfig); SerilizeModifier(skillNodeGraph, skillLogicConfig); } string str = MongoHelper.ToJson(data); Utility.FileOpation.Delete(configPath); File.WriteAllText(configPath, str); File.WriteAllText(newpath, str); File.WriteAllText(saveath, str); Log.Info($"保存Config成功{DateTime.Now:MM_dd+HH_mm_ss} {str.Length / 1024f:f1}K"); SerilizeBson(data); } private void SerilizeBson(SkillLogicConfigCollection data) { string newpath = Path.GetFullPath(Path.Combine(path, fileBytesName)); string serPath = Path.GetFullPath(Path.Combine("../Config/Skill", fileBytesName)); Utility.FileOpation.Delete(newpath); Utility.FileOpation.Delete(serPath); var str = MongoHelper.ToBson(data); File.WriteAllBytes(newpath, str); File.WriteAllBytes(serPath, str); } private void SerilizeSkillEvent(RootNode rootNode, SkillLogicConfig skillLogicConfig) { foreach (var port in rootNode.Ports) { if (port.IsConnected && port.IsOutput) { skillLogicConfig.skillEventDic = skillLogicConfig.skillEventDic ?? new Dictionary(); foreach (var anotherPort in port.GetConnections()) { SkillEventConditionNode node = anotherPort.node.As(); SkillOptionBase[] arr = SerilizeSkillOptions(node); skillLogicConfig.skillEventDic.Add(node.condition, arr); } } } SkillOptionBase[] SerilizeSkillOptions(SkillEventConditionNode node) { List list = new List(); foreach (var port in node.Ports) { if (port.IsConnected && port.IsOutput) { foreach (var anotherPort in port.GetConnections()) { SkillOptionBase skillOption = System.Activator.CreateInstance(anotherPort.node.GetType()) as SkillOptionBase; var anotherNode = anotherPort.node.As(); anotherNode.Clear(); anotherNode.DeepClone(skillOption); anotherNode.Serilize(skillOption); list.Add(skillOption); } } } return list.ToArray(); } } private void SerilizeModifier(SkillNodeGraph skillNodeGraph, SkillLogicConfig skillLogicConfig) { foreach (SkillNode node in skillNodeGraph.nodes) { if (node is ModifierNode modifierNode) { skillLogicConfig.modifierDic = skillLogicConfig.modifierDic ?? new Dictionary(); var modifier = modifierNode.modifier.Clone(); skillLogicConfig.modifierDic.Add(modifier.Id, modifier); SerilizeModifierEvent(modifierNode, modifier); } } } private void SerilizeModifierEvent(ModifierNode modifierNode, ModifierConfig modifier) { foreach (var port in modifierNode.Ports) { if (port.IsConnected && port.IsOutput) { modifier.modifierEventDic = modifier.modifierEventDic ?? new Dictionary(); foreach (var anotherPort in port.GetConnections()) { ModifierEventConditionNode node = anotherPort.node.As(); SkillOptionBase[] arr = SerilizeSkillOptions(node); modifier.modifierEventDic.Add(node.condition, arr); } } } SkillOptionBase[] SerilizeSkillOptions(ModifierEventConditionNode node) { List list = new List(); foreach (var port in node.Ports) { if (port.IsConnected && port.IsOutput) { foreach (var anotherPort in port.GetConnections()) { SkillOptionBase skillOption = System.Activator.CreateInstance(anotherPort.node.GetType()) as SkillOptionBase; var anotherNode = anotherPort.node.As(); anotherNode.DeepClone(skillOption); anotherNode.Clear(); anotherNode.Serilize(skillOption); list.Add(skillOption); } } } return list.ToArray(); } } #endregion private void GenerateNestIds(SkillNode node) { if (node == null) return; //node.CheckData(); node.nextIds?.Clear(); foreach (var port in node.Ports) { if (port.IsConnected && port.IsOutput) { foreach (var otherPort in port.GetConnections()) { node.nextIds = node.nextIds ?? new Dictionary>(); if (!node.nextIds.TryGetValue(port.fieldName, out var list)) list = new List(); list.Add(otherPort.node.As().uniqeId); node.nextIds[port.fieldName] = list; } } } } #region Deserialize [Button("加载")] [ButtonGroup] void LoadTxt() { RegisterMongo(); string path = Path.Combine(saveSODataDir, $"nodes.json"); string str = File.ReadAllText(path); NodeDataUtil.dic = MongoHelper.FromJson>(str); Log.Info($"Load{DateTime.Now:MM_dd+HH_mm_ss} {str.Length / 1024f:f1}K"); } [Button("反序列化")] [ButtonGroup] void Deserilize() { try { var arr = GetSkills(); foreach (var _skillNodeGraph in arr) { if (!NodeDataUtil.dic.TryGetValue(_skillNodeGraph.Id, out var deserilizedGraph)) { return; } 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; } try { 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; } } catch (Exception e) { Log.Error($"[3]skill has error in dic which id = {_skillNodeGraph.Id}"); Log.Error(e); } 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); } 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.SaveAssets(); AssetDatabase.Refresh(); } 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; } #endregion public static void RegisterMongo() { try { BsonSerializer.RegisterSerializer(typeof(ModifierId), new StructBsonSerialize()); BsonSerializer.RegisterSerializer(typeof(CastParam), new StructBsonSerialize()); } catch (Exception e) { Log.Error(e); } Type[] types = typeof(RootNode).Assembly.GetTypes(); foreach (Type type in types) { if (!type.IsSubclassOf(typeof(SelectTargetBase)) && !type.IsSubclassOf(typeof(SkillNode)) && !type.IsSubclassOf(typeof(Node)) && !type.IsSubclassOf(typeof(NodeGraph)) && !type.IsSubclassOf(typeof(SkillOptionBase)) ) { continue; } if (type.IsGenericType) { continue; } try { MongoDB.Bson.Serialization.BsonClassMap.LookupClassMap(type); } catch (Exception e) { Log.Error($"11: {type.Name} {e}"); } } } }