From 8e3d2baca676cfb39d5d6e3b463f5c93bf9196e9 Mon Sep 17 00:00:00 2001 From: Pavel Shevaev Date: Mon, 23 Oct 2023 11:13:52 +0300 Subject: [PATCH] Initial commit --- .gitignore | 1 + README.md | 19 +++++ composer.json | 15 ++++ src/bind.inc.php | 58 ++++++++++++++ tpl/bind_ecslite.twig | 176 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 269 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 composer.json create mode 100644 src/bind.inc.php create mode 100644 tpl/bind_ecslite.twig diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e92f57 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tags diff --git a/README.md b/README.md new file mode 100644 index 0000000..6dc8f3b --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +This package is used for code generation of bhl2 LeoECS Lite bindings for C# using Twig templates + +Here the example of bindings declaration: + +@shared_tokens:{"bhl_bind":true, "bhl_ecslite_component_entity":"EcsEntity"} + +struct EcsEntity + @bhl_no_new @bhl_native_class:Leopotam.EcsLite.EcsPackedEntityWithWorld @bhl_custom_rw +end + +struct Velocity + @bhl_native_class:`BitGames.GamePlay.Components.Velocity` @bhl_ecslite_component + Value : Vector3 +end + +struct Position + @bhl_native_class:`BitGames.GamePlay.Components.Position` @bhl_ecslite_component + Value : Vector3 +end diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c846b79 --- /dev/null +++ b/composer.json @@ -0,0 +1,15 @@ +{ + "name": "bit/metagen_bhl_bind_ecslite", + "description": "bhl bindings code generation utils for LeoECS lite", + "homepage": "https://git.bit5.ru/bit/metagen_bhl_bind_ecslite", + "require": { + "php": ">=7.4", + "twig/twig" : "v3.4.3", + "bit/metagen" : "^v3.0.0" + }, + "autoload": { + "files": [ + "src/bind.inc.php" + ] + } +} diff --git a/src/bind.inc.php b/src/bind.inc.php new file mode 100644 index 0000000..39c6a08 --- /dev/null +++ b/src/bind.inc.php @@ -0,0 +1,58 @@ +getLoader(); + $loader->setPaths( + array_merge( + $loader->getPaths(), + [__DIR__ . "/../tpl"] + ) + ); + + //let's collect units we're responsible for + foreach($meta->getUnits() as $u) + { + if($u->object->hasToken('bhl_ecslite_component')) + { + $this->units[] = $u; + } + } + + //let's remove our units from the original collection + foreach($this->units as $u) + { + $meta->delUnit($u); + } + } + + function codegenDecls(\Twig\Environment $twig) + { + return ''; + } + + function codegenRegister(\Twig\Environment $twig) + { + $code = ''; + foreach($this->units as $u) + { + if($u->object->hasToken('bhl_ecslite_component')) + $code .= $twig->render('bind_ecslite.twig', ['unit' => $u->object]); + } + return $code; + } +} diff --git a/tpl/bind_ecslite.twig b/tpl/bind_ecslite.twig new file mode 100644 index 0000000..891b1b2 --- /dev/null +++ b/tpl/bind_ecslite.twig @@ -0,0 +1,176 @@ +{% import "bhl_bind_macro.twig" as bhl_bind %} + +{%- macro reg_ecslite_component(o) ~%} + { + var fn = new FuncSymbolNative(new Origin(), "{{o.name}}_Ensure", Types.Void, + #if !BHL_FRONT + delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) { + EcsPackedEntityWithWorld e = default; + stack.PopRelease().Decode(ref e); + + if (e.Unpack(out EcsWorld world, out int id) == false) + return null; + + ref var cmp = ref world.GetPool<{{o.name}}>().Ensure(id); + + return null; + } + #else + null + #endif + , + new FuncArgSymbol("__self", types.T("{{token(o, 'bhl_ecslite_component_entity')}}")) + ); + types.ns.Define(fn); + } + + { + var fn = new FuncSymbolNative(new Origin(), "{{o.name}}_Del", Types.Void, + #if !BHL_FRONT + delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) { + EcsPackedEntityWithWorld e = default; + stack.PopRelease().Decode(ref e); + + if (e.Unpack(out EcsWorld world, out int id) == false) + return null; + + world.GetPool<{{o.name}}>().Del(id); + + return null; + } + #else + null + #endif + , + new FuncArgSymbol("__self", types.T("{{token(o, 'bhl_ecslite_component_entity')}}")) + ); + types.ns.Define(fn); + } + + { + var fn = new FuncSymbolNative(new Origin(), "{{o.name}}_Exists", Types.Bool, + #if !BHL_FRONT + delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) { + EcsPackedEntityWithWorld e = default; + stack.PopRelease().Decode(ref e); + + var dv = bhl.Val.New(frm.vm); + + if (e.Unpack(out EcsWorld world, out int id) == false) + dv.SetBool(false); + else + dv.SetBool(world.GetPool<{{o.name}}>().Has(id)); + stack.Push(dv); + + return null; + } + #else + null + #endif + , + new FuncArgSymbol("__self", types.T("{{token(o, 'bhl_ecslite_component_entity')}}")) + ); + types.ns.Define(fn); + } + + {% for f in o.getfields %} + {{ _self.ecslite_component_field(o, f) }} + {% endfor %} + + {% for m in o.getfuncs %} + {{ _self.ecslite_component_func(o, m) }} + {% endfor %} + +{%- endmacro -%} + +{%- macro ecslite_component_field(o, f) ~%} + { + var fn = new FuncSymbolNative(new Origin(), "{{o.name}}_{{f.name}}", {{f.type|bhl_type_ref}}, + {%- if token_or(f, 'bhl_set', 1) != 0 ~%} + 1, + {%- endif ~%} + delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) { + #if !BHL_FRONT + Val dv = null; + + {%- if token_or(f, 'bhl_set', 1) != 0 ~%} + if(args_info.CountArgs() > 1) + dv = stack.Pop(); + {%- endif ~%} + + EcsPackedEntityWithWorld e = default; + stack.PopRelease().Decode(ref e); + + if (e.Unpack(out EcsWorld world, out int id) == false) + return null; + + ref var cmp = ref world.GetPool<{{o.name}}>().Ensure(id); + var v = cmp.{{f.name}}; + + {%- if token_or(f, 'bhl_set', 1) != 0 ~%} + if(dv != null) { + {{ bhl_bind.val2native(f.type, 'dv', 'v') }}; + cmp.{{f.name}} = v; + dv.Release(); + } + {%- endif ~%} + + dv = Val.New(frm.vm); + { + {{ bhl_bind.native2val(f.type, 'v', 'dv') }}; + } + stack.Push(dv); + #endif + return null; + }, + new FuncArgSymbol("e", types.T("{{token(o, 'bhl_ecslite_component_entity')}}")) + {%- if token_or(f, 'bhl_set', 1) != 0 ~%} + , new FuncArgSymbol("v", {{f.type|bhl_type_ref}}) + {%- endif ~%} + ); + types.ns.Define(fn); + } +{%- endmacro -%} + +{%- macro ecslite_component_func(o, m) ~%} + { + var fn = new FuncSymbolNative(new Origin(), "{{o.name}}_{{m.name}}", + {{m.returntype|bhl_type_ref}}, + {{ count_default_args(m) }}, + #if !BHL_FRONT + delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) { + EcsPackedEntityWithWorld e = default; + + {{ bhl_bind.read_args2natives(m, '__') }} + + stack.PopRelease().Decode(ref e); + + if (e.Unpack(out EcsWorld world, out int id) == false) + return null; + + ref var cmp = ref world.GetPool<{{o.name}}>().Ensure(id); + + {%~ if m.returntype %} + var return_val = + {%- endif ~%} + + cmp.{{m.name}}( + {%- for arg in m.args ~%} __{{arg.name}}{% if not loop.last %},{% endif %} {%- endfor ~%} + ); + + {{ bhl_bind.return_val(m, 'return_val') }} + + return null; + } + #else + null + #endif + , new FuncArgSymbol("__self", types.T("{{token(o, 'bhl_ecslite_component_entity')}}")) + {%- if m.args %},{% endif ~%} + {{ bhl_bind.func_decl_args(m) }} + ); + types.ns.Define(fn); + } +{%- endmacro -%} + +{{ _self.reg_ecslite_component(unit) }}