430 lines
20 KiB
C#
430 lines
20 KiB
C#
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<SkillConfig>
|
|
{
|
|
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<Dictionary<int, SkillNodeGraph>>(str);
|
|
Deserilize();
|
|
AssetDatabase.Refresh();
|
|
Log.Info($"加载完毕:{str.Length / 1000}K " + DateTime.Now);
|
|
}
|
|
private List<int> GetSkills()
|
|
{
|
|
var arr = Utility.FileOpation.GetFiles(soDir, "*.asset", SearchOption.AllDirectories);
|
|
List<int> list = new List<int>();
|
|
foreach (var item in arr)
|
|
{
|
|
var asset = AssetDatabase.LoadAssetAtPath<SkillNodeGraph>(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>();
|
|
_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<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;
|
|
}
|
|
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;
|
|
}
|
|
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);
|
|
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<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;
|
|
}
|
|
void LoadAllAsync(SkillLogicConfigCollection data)
|
|
{
|
|
foreach (var item in data.skillDic)
|
|
{
|
|
var logic = item.Value;
|
|
string assetPath = $"{soDir}/{item.Key}.asset";
|
|
SkillNodeGraph so = CreateInstance<SkillNodeGraph>();
|
|
AssetDatabase.CreateAsset(so, assetPath);
|
|
RootNode root = so.AddNode<RootNode>();
|
|
root.name = "Root";
|
|
root.position = so.GetEmptyNodePos();
|
|
AssetDatabase.AddObjectToAsset(root, so);
|
|
root.skillLogic = logic;
|
|
|
|
Dictionary<ModifierId, ModifierNode> modifierNodeDic = new Dictionary<ModifierId, ModifierNode>();
|
|
if (logic.modifierDic != null)
|
|
{
|
|
foreach (var modifier in logic.modifierDic)
|
|
{
|
|
ModifierNode modifierNode = so.AddNode<ModifierNode>();
|
|
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<ModifierEventConditionNode>();
|
|
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>();
|
|
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<ModifierId, ModifierNode> 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<RootNode>().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<RootNode>().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
|
|
}
|