diff --git a/src/Luban.Job.Cfg/Luban.Job.Cfg.csproj b/src/Luban.Job.Cfg/Luban.Job.Cfg.csproj
index 7962eed..34800e1 100644
--- a/src/Luban.Job.Cfg/Luban.Job.Cfg.csproj
+++ b/src/Luban.Job.Cfg/Luban.Job.Cfg.csproj
@@ -15,6 +15,7 @@
+
diff --git a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs
index 734dbbf..9e45c6e 100644
--- a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs
+++ b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs
@@ -77,7 +77,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TBytes type, XElement x, DefAssembly ass)
{
- throw new NotImplementedException();
+ throw new NotSupportedException();
}
public DType Accept(TText type, XElement x, DefAssembly ass)
diff --git a/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs
new file mode 100644
index 0000000..d313597
--- /dev/null
+++ b/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs
@@ -0,0 +1,245 @@
+using Luban.Common.Utils;
+using Luban.Job.Cfg.Datas;
+using Luban.Job.Cfg.Defs;
+using Luban.Job.Cfg.Utils;
+using Luban.Job.Common.Types;
+using Luban.Job.Common.TypeVisitors;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using YamlDotNet.RepresentationModel;
+
+namespace Luban.Job.Cfg.DataCreators
+{
+ class YamlDataCreator : ITypeFuncVisitor
+ {
+ public static YamlDataCreator Ins { get; } = new();
+
+ private static string GetLowerTextValue(YamlNode node)
+ {
+ return ((string)node).Trim().ToLower();
+ }
+
+ private static string GetTextValue(YamlNode node)
+ {
+ return ((string)node);
+ }
+
+ public DType Accept(TBool type, YamlNode x, DefAssembly y)
+ {
+ return DBool.ValueOf(bool.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TByte type, YamlNode x, DefAssembly y)
+ {
+ return new DByte(byte.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TShort type, YamlNode x, DefAssembly y)
+ {
+ return new DShort(short.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TFshort type, YamlNode x, DefAssembly y)
+ {
+ return new DFshort(short.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TInt type, YamlNode x, DefAssembly y)
+ {
+ return DInt.ValueOf(int.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TFint type, YamlNode x, DefAssembly y)
+ {
+ return new DFint(int.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TLong type, YamlNode x, DefAssembly y)
+ {
+ return DLong.ValueOf(long.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TFlong type, YamlNode x, DefAssembly y)
+ {
+ return new DFlong(long.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TFloat type, YamlNode x, DefAssembly y)
+ {
+ return DFloat.ValueOf(float.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TDouble type, YamlNode x, DefAssembly y)
+ {
+ return new DDouble(double.Parse(GetLowerTextValue(x)));
+ }
+
+ public DType Accept(TEnum type, YamlNode x, DefAssembly y)
+ {
+ return new DEnum(type, GetTextValue(x));
+ }
+
+ public DType Accept(TString type, YamlNode x, DefAssembly y)
+ {
+ return DString.ValueOf(GetTextValue(x));
+ }
+
+ public DType Accept(TBytes type, YamlNode x, DefAssembly y)
+ {
+ throw new NotSupportedException();
+ }
+
+ private readonly static YamlScalarNode s_keyNodeName = new("key");
+ private readonly static YamlScalarNode s_textNodeName = new("text");
+
+ public DType Accept(TText type, YamlNode x, DefAssembly y)
+ {
+ var key = GetTextValue(x[s_keyNodeName]);
+ var text = GetTextValue(x[s_textNodeName]);
+ DataUtil.ValidateText(key, text);
+ return new DText(key, text);
+ }
+
+ private readonly static YamlScalarNode s_typeNodeName = new(DefBean.TYPE_NAME_KEY);
+
+ public DType Accept(TBean type, YamlNode x, DefAssembly y)
+ {
+ var m = (YamlMappingNode)x;
+ var bean = (DefBean)type.Bean;
+
+ DefBean implBean;
+ if (bean.IsAbstractType)
+ {
+ string subType = m.Children.TryGetValue(s_typeNodeName, out var typeNode) ? (string)typeNode : null;
+ if (string.IsNullOrWhiteSpace(subType))
+ {
+ throw new Exception($"bean:'{bean.FullName}'是多态,需要指定{DefBean.TYPE_NAME_KEY}属性.\n xml:{x}");
+ }
+ var fullName = TypeUtil.MakeFullName(bean.Namespace, subType);
+ var defType = (DefBean)bean.GetNotAbstractChildType(subType);
+ implBean = defType ?? throw new Exception($"type:'{fullName}' 不是合法类型");
+ }
+ else
+ {
+ implBean = bean;
+ }
+
+ var fields = new List();
+ foreach (DefField f in implBean.HierarchyFields)
+ {
+ if (!m.Children.TryGetValue(new YamlScalarNode(f.Name), out var fele))
+ {
+ if (f.CType.IsNullable)
+ {
+ fields.Add(null);
+ continue;
+ }
+ throw new Exception($"bean:{implBean.FullName} 字段:{f.Name} 缺失");
+ }
+ try
+ {
+ fields.Add(f.CType.Apply(this, fele, y));
+ }
+ catch (DataCreateException dce)
+ {
+ dce.Push(implBean, f);
+ throw;
+ }
+ catch (Exception e)
+ {
+ var dce = new DataCreateException(e, "");
+ dce.Push(bean, f);
+ throw dce;
+ }
+
+ }
+ return new DBean(bean, implBean, fields);
+ }
+
+ private List ReadList(TType type, YamlSequenceNode x, DefAssembly ass)
+ {
+ var list = new List();
+ foreach (var e in x)
+ {
+ list.Add(type.Apply(this, e, ass));
+ }
+ return list;
+ }
+
+ public DType Accept(TArray type, YamlNode x, DefAssembly y)
+ {
+ return new DArray(type, ReadList(type.ElementType, (YamlSequenceNode)x, y));
+ }
+
+ public DType Accept(TList type, YamlNode x, DefAssembly y)
+ {
+ return new DList(type, ReadList(type.ElementType, (YamlSequenceNode)x, y));
+ }
+
+ public DType Accept(TSet type, YamlNode x, DefAssembly y)
+ {
+ return new DSet(type, ReadList(type.ElementType, (YamlSequenceNode)x, y));
+ }
+
+ public DType Accept(TMap type, YamlNode x, DefAssembly y)
+ {
+ var m = (YamlSequenceNode)x;
+ var map = new Dictionary();
+ foreach (var e in m)
+ {
+ var kv = (YamlSequenceNode)e;
+ if (kv.Count() != 2)
+ {
+ throw new ArgumentException($"yaml map 类型的 成员数据项:{e} 必须是 [key,value] 形式的列表");
+ }
+ DType key = type.KeyType.Apply(this, kv[0], y);
+ DType value = type.ValueType.Apply(this, kv[1], y);
+ if (!map.TryAdd(key, value))
+ {
+ throw new Exception($"map 的 key:{key} 重复");
+ }
+ }
+ return new DMap(type, map);
+ }
+
+ private readonly static YamlScalarNode s_xNodeName = new("x");
+ private readonly static YamlScalarNode s_yNodeName = new("y");
+ private readonly static YamlScalarNode s_zNodeName = new("z");
+ private readonly static YamlScalarNode s_wNodeName = new("w");
+
+ private static float ParseChildFloatValue(YamlNode node, YamlScalarNode keyName)
+ {
+ return float.Parse(GetLowerTextValue(node[keyName]));
+ }
+
+ public DType Accept(TVector2 type, YamlNode x, DefAssembly y)
+ {
+ return new DVector2(new System.Numerics.Vector2(ParseChildFloatValue(x, s_xNodeName), ParseChildFloatValue(x, s_yNodeName)));
+ }
+
+ public DType Accept(TVector3 type, YamlNode x, DefAssembly y)
+ {
+ return new DVector3(new System.Numerics.Vector3(
+ ParseChildFloatValue(x, s_xNodeName),
+ ParseChildFloatValue(x, s_yNodeName),
+ ParseChildFloatValue(x, s_zNodeName)));
+ }
+
+ public DType Accept(TVector4 type, YamlNode x, DefAssembly y)
+ {
+ return new DVector4(new System.Numerics.Vector4(
+ ParseChildFloatValue(x, s_xNodeName),
+ ParseChildFloatValue(x, s_yNodeName),
+ ParseChildFloatValue(x, s_zNodeName),
+ ParseChildFloatValue(x, s_wNodeName)));
+ }
+
+ public DType Accept(TDateTime type, YamlNode x, DefAssembly y)
+ {
+ return DataUtil.CreateDateTime(GetLowerTextValue(x));
+ }
+ }
+}
diff --git a/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs b/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs
index b1c5193..ad4ec5c 100644
--- a/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs
+++ b/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs
@@ -21,6 +21,7 @@ namespace Luban.Job.Cfg.DataSources
case "lua": source = new Lua.LuaDataSource(); break;
case "json": source = new Json.JsonDataSource(); break;
case "b": source = new Binary.BinaryDataSource(); break;
+ case "yml": source = new Yaml.YamlDataSource(); break;
default: throw new Exception($"不支持的文件类型:{url}");
}
source.Load(url, sheetName, stream, exportTestData);
diff --git a/src/Luban.Job.Cfg/Source/DataSources/Yaml/YamlDataSource.cs b/src/Luban.Job.Cfg/Source/DataSources/Yaml/YamlDataSource.cs
new file mode 100644
index 0000000..145f1e4
--- /dev/null
+++ b/src/Luban.Job.Cfg/Source/DataSources/Yaml/YamlDataSource.cs
@@ -0,0 +1,68 @@
+using Luban.Job.Cfg.DataCreators;
+using Luban.Job.Cfg.Datas;
+using Luban.Job.Cfg.Defs;
+using Luban.Job.Cfg.Utils;
+using Luban.Job.Common.Types;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using YamlDotNet.RepresentationModel;
+
+namespace Luban.Job.Cfg.DataSources.Yaml
+{
+ class YamlDataSource : AbstractDataSource
+ {
+ private YamlMappingNode _root;
+ public override void Load(string rawUrl, string sheetName, Stream stream, bool exportDebugData)
+ {
+ var ys = new YamlStream();
+ ys.Load(new StreamReader(stream));
+ var rootNode = (YamlMappingNode)ys.Documents[0].RootNode;
+ if (string.IsNullOrEmpty(sheetName))
+ {
+ this._root = rootNode;
+ }
+ else
+ {
+ if (rootNode.Children.TryGetValue(new YamlScalarNode(sheetName), out var childNode))
+ {
+ this._root = (YamlMappingNode)childNode;
+ }
+ else
+ {
+ throw new Exception($"yaml文件:{RawUrl} 不包含子字段:{sheetName}");
+ }
+ }
+ }
+
+ public override List ReadMulti(TBean type)
+ {
+ throw new NotImplementedException();
+ }
+
+ private readonly static YamlScalarNode s_tagNameNode = new(TAG_KEY);
+
+ public override Record ReadOne(TBean type)
+ {
+ string tagName;
+ if (_root.Children.TryGetValue(s_tagNameNode, out var tagNode))
+ {
+ tagName = (string)tagNode;
+ }
+ else
+ {
+ tagName = null;
+ }
+ if (DataUtil.IsIgnoreTag(tagName))
+ {
+ return null;
+ }
+ var data = (DBean)type.Apply(YamlDataCreator.Ins, _root, (DefAssembly)type.Bean.AssemblyBase);
+ bool isTest = DataUtil.IsTestTag(tagName);
+ return new Record(data, RawUrl, isTest);
+ }
+ }
+}