【特性】支持gdscript语言

main
Dongua 2022-06-09 12:31:42 +08:00
parent f756ab2aa2
commit 60faab741e
19 changed files with 474 additions and 34 deletions

View File

@ -121,6 +121,11 @@ namespace Luban.Common.Utils
return module.Replace('.', '_') + name;
}
public static string MakeGDScriptFullName(string module, string name)
{
return UpperCaseFirstChar(module.Replace('.', '_') + name);
}
public static string MakeRustFullName(string module, string name)
{
return MakeGoNamespace(module) + name;

View File

@ -8,7 +8,7 @@ namespace Luban.Job.Cfg
[Option('s', "service", Required = true, HelpText = "service")]
public string Service { get; set; }
[Option("gen_types", Required = true, HelpText = "code_cs_bin,code_cs_dotnet_json,code_cs_unity_json,code_cs_unity_editor_json,code_lua_bin,code_java_bin,code_java_json,code_go_bin,code_go_json,code_cpp_bin,code_cpp_ue_editor_json,code_python2_json,code_python3_json,code_typescript_bin,code_typescript_json,code_rust_json,code_protobuf,code_template,code_flatbuffers,data_bin,data_lua,data_json,data_json2,data_json_monolithic,data_yaml,data_xml,data_resources,data_template,data_protobuf_bin,data_protobuf_json,data_flatbuffers_json,convert_json,convert_lua,convert_xlsx . can be multi")]
[Option("gen_types", Required = true, HelpText = "code_cs_bin,code_cs_dotnet_json,code_cs_unity_json,code_cs_unity_editor_json,code_lua_bin,code_java_bin,code_java_json,code_go_bin,code_go_json,code_cpp_bin,code_cpp_ue_editor_json,code_python2_json,code_python3_json,code_typescript_bin,code_typescript_json,code_rust_json,code_protobuf,code_template,code_flatbuffers,code_gdscript_json,data_bin,data_lua,data_json,data_json2,data_json_monolithic,data_yaml,data_xml,data_resources,data_template,data_protobuf_bin,data_protobuf_json,data_flatbuffers_json,convert_json,convert_lua,convert_xlsx . can be multi")]
public string GenType { get; set; }
[Option("input_data_dir", Required = true, HelpText = "input data dir")]

View File

@ -0,0 +1,39 @@
using Luban.Job.Cfg.Defs;
using Luban.Job.Common.Generate;
using Luban.Job.Common.Tpl;
using Luban.Job.Common.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.Generate
{
[Render("code_gdscript_json")]
internal class GDScriptCodeJsonRender : TemplateCodeRenderBase
{
protected override string RenderTemplateDir => "gdscript_json";
public override void Render(GenContext ctx)
{
ctx.Render = this;
ctx.Lan = Common.ELanguage.GDSCRIPT;
DefAssembly.LocalAssebmly.CurrentLanguage = ctx.Lan;
var lines = new List<string>(10000);
static void PreContent(List<string> fileContent)
{
//fileContent.Add(PythonStringTemplates.ImportTython3Enum);
//fileContent.Add(PythonStringTemplates.PythonVectorTypes);
fileContent.Add(StringTemplateManager.Ins.GetTemplateString("config/gdscript_json/header"));
}
GenerateCodeMonolithic(ctx,
System.IO.Path.Combine(ctx.GenArgs.OutputCodeDir, RenderFileUtil.GetFileOrDefault(ctx.GenArgs.OutputCodeMonolithicFile, "types.gd")),
lines,
PreContent,
null);
}
}
}

View File

@ -0,0 +1,159 @@
using Luban.Job.Cfg.Datas;
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;
namespace Luban.Job.Cfg.TypeVisitors
{
class GDScriptUnderingDeserializeVisitor : ITypeFuncVisitor<string, string, string>
{
public static GDScriptUnderingDeserializeVisitor Ins { get; } = new();
public string Accept(TBool type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TByte type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TShort type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TFshort type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TInt type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TFint type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TLong type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TFlong type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TFloat type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TDouble type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TEnum type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TString type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TBytes type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
public string Accept(TText type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}['{DText.TEXT_NAME}']";
}
public string Accept(TBean type, string jsonVarName, string fieldName)
{
if (type.Bean.IsAbstractType)
{
return $"{fieldName} = {type.Bean.GDScriptFullName}.from_json({jsonVarName})";
}
else
{
return $"{fieldName} = {type.Bean.GDScriptFullName}.new({jsonVarName})";
}
}
public string Accept(TArray type, string jsonVarName, string fieldName)
{
if (type.Apply(SimpleJsonTypeVisitor.Ins))
{
return $"{fieldName} = {jsonVarName}";
}
else
{
return $"{fieldName} = []\n for _ele in {jsonVarName}:\n var {type.ElementType.Apply(this, "_ele", "_e")};\n {fieldName}.append(_e)";
}
}
public string Accept(TList type, string jsonVarName, string fieldName)
{
if (type.Apply(SimpleJsonTypeVisitor.Ins))
{
return $"{fieldName} = {jsonVarName}";
}
else
{
return $"{fieldName} = []\n for _ele in {jsonVarName}:\n var {type.ElementType.Apply(this, "_ele", "_e")};\n {fieldName}.append(_e)";
}
}
public string Accept(TSet type, string jsonVarName, string fieldName)
{
if (type.Apply(SimpleJsonTypeVisitor.Ins))
{
return $"{fieldName} = {jsonVarName}";
}
else
{
return $"{fieldName} = set()\n for _ele in {jsonVarName}:\n var {type.ElementType.Apply(this, "_ele", "_e")};\n {fieldName}.add(_e)";
}
}
public string Accept(TMap type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {{}}\n for _v in {jsonVarName}:\n {fieldName}[_v[0]] =_v[1]";
}
public string Accept(TVector2 type, string jsonVarName, string fieldName)
{
return $"{fieldName} = Vector2({jsonVarName}['x'], {jsonVarName}['y'])";
}
public string Accept(TVector3 type, string jsonVarName, string fieldName)
{
return $"{fieldName} = Vector3({jsonVarName}['x'], {jsonVarName}['y'], {jsonVarName}['z'])";
}
public string Accept(TVector4 type, string jsonVarName, string fieldName)
{
return $"{fieldName} = Vector3({jsonVarName}['x'], {jsonVarName}['y'], {jsonVarName}['z'])";
}
public string Accept(TDateTime type, string jsonVarName, string fieldName)
{
return $"{fieldName} = {jsonVarName}";
}
}
}

View File

@ -225,6 +225,30 @@ namespace Luban.Job.Cfg.Utils
}
}
public static string GdscriptDeserializeValue(string fieldName, string jsonVarName, TType type)
{
if (type.IsNullable)
{
return $"if {jsonVarName} != None: {type.Apply(GDScriptUnderingDeserializeVisitor.Ins, jsonVarName, fieldName)}";
}
else
{
return type.Apply(GDScriptUnderingDeserializeVisitor.Ins, jsonVarName, fieldName);
}
}
public static string GdscriptDeserializeField(string fieldName, string jsonVarName, string jsonFieldName, TType type)
{
if (type.IsNullable)
{
return $"if {jsonVarName}.get('{jsonFieldName}') != null: {type.Apply(GDScriptUnderingDeserializeVisitor.Ins, $"{jsonVarName}['{jsonFieldName}']", fieldName)}";
}
else
{
return type.Apply(GDScriptUnderingDeserializeVisitor.Ins, $"{jsonVarName}['{jsonFieldName}']", fieldName);
}
}
public static string DefineTextKeyField(DefField field, string lan)
{
switch (lan)
@ -266,7 +290,7 @@ namespace Luban.Job.Cfg.Utils
public static string CsUnityEditorJsonLoad(string jsonName, string fieldName, TType type)
{
return $"{type.Apply(CsEditorJsonLoad.Ins, jsonName, fieldName)}";
return $"{type.Apply(CsEditorJsonLoad.Ins, jsonName, fieldName)}";
}
public static string CsUnityEditorJsonSave(string jsonName, string jsonFieldName, string fieldName, TType type)

View File

@ -33,24 +33,25 @@ namespace Luban.Job.Common.Defs
case NamingConvention.UnderScores: cn = TypeUtil.ToUnderScores(Name); break;
case NamingConvention.Invalid: throw new Exception($"invalid NamingConvention");
case NamingConvention.LanguangeRecommend:
{
switch (curLan)
{
case ELanguage.INVALID: throw new Exception($"not set current language. can't get recommend naming convention name");
case ELanguage.CS: cn = TypeUtil.ToPascalCase(Name); break;
case ELanguage.JAVA: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.GO: cn = TypeUtil.ToPascalCase(Name); break;
case ELanguage.CPP: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.LUA: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.JAVASCRIPT: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.TYPESCRIPT: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.PYTHON: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.RUST: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.PROTOBUF: cn = Name; break;
default: throw new Exception($"unknown language:{curLan}");
switch (curLan)
{
case ELanguage.INVALID: throw new Exception($"not set current language. can't get recommend naming convention name");
case ELanguage.CS: cn = TypeUtil.ToPascalCase(Name); break;
case ELanguage.JAVA: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.GO: cn = TypeUtil.ToPascalCase(Name); break;
case ELanguage.CPP: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.LUA: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.JAVASCRIPT: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.TYPESCRIPT: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.PYTHON: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.GDSCRIPT: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.RUST: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.PROTOBUF: cn = Name; break;
default: throw new Exception($"unknown language:{curLan}");
}
break;
}
break;
}
default: throw new Exception($"unknown NamingConvention:{AssemblyBase.NamingConventionBeanMember}");
}
if (curLan == ELanguage.RUST)
@ -131,21 +132,21 @@ namespace Luban.Job.Common.Defs
switch (CType)
{
case TArray t:
{
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
}
break;
}
break;
}
case TList t:
{
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
}
break;
}
break;
}
}
}

View File

@ -53,6 +53,8 @@ namespace Luban.Job.Common.Defs
public string PyFullName => TypeUtil.MakePyFullName(Namespace, Name);
public string GDScriptFullName => TypeUtil.MakeGDScriptFullName(Namespace, Name);
public string RustFullName => TypeUtil.MakeRustFullName(Namespace, Name);
public string PbFullName => TypeUtil.MakePbFullName(Namespace, Name);

View File

@ -87,6 +87,11 @@ namespace Luban.Job.Common.Defs
return type.Apply(CppDefineTypeName.Ins);
}
public static string GdscriptDefineType(TType type)
{
return type.Apply(GDScriptDefineTypeName.Ins);
}
public static string CppConstValue(TType type, string value)
{
return type.Apply(CsConstValueVisitor.Ins, value);
@ -190,7 +195,6 @@ namespace Luban.Job.Common.Defs
return type.Apply(ErlangDefineTypeNameVisitor.Ins);
}
public static string GoDefineType(TType type)
{
return type.Apply(GoTypeNameVisitor.Ins);

View File

@ -15,5 +15,6 @@ namespace Luban.Job.Common
RUST,
PROTOBUF,
FLATBUFFERS,
GDSCRIPT,
}
}

View File

@ -0,0 +1,43 @@
using Luban.Job.Common.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Common.TypeVisitors
{
public class GDScriptDefineTypeName : DecoratorFuncVisitor<string>
{
public static PyDefineTypeName Ins { get; } = new PyDefineTypeName();
public override string DoAccept(TType type)
{
throw new System.NotSupportedException();
}
public override string Accept(TEnum type)
{
return type.DefineEnum.GDScriptFullName;
}
public override string Accept(TBean type)
{
return type.Bean.GDScriptFullName;
}
public override string Accept(TVector2 type)
{
return "Vector2";
}
public override string Accept(TVector3 type)
{
return "Vector3";
}
public override string Accept(TVector4 type)
{
return "Vector4";
}
}
}

View File

@ -265,7 +265,8 @@ namespace Luban.Job.Common.Utils
case ELanguage.PYTHON:
case ELanguage.RUST:
case ELanguage.PROTOBUF:
return System.Web.HttpUtility.HtmlEncode(comment).Replace("\n", "<br/>");
case ELanguage.GDSCRIPT:
return System.Web.HttpUtility.HtmlEncode(comment).Replace("\n", "<br/>");
default: throw new Exception($"unknown language:{curLan}");
}
}
@ -291,6 +292,7 @@ namespace Luban.Job.Common.Utils
case "rust": return ELanguage.RUST;
case "pb":
case "protobuf": return ELanguage.PROTOBUF;
case "gdscript": return ELanguage.GDSCRIPT;
default: throw new ArgumentException($"parse lan:'{lan}' fail");
}
}

View File

@ -29,6 +29,13 @@ namespace Luban.Job.Common.Utils
the code is regenerated.
</auto-generated>
'''
";
const string AUTO_GENERATE_GDScript= @"# <auto-generated>
# This code was generated by a tool.
# Changes to this file may cause incorrect behavior and will be lost if
# the code is regenerated.
# </auto-generated>
";
public static string ConcatAutoGenerationHeader(string txt, ELanguage lan)
@ -37,6 +44,7 @@ namespace Luban.Job.Common.Utils
{
case ELanguage.LUA: return AUTO_GENERATE_LUA + txt;
case ELanguage.PYTHON: return AUTO_GENERATE_PYTHON + txt;
case ELanguage.GDSCRIPT: return AUTO_GENERATE_GDScript + txt;
default: return AUTO_GENERATE_C_LIKE + txt;
}
}
@ -47,6 +55,7 @@ namespace Luban.Job.Common.Utils
{
case ELanguage.LUA: return AUTO_GENERATE_LUA;
case ELanguage.PYTHON: return AUTO_GENERATE_PYTHON;
case ELanguage.GDSCRIPT: return AUTO_GENERATE_GDScript;
default: return AUTO_GENERATE_C_LIKE;
}
}

View File

@ -19,9 +19,9 @@ namespace Luban.Job.Common.Utils
case ELanguage.TYPESCRIPT: return fullName.Replace('.', '/') + ".ts";
case ELanguage.RUST: return fullName.Replace('.', '_') + ".rs";
case ELanguage.PROTOBUF: return fullName.Replace('.', '_') + ".pb";
case ELanguage.GDSCRIPT: return fullName.Replace('.', '_') + ".gd";
default: throw new NotSupportedException();
}
}
public static string GetCsDefTypePath(string fullName)
@ -44,7 +44,6 @@ namespace Luban.Job.Common.Utils
return fullName.Replace('.', '_');
}
public static string GetCppDefTypeCppFilePath(string fullName)
{
return fullName + ".cpp";
@ -73,6 +72,7 @@ namespace Luban.Job.Common.Utils
{ "erlang", ELanguage.ERLANG },
{ "rust", ELanguage.RUST },
{ "protobuf", ELanguage.PROTOBUF },
{ "gdscript", ELanguage.GDSCRIPT },
};
public static ELanguage GetLanguage(string genType)
@ -103,6 +103,7 @@ namespace Luban.Job.Common.Utils
ELanguage.RUST => "rust",
ELanguage.PROTOBUF => "protobuf",
ELanguage.FLATBUFFERS => "flatbuffers",
ELanguage.GDSCRIPT => "gdscript",
_ => throw new Exception($"not support common template dir for lan:{lan}"),
};
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@ -73,6 +73,9 @@
<None Update="Templates\common\python\enum.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\common\gdscript\enum.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\common\rust\enum.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@ -244,6 +247,18 @@
<None Update="Templates\config\python3_json\bean.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\config\gdscript_json\header.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\config\gdscript_json\bean.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\config\gdscript_json\table.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\config\gdscript_json\tables.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Templates\config\python3_json\include.tpl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@ -0,0 +1,20 @@
{{~
name = x.name
namespace_with_top_module = x.namespace_with_top_module
comment = x.comment
items = x.items
~}}
{{~if comment != '' ~}}
# {{comment | html.escape}}
{{~end~}}
enum {{x.gdscript_full_name}}{
{{~ for item in items ~}}
{{~if item.comment != '' ~}}
{{item.name}} = {{item.int_value}}, # {{item.escape_comment}}
{{~else~}}
{{item.name}} = {{item.int_value}},
{{~end~}}
{{~end~}}
}

View File

@ -0,0 +1,39 @@
{{
name = x.gdscript_full_name
is_abstract_type = x.is_abstract_type
parent_def_type = x.parent_def_type
export_fields = x.export_fields
hierarchy_export_fields = x.hierarchy_export_fields
}}
class {{name}}:
{{if parent_def_type}}
extends {{parent_def_type.gdscript_full_name}}
{{end}}
{{~if x.is_abstract_type~}}
static func from_json(_json_):
var type = _json_['{{x.json_type_name_key}}']
match type:
{{~ for child in x.hierarchy_not_abstract_children~}}
"{{cs_impl_data_type child x}}":
return {{child.gdscript_full_name}}.new(_json_)
{{~end~}}
_:
assert(false)
{{~end~}}
{{~ for field in export_fields ~}}
var {{field.convention_name}}
{{~end~}}
{{~if parent_def_type~}}
func _init(_json_).(_json_) -> void:
{{~else~}}
func _init(_json_) -> void:
{{~end~}}
{{~if export_fields~}}
{{~ for field in export_fields ~}}
{{gdscript_deserialize_field ('self.' + field.convention_name) '_json_' field.name field.ctype}}
{{~end~}}
{{~end~}}
{{~if export_fields.empty?}}
pass
{{~end~}}

View File

@ -0,0 +1 @@
class_name Types

View File

@ -0,0 +1,62 @@
{{
name = x.gdscript_full_name
key_type = x.key_ttype
key_type1 = x.key_ttype1
key_type2 = x.key_ttype2
value_type = x.value_ttype
}}
class {{name}}:
{{~if x.is_map_table ~}}
var _data_map = {}
var _data_list = []
func _init(_json_) -> void:
self._data_map = {}
self._data_list = []
for _json2_ in _json_:
var _v
{{gdscript_deserialize_value '_v' '_json2_' value_type}}
self._data_list.append(_v)
self._data_map[_v.{{x.index_field.convention_name}}] = _v
func get_data_map() -> Dictionary:
return self._data_map
func get_data_list() -> Array:
return self._data_list
func get(key):
return self._data_map.get(key)
{{~else if x.is_list_table ~}}
var _data_list
func _init(_json_) -> void:
self._data_list = []
for _json2_ in _json_:
var _v
{{gdscript_deserialize_value '_v' '_json2_' value_type}}
self._data_list.append(_v)
func get_data_list():
return self._data_list
func get(index):
return self._data_list[index]
{{~else~}}
var _data: Dictionary
func _init(_json_) -> void:
assert(len(_json_) == 1, 'table mode=one, but size != 1')
self._data = _json_[0]
func get_data() -> Dictionary:
return self._data
{{~ for field in value_type.bean.hierarchy_export_fields ~}}
{{~if field.comment != '' ~}}
# {{field.escape_comment}}
{{~end~}}
func {{field.convention_name}}():
return self._data.{{field.convention_name}}
{{~end~}}
{{~end~}}

View File

@ -0,0 +1,13 @@
{{
name = x.name
namespace = x.namespace
tables = x.tables
}}
{{~ for table in tables ~}}
var {{table.name}}: {{table.gdscript_full_name}}
{{~end~}}
func _init(loader) -> void:
{{~for table in tables ~}}
self.{{table.name}} = {{table.gdscript_full_name}}.new(loader.call('{{table.output_data_file}}'))
{{~end~}}