Compare commits
No commits in common. "master" and "v4.8.3" have entirely different histories.
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -1,24 +1,3 @@
|
|||
## v7.1.0
|
||||
- Using a shared helper method to streamline the generated code
|
||||
|
||||
## v7.0.0
|
||||
- Using a dedicated wrapper for i18n strings to streamline the generated code
|
||||
|
||||
## v6.1.0
|
||||
- Removed redundant accessor interface declarations in generated slices
|
||||
|
||||
## v5.0.0
|
||||
- Splitting one huge codegenerated file into multiple ones
|
||||
|
||||
## v4.10.0
|
||||
- Added @flt_i18n token to support translations
|
||||
|
||||
## v4.9.2
|
||||
- Added @cs_obsolete token, that mark fields with [Obsolete]. @cs_obsolete:"Comment" will add summary with "Comment" to field
|
||||
|
||||
## v4.9.1
|
||||
- Fixing nested diffable POD structs being incorrectly marked as clean in GetDiff
|
||||
|
||||
## v4.8.2
|
||||
- Fixing thread safety possible issue when reading an array of enums
|
||||
- Fixing bug when the target enum array property wouldn't be cleared before reading data
|
||||
|
@ -27,4 +6,4 @@
|
|||
- Using C# built-in initialization routines instead of MetaIO's methods
|
||||
|
||||
## v4.7.0
|
||||
- Array comparison generated code now takes bitfields token into account for array entries
|
||||
- Array comparison generated code now takes bitfields token into account for array entries
|
|
@ -2,10 +2,9 @@ This package is used for code generation of C# meta structs using Twig templates
|
|||
|
||||
Usage example:
|
||||
|
||||
$output = \metagen_cs\codegen(null, get_meta(),
|
||||
$code = \metagen_cs\codegen(null, get_meta(),
|
||||
[
|
||||
'namespace' => 'BitGames.Autogen'
|
||||
]);
|
||||
foreach($output as $name => $text)
|
||||
file_put_contents($name, $text);
|
||||
file_put_contents('bundle.cs', $code);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace metagen_cs;
|
||||
use Exception;
|
||||
|
||||
function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) : array
|
||||
function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) : string
|
||||
{
|
||||
$twig = get_twig();
|
||||
|
||||
|
@ -15,21 +15,7 @@ function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) :
|
|||
if(!isset($options['namespace']))
|
||||
$options['namespace'] = 'BitGames.Autogen';
|
||||
|
||||
$sliced_units = slice_units($meta->getUnits(), 50);
|
||||
|
||||
$output = array();
|
||||
|
||||
foreach($sliced_units as $slice_idx => $slice_units)
|
||||
{
|
||||
$slice_options = $options;
|
||||
$slice_options['slice_idx'] = $slice_idx;
|
||||
$slice_options['slice_units'] = $slice_units;
|
||||
$output['types_'.$slice_idx.'.cs'] = $twig->render('codegen_types_slice.twig', $slice_options);
|
||||
}
|
||||
|
||||
$output['factory.cs'] = $twig->render('codegen_factory.twig', $options);
|
||||
|
||||
return $output;
|
||||
return $twig->render('codegen_bundle.twig', $options);
|
||||
}
|
||||
|
||||
function get_twig(array $inc_path = []) : \Twig\Environment
|
||||
|
@ -69,7 +55,6 @@ function supported_tokens() : array
|
|||
'cs_propget_interface',
|
||||
'cs_propset_interface',
|
||||
'cs_propgetset_interface',
|
||||
'cs_obsolete',
|
||||
//TODO:
|
||||
//'i18n'
|
||||
];
|
||||
|
@ -137,18 +122,9 @@ function _add_twig_support(\Twig\Environment $twig)
|
|||
}
|
||||
));
|
||||
$twig->addFilter(new \Twig\TwigFilter('cs_type',
|
||||
function($type, $fld = null)
|
||||
{
|
||||
return cs_type($type, $fld);
|
||||
}
|
||||
));
|
||||
$twig->addFilter(new \Twig\TwigFilter('cs_simple_type',
|
||||
function($type)
|
||||
{
|
||||
if($type instanceof \mtgArrType)
|
||||
return cs_simple_type($type->getValue());
|
||||
else
|
||||
return cs_simple_type($type);
|
||||
return cs_type($type);
|
||||
}
|
||||
));
|
||||
$twig->addFilter(new \Twig\TwigFilter('cs_type_prefix',
|
||||
|
@ -213,14 +189,10 @@ function _add_twig_support(\Twig\Environment $twig)
|
|||
));
|
||||
}
|
||||
|
||||
function cs_type(\mtgType $type, $fld = null)
|
||||
function cs_type(\mtgType $type)
|
||||
{
|
||||
if($type instanceof \mtgBuiltinType || $type instanceof \mtgUserType)
|
||||
{
|
||||
if($fld != null && $fld->hasToken("flt_i18n"))
|
||||
return "MetaI18NString";
|
||||
return cs_simple_type($type);
|
||||
}
|
||||
else if($type instanceof \mtgArrType)
|
||||
return "List<" . cs_simple_type($type->getValue()) . ">";
|
||||
else
|
||||
|
@ -260,7 +232,7 @@ function cs_simple_type(\mtgType $type)
|
|||
case "bool":
|
||||
return "bool";
|
||||
case "blob":
|
||||
return "ArraySegment<byte>";
|
||||
return "byte[]";
|
||||
}
|
||||
throw new Exception("Unknown type '{$type}'");
|
||||
}
|
||||
|
@ -371,7 +343,7 @@ function var_reset($name, \mtgType $type, $default = null)
|
|||
$str .= " = ".trim($default, '"').";";
|
||||
}
|
||||
else
|
||||
$str .= ' = default;';
|
||||
$str .= ' = null;';
|
||||
}
|
||||
else
|
||||
throw new Exception("Unknown type '$type'");
|
||||
|
@ -423,16 +395,16 @@ function var_reset($name, \mtgType $type, $default = null)
|
|||
|
||||
if($default)
|
||||
{
|
||||
$default_val = is_array($default) ? $default : json_decode($default, true);
|
||||
if(is_array($default_val))
|
||||
$default = is_array($default) ? $default : json_decode($default, true);
|
||||
if(is_array($default))
|
||||
{
|
||||
foreach($default_val as $k => $v)
|
||||
foreach($default as $k => $v)
|
||||
{
|
||||
$kf = $type->getField($k);
|
||||
$str .= var_reset("$name." . $kf->getName(), $kf->getType(), $v);
|
||||
}
|
||||
}
|
||||
else if(is_null_str($default))
|
||||
else if($default === null)
|
||||
$str .= "$name = null; ";
|
||||
else
|
||||
throw new Exception("Bad default value for struct: " . var_export($default, true));
|
||||
|
@ -445,7 +417,7 @@ function var_reset($name, \mtgType $type, $default = null)
|
|||
|
||||
function is_null_str($default)
|
||||
{
|
||||
return is_string($default) && strtolower($default) === 'null';
|
||||
return is_string($default) && json_decode($default, true) === null;
|
||||
}
|
||||
|
||||
function var_sync($fname, \mtgType $type, $buf, array $tokens, $opts)
|
||||
|
@ -455,10 +427,7 @@ function var_sync($fname, \mtgType $type, $buf, array $tokens, $opts)
|
|||
$str = '';
|
||||
if($type instanceof \mtgBuiltinType)
|
||||
{
|
||||
if($type->isString() && array_key_exists('flt_i18n', $tokens))
|
||||
$str .= "$fname.SyncSingular({$buf}, \"{$key_name}\", {$opts});\n"; //TODO: plurals support
|
||||
else
|
||||
$str .= "MetaIO.Sync({$buf}, ref {$fname}, \"{$key_name}\", {$opts});\n";
|
||||
$str .= "MetaIO.Sync({$buf}, ref {$fname}, \"{$key_name}\", {$opts});\n";
|
||||
}
|
||||
else if($type instanceof \mtgMetaStruct)
|
||||
{
|
||||
|
@ -471,7 +440,7 @@ function var_sync($fname, \mtgType $type, $buf, array $tokens, $opts)
|
|||
{
|
||||
$str .= "int __tmp_{$fname} = (int)$fname;\n";
|
||||
$str .= "MetaIO.Sync({$buf}, ref __tmp_{$fname}, \"{$key_name}\", {$opts});\n";
|
||||
$str .= "if($buf.is_read) {$fname} = (".cs_type($type).")__tmp_{$fname};\n";
|
||||
$str .= "if($buf.is_read) {$fname} = ({$type->getName()})__tmp_{$fname};\n";
|
||||
}
|
||||
else if($type instanceof \mtgArrType)
|
||||
{
|
||||
|
@ -612,11 +581,6 @@ class AccessorInterfaceField
|
|||
return $this->field->getName();
|
||||
}
|
||||
|
||||
function hasToken($token)
|
||||
{
|
||||
return $this->field->hasToken($token);
|
||||
}
|
||||
|
||||
function getCamelFieldName()
|
||||
{
|
||||
$name_parts = explode("_", $this->field->getName());
|
||||
|
@ -739,41 +703,3 @@ function get_field_index(\mtgMetaStruct $struct, string $field_name): int
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function paginate($total, $step)
|
||||
{
|
||||
//pages are returned as an array where each element is in interval [N, Y)
|
||||
$pages = array();
|
||||
|
||||
$steps = (int)($total/$step);
|
||||
$rest = $total % $step;
|
||||
|
||||
for($i=1;$i<=$steps;++$i)
|
||||
$pages[] = array(($i-1)*$step, $i*$step);
|
||||
|
||||
if($rest != 0)
|
||||
$pages[] = array(($i-1)*$step, ($i-1)*$step + $rest);
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
//slices array like this: [[idx0,[..]], [idx1,[..]], ...]
|
||||
function slice_units(array $units, $max)
|
||||
{
|
||||
$pages = paginate(sizeof($units), $max);
|
||||
|
||||
$sliced = array();
|
||||
|
||||
$units_keys = array_keys($units);
|
||||
|
||||
foreach($pages as $idx => $page)
|
||||
{
|
||||
$slice = array();
|
||||
for($i = $page[0];$i<$page[1];++$i)
|
||||
{
|
||||
$slice[] = $units[$units_keys[$i]];
|
||||
}
|
||||
$sliced[$idx] = $slice;
|
||||
}
|
||||
return $sliced;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//THIS FILE IS GENERATED AUTOMATICALLY, DO NOT TOUCH IT!
|
||||
using System.Collections.Generic;
|
||||
using metagen;
|
||||
using System;
|
||||
|
||||
{%- import "macro.twig" as macro -%}
|
||||
|
||||
|
@ -9,9 +8,7 @@ using System;
|
|||
namespace {{namespace}} {
|
||||
{% endif %}
|
||||
|
||||
{%- for ai in get_all_declarable_accessor_interfaces(meta) ~%}
|
||||
{{ macro.decl_accessor_interface(ai) }}
|
||||
{%- endfor ~%}
|
||||
{{ macro.decl_units(meta) }}
|
||||
|
||||
static public class AutogenBundle
|
||||
{
|
|
@ -1,16 +0,0 @@
|
|||
//THIS FILE IS GENERATED AUTOMATICALLY, DO NOT TOUCH IT!
|
||||
using System.Collections.Generic;
|
||||
using metagen;
|
||||
using System;
|
||||
|
||||
{%- import "macro.twig" as macro -%}
|
||||
|
||||
{% if namespace is defined ~%}
|
||||
namespace {{namespace}} {
|
||||
{% endif %}
|
||||
|
||||
{{ macro.decl_units(slice_units) }}
|
||||
|
||||
{% if namespace is defined ~%}
|
||||
} //namespace {{namespace}}
|
||||
{% endif %}
|
121
tpl/macro.twig
121
tpl/macro.twig
|
@ -1,6 +1,6 @@
|
|||
{% macro decl_units(units) %}
|
||||
{% macro decl_units(meta) %}
|
||||
|
||||
{%- for u in units ~%}
|
||||
{%- for u in meta.getunits ~%}
|
||||
{%- if u.object is instanceof('\\mtgMetaStruct') -%}
|
||||
{{ _self.decl_struct(u.object) }}
|
||||
{%- elseif u.object is instanceof('\\mtgMetaEnum') -%}
|
||||
|
@ -10,6 +10,10 @@
|
|||
{%- endif ~%}
|
||||
{%- endfor ~%}
|
||||
|
||||
{%- for ai in get_all_declarable_accessor_interfaces(meta) ~%}
|
||||
{{ _self.decl_accessor_interface(ai) }}
|
||||
{%- endfor ~%}
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
{% macro decl_struct(o, extra = '') %}
|
||||
|
@ -156,27 +160,17 @@ public FieldsMask fields_mask;
|
|||
|
||||
{%- macro decl_struct_field(o, f) -%}
|
||||
{{_self.attributes(f)}}
|
||||
public {{f.type|cs_type(f)|obscure_type(f)}} {{f.name}} {% if not has_token(o, 'POD') -%} {{_self.decl_init_value(f)}} {%- endif -%};
|
||||
public {{f.type|cs_type|obscure_type(f)}} {{f.name}} {% if not has_token(o, 'POD') -%} {{_self.decl_init_value(f)}} {%- endif -%};
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro decl_init_value(f) %}
|
||||
{%- if f.type is instanceof('\\mtgBuiltinType') -%}
|
||||
{%- if f.type.isstring -%}
|
||||
{% if has_token(f, 'flt_i18n') -%}
|
||||
{%- if has_token(f, 'default') -%}
|
||||
= new({{token(f, 'default')}})
|
||||
{%- else -%}
|
||||
= new()
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
= ""
|
||||
{%- endif ~%}
|
||||
{%- endif -%}
|
||||
{%- if f.type.isstring -%} = ""{%- endif -%}
|
||||
{%- else -%}
|
||||
{%- if has_token(f, 'default') and token(f, 'default') == 'null' -%}
|
||||
/*null*/
|
||||
{%- else -%}
|
||||
= new {{f.type|cs_type(f)}}()
|
||||
= new {{f.type|cs_type}}()
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
|
@ -186,11 +180,7 @@ public {{f.type|cs_type(f)|obscure_type(f)}} {{f.name}} {% if not has_token(o, '
|
|||
base.Reset();
|
||||
{%- endif -%}
|
||||
{%- for f in o.fields ~%}
|
||||
{% if has_token(f, 'flt_i18n') -%}
|
||||
{{f.name}}?.Reset();
|
||||
{%- else ~%}
|
||||
{{var_reset(f.name, f.type, token_or(f, 'default', null))}}
|
||||
{%- endif ~%}
|
||||
{%- endfor -%}
|
||||
{%- if has_token(o, 'bitfields') ~%}
|
||||
ResetFieldMask();
|
||||
|
@ -198,12 +188,6 @@ ResetFieldMask();
|
|||
{% endmacro %}
|
||||
|
||||
{%- macro attributes(o) %}
|
||||
{% if has_token(o, "cs_obsolete") %}
|
||||
/// <summary>
|
||||
/// {{token(o, "cs_obsolete")}}
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
{% endif %}
|
||||
{%- if has_token(o, 'cs_attributes') -%}
|
||||
{%- for attr in token(o, 'cs_attributes')|split(',') -%}
|
||||
[{{attr}}]
|
||||
|
@ -319,7 +303,14 @@ base.SyncFields(ctx);
|
|||
int fields_amount = {{fields_count(o)}};
|
||||
var primary_id_mask = FieldsMask.MakeClean(fields_amount);
|
||||
SetPrimaryFieldsChanged(ref primary_id_mask);
|
||||
return FieldsMask.CheckContentsChanged(fields_amount, ref primary_id_mask, ref fields_mask);
|
||||
for(int i = 0; i < fields_amount; i++)
|
||||
{
|
||||
bool is_primary_id = primary_id_mask.IsDirty(i);
|
||||
if(!is_primary_id && fields_mask.IsDirty(i))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetDirtyMask()
|
||||
|
@ -468,7 +459,7 @@ public class {{o.name}} : IRpc
|
|||
}
|
||||
else if(old > item)
|
||||
{
|
||||
item.SetDirtyMaskDeep();
|
||||
item.SetDirtyMask();
|
||||
if(changed != null)
|
||||
changed.Add(item);
|
||||
i++;
|
||||
|
@ -492,7 +483,7 @@ public class {{o.name}} : IRpc
|
|||
for(; i < items.Count; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
item.SetDirtyMaskDeep();
|
||||
item.SetDirtyMask();
|
||||
if(changed != null)
|
||||
changed.Add(item);
|
||||
has_diff = true;
|
||||
|
@ -541,48 +532,10 @@ public class {{o.name}} : IRpc
|
|||
{{has_token(o, 'bitfields')?'CompareAndMarkFields':'IsEqual'}}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro field_compare_array_bitfields_nested_diffable(o, f, field_idx) %}
|
||||
{
|
||||
int {{f.name}}_count_a = a.{{f.name}} == null ? 0 : a.{{f.name}}.Count;
|
||||
int {{f.name}}_count_b = b.{{f.name}} == null ? 0 : b.{{f.name}}.Count;
|
||||
{%- macro field_compare(o, f, field_idx) -%}
|
||||
|
||||
//For NESTED arrays of DIFFABLE structs:
|
||||
//for DB compatibility we must add the WHOLE ARRAY to the diff if ANY ELEMENT of the array has changed.
|
||||
//That means marking each element's fields_mask as dirty
|
||||
|
||||
//Changed size means the array has changed, no furhter checks required.
|
||||
bool {{f.name}}_equal = {{f.name}}_count_a == {{f.name}}_count_b;
|
||||
|
||||
//For same size arrays - check contents for changes.
|
||||
if({{f.name}}_equal)
|
||||
{
|
||||
for(int i=0;i<{{f.name}}_count_a && i<{{f.name}}_count_b;++i)
|
||||
{
|
||||
var tmp_{{f.name}} = a.{{f.name}}[i];
|
||||
if(!CompareAndMarkFields(ref tmp_{{f.name}}, b.{{f.name}}[i]))
|
||||
{
|
||||
{{f.name}}_equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If change detected - mark top-level field as changed and add the whole array to the diff
|
||||
if(!{{f.name}}_equal)
|
||||
{
|
||||
MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
|
||||
for(int i=0; i<{{f.name}}_count_a;++i)
|
||||
{
|
||||
var tmp_{{f.name}} = a.{{f.name}}[i];
|
||||
tmp_{{f.name}}.SetDirtyMaskDeep();
|
||||
a.{{f.name}}[i] = tmp_{{f.name}};
|
||||
is_equal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro field_compare_array_bitfields_nested_plain(o, f, field_idx) %}
|
||||
{% if f.type is instanceof('\\mtgArrType') ~%}
|
||||
{% if has_token(o, 'bitfields') ~%}
|
||||
if(a.{{f.name}} == null ||
|
||||
b.{{f.name}} == null ||
|
||||
a.{{f.name}}.Count != b.{{f.name}}.Count)
|
||||
|
@ -612,9 +565,7 @@ public class {{o.name}} : IRpc
|
|||
{%- endif -%}
|
||||
}
|
||||
}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro field_compare_array_plain(o, f, field_idx) %}
|
||||
{% else ~%}
|
||||
if(a.{{f.name}} == null ||
|
||||
b.{{f.name}} == null ||
|
||||
a.{{f.name}}.Count != b.{{f.name}}.Count)
|
||||
|
@ -630,19 +581,6 @@ public class {{o.name}} : IRpc
|
|||
return false;
|
||||
{%- endif -%}
|
||||
}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro field_compare(o, f, field_idx) -%}
|
||||
|
||||
{% if f.type is instanceof('\\mtgArrType') ~%}
|
||||
{% if has_token(o, 'bitfields') ~%}
|
||||
{% if has_token(f.type.value, 'bitfields') ~%}
|
||||
{{_self.field_compare_array_bitfields_nested_diffable(o, f, field_idx)}}
|
||||
{% else ~%}
|
||||
{{_self.field_compare_array_bitfields_nested_plain(o, f, field_idx)}}
|
||||
{% endif ~%}
|
||||
{% else ~%}
|
||||
{{_self.field_compare_array_plain(o, f, field_idx)}}
|
||||
{% endif ~%}
|
||||
|
||||
{% elseif f.type is instanceof('\\mtgMetaStruct') ~%}
|
||||
|
@ -737,12 +675,12 @@ public interface {{ai.interfacename}}
|
|||
{
|
||||
{%- for aif in ai.fields ~%}
|
||||
{% if aif.is_accessor -%}
|
||||
{{aif.field.type|cs_type(aif)}} Get{{aif.camelfieldname}}();
|
||||
void Set{{aif.camelfieldname}}({{aif.field.type|cs_type(aif)}} v);
|
||||
{{aif.field.type|cs_type}} Get{{aif.camelfieldname}}();
|
||||
void Set{{aif.camelfieldname}}({{aif.field.type|cs_type}} v);
|
||||
{% endif -%}
|
||||
|
||||
{%- if aif.is_propget -%}
|
||||
{{aif.field.type|cs_type(aif)}} {{aif.camelfieldname}} {
|
||||
{{aif.field.type|cs_type}} {{aif.camelfieldname}} {
|
||||
{%- if aif.is_propget -%}
|
||||
get;
|
||||
{%- endif %}
|
||||
|
@ -759,18 +697,18 @@ public interface {{ai.interfacename}}
|
|||
{%- for ai in get_accessor_interfaces(o) ~%}
|
||||
{%- for aif in ai.fields ~%}
|
||||
{% if aif.is_accessor %}
|
||||
public {{aif.field.type|cs_type(aif)}} Get{{aif.camelfieldname}}()
|
||||
public {{aif.field.type|cs_type}} Get{{aif.camelfieldname}}()
|
||||
{
|
||||
return {{aif.field.name}};
|
||||
}
|
||||
public void Set{{aif.camelfieldname}}({{aif.field.type|cs_type(aif)}} v)
|
||||
public void Set{{aif.camelfieldname}}({{aif.field.type|cs_type}} v)
|
||||
{
|
||||
this.{{aif.field.name}} = v;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if aif.is_propget or aif.is_propset %}
|
||||
public {{aif.field.type|cs_type(aif)}} {{aif.camelfieldname}} {
|
||||
public {{aif.field.type|cs_type}} {{aif.camelfieldname}} {
|
||||
{%- if aif.is_propget -%}
|
||||
get => this.{{aif.field.name}};
|
||||
{%- endif -%}
|
||||
|
@ -782,3 +720,4 @@ public interface {{ai.interfacename}}
|
|||
{% endfor %}
|
||||
{%- endfor ~%}
|
||||
{% endmacro %}
|
||||
|
||||
|
|
Loading…
Reference in New Issue