495 lines
19 KiB
C#
495 lines
19 KiB
C#
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<int, SkillNodeGraph> 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<SkillNodeGraph> GetSkills()
|
|
{
|
|
var arr = Utility.FileOpation.GetFiles(soDir, "*.asset", SearchOption.AllDirectories);
|
|
List<SkillNodeGraph> list = new List<SkillNodeGraph>();
|
|
foreach (var item in arr)
|
|
{
|
|
var asset = AssetDatabase.LoadAssetAtPath<SkillNodeGraph>(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<SkillNode>().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<SkillNodeGraph> 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<SkillEventCondition, SkillOptionBase[]>();
|
|
foreach (var anotherPort in port.GetConnections())
|
|
{
|
|
SkillEventConditionNode node = anotherPort.node.As<SkillEventConditionNode>();
|
|
SkillOptionBase[] arr = SerilizeSkillOptions(node);
|
|
skillLogicConfig.skillEventDic.Add(node.condition, arr);
|
|
}
|
|
}
|
|
}
|
|
SkillOptionBase[] SerilizeSkillOptions(SkillEventConditionNode node)
|
|
{
|
|
List<SkillOptionBase> list = new List<SkillOptionBase>();
|
|
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<SkillOptionBase>();
|
|
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<ModifierId, ModifierConfig>();
|
|
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<ModifierEventCondition, SkillOptionBase[]>();
|
|
foreach (var anotherPort in port.GetConnections())
|
|
{
|
|
ModifierEventConditionNode node = anotherPort.node.As<ModifierEventConditionNode>();
|
|
SkillOptionBase[] arr = SerilizeSkillOptions(node);
|
|
if (modifier.modifierEventDic.ContainsKey(node.condition))
|
|
{
|
|
Log.Error($"{node.uniqeId} {modifierNode.skillGraph.name}");
|
|
}
|
|
modifier.modifierEventDic.Add(node.condition, arr);
|
|
}
|
|
}
|
|
}
|
|
SkillOptionBase[] SerilizeSkillOptions(ModifierEventConditionNode node)
|
|
{
|
|
List<SkillOptionBase> list = new List<SkillOptionBase>();
|
|
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<SkillOptionBase>();
|
|
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<string, List<int>>();
|
|
if (!node.nextIds.TryGetValue(port.fieldName, out var list))
|
|
list = new List<int>();
|
|
list.Add(otherPort.node.As<SkillNode>().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<Dictionary<int, SkillNodeGraph>>(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<SkillNode>().uniqeId == node.uniqeId) as SkillNode;
|
|
if (oldNode == null)
|
|
{
|
|
GeanerateNotExistNode(_skillNodeGraph, deserilizedGraph.nodes.Find(t => t.As<SkillNode>().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<SkillNode>().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<RootNode>().skillLogic;
|
|
break;
|
|
case SkillEventConditionNode rootNode:
|
|
rootNode.condition = node.As<SkillEventConditionNode>().condition;
|
|
break;
|
|
case ModifierNode rootNode:
|
|
rootNode.modifier = node.As<ModifierNode>().modifier;
|
|
break;
|
|
case ModifierEventConditionNode rootNode:
|
|
rootNode.condition = node.As<ModifierEventConditionNode>().condition;
|
|
break;
|
|
case SkillOptionBase rootNode:
|
|
int index = _skillNodeGraph.nodes.IndexOf(oldNode);
|
|
_skillNodeGraph.nodes[index] = oldNode = node.As<SkillOptionBase>().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<SkillNode>().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<RootNode>().skillLogic;
|
|
break;
|
|
case SkillEventConditionNode rootNode:
|
|
rootNode.condition = skillNode.As<SkillEventConditionNode>().condition;
|
|
break;
|
|
case ModifierNode rootNode:
|
|
rootNode.modifier = skillNode.As<ModifierNode>().modifier;
|
|
break;
|
|
case ModifierEventConditionNode rootNode:
|
|
rootNode.condition = skillNode.As<ModifierEventConditionNode>().condition;
|
|
break;
|
|
case SkillOptionBase rootNode:
|
|
int index = skillGraph.nodes.IndexOf(node);
|
|
node.position = skillNode.position;
|
|
skillGraph.nodes[index] = node = skillNode.As<SkillOptionBase>().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<ModifierId>());
|
|
BsonSerializer.RegisterSerializer(typeof(CastParam), new StructBsonSerialize<CastParam>());
|
|
}
|
|
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}");
|
|
}
|
|
}
|
|
}
|
|
}
|