679 lines
18 KiB
PHP
679 lines
18 KiB
PHP
|
<?php
|
||
|
|
||
|
include_once(dirname(__FILE__) . "/../utils/metagen/targets/php/php.inc.php");
|
||
|
include_once(dirname(__FILE__) . "/../utils/metagen/targets/cs/cs_generator.inc.php");
|
||
|
include_once(dirname(__FILE__) . "/../utils/metagen/targets/cs/cs.inc.php");
|
||
|
|
||
|
define('META_FLT_CLIENT', 1);
|
||
|
define('META_FLT_SERVER', 2);
|
||
|
define('META_FLT_BINDINGS', 4);
|
||
|
|
||
|
function get_meta($opts)
|
||
|
{
|
||
|
$m = parse_meta();
|
||
|
$m = _meta_filter($m, $opts);
|
||
|
return $m;
|
||
|
}
|
||
|
|
||
|
function parse_meta()
|
||
|
{
|
||
|
global $GAME_ROOT;
|
||
|
$meta_dirs = array("$GAME_ROOT/meta/");
|
||
|
$meta_files = scan_files_rec($meta_dirs);
|
||
|
$meta_cache = "$GAME_ROOT/build/tmp/meta.cache";
|
||
|
if(need_to_regen($meta_cache, $meta_files))
|
||
|
{
|
||
|
$meta = mtg_parse_meta($meta_dirs);
|
||
|
process_meta($meta);
|
||
|
validate_meta($meta);
|
||
|
ensure_write($meta_cache, serialize($meta));
|
||
|
return $meta;
|
||
|
}
|
||
|
else
|
||
|
return unserialize(ensure_read($meta_cache));
|
||
|
}
|
||
|
|
||
|
function process_meta(mtgMetaInfo $meta)
|
||
|
{
|
||
|
foreach($meta->getUnits() as $u)
|
||
|
{
|
||
|
$o = $u->object;
|
||
|
|
||
|
if($o instanceof mtgMetaStruct)
|
||
|
{
|
||
|
if($o->hasToken("table") && $o->hasToken("id") && $o->hasToken("owner"))
|
||
|
{
|
||
|
foreach($o->getFields() as $fld)
|
||
|
$fld->setToken("optional", true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function validate_meta(mtgMetaInfo $meta)
|
||
|
{
|
||
|
foreach($meta->getUnits() as $u)
|
||
|
{
|
||
|
$o = $u->object;
|
||
|
|
||
|
if($o instanceof mtgMetaStruct)
|
||
|
{
|
||
|
$optional_spotted = false;
|
||
|
foreach($o->getFields() as $idx => $fld)
|
||
|
{
|
||
|
if(!$optional_spotted && $fld->hasToken("optional"))
|
||
|
$optional_spotted = true;
|
||
|
else if($optional_spotted && !$fld->hasToken("optional"))
|
||
|
throw new Exception("Field '{$fld->getName()}' in struct '{$o->getName()}' must be marked as @optional since there are preceding optional fields");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _meta_filter(mtgMetaInfo $meta, $opts)
|
||
|
{
|
||
|
$filtered = new mtgMetaInfo();
|
||
|
|
||
|
foreach($meta->getUnits() as $u)
|
||
|
{
|
||
|
$o = $u->object;
|
||
|
|
||
|
if(($opts & META_FLT_CLIENT) != 0 &&
|
||
|
($o->hasToken('autogen') ||
|
||
|
strpos($u->file, 'bind.meta') === false)
|
||
|
)
|
||
|
{
|
||
|
$filtered->addUnit($u);
|
||
|
}
|
||
|
|
||
|
if(($opts & META_FLT_SERVER) != 0 &&
|
||
|
strpos($u->file, 'bind.meta') === false
|
||
|
)
|
||
|
{
|
||
|
$filtered->addUnit($u);
|
||
|
}
|
||
|
|
||
|
if(($opts & META_FLT_BINDINGS) != 0 && (
|
||
|
strpos($u->file, 'bind.meta') !== false ||
|
||
|
$o instanceof mtgMetaEnum ||
|
||
|
($o instanceof mtgUserType && $o->hasToken('bhl_bind')))
|
||
|
)
|
||
|
{
|
||
|
$filtered->addUnit($u);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $filtered;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deps cs_autogen
|
||
|
* @alias dlls
|
||
|
*/
|
||
|
function task_client_dlls()
|
||
|
{
|
||
|
global $GAME_ROOT;
|
||
|
|
||
|
build_mono_dll(
|
||
|
"$GAME_ROOT/dll_src/crc/",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_crc.dll"
|
||
|
);
|
||
|
|
||
|
build_mono_dll(
|
||
|
"$GAME_ROOT/dll_src/msgpack/",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_msgpack.dll"
|
||
|
);
|
||
|
|
||
|
build_mono_dll(
|
||
|
"$GAME_ROOT/dll_src/CodeStage/AntiCheatToolkit/Scripts/",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_obscured.dll",
|
||
|
array(
|
||
|
"UnityEngine.dll",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_crc.dll",
|
||
|
)
|
||
|
);
|
||
|
|
||
|
build_mono_dll(
|
||
|
"$GAME_ROOT/utils/metagen/targets/cs/metagen.cs",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_metagen.dll",
|
||
|
array(
|
||
|
"$GAME_ROOT/Assets/Plugins/game_msgpack.dll",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_obscured.dll",
|
||
|
),
|
||
|
is_dev() ? "-debug" : ""
|
||
|
);
|
||
|
|
||
|
build_mono_dll(
|
||
|
"$GAME_ROOT/dll_src/metagen/autogen",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_autogen.dll",
|
||
|
array(
|
||
|
"UnityEngine.dll",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_metagen.dll",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_obscured.dll",
|
||
|
"$GAME_ROOT/Assets/Plugins/game_msgpack.dll",
|
||
|
),
|
||
|
is_dev() ? "-debug -define:DEBUG" : ""
|
||
|
);
|
||
|
|
||
|
//$bhl_dll = bhl_build_dll();
|
||
|
|
||
|
//build_mono_dll(
|
||
|
// "$GAME_ROOT/dll_src/bhl/autobind.cs",
|
||
|
// "$GAME_ROOT/Assets/Plugins/game_bhl_autobind.dll",
|
||
|
// array(
|
||
|
// "UnityEngine.dll",
|
||
|
// "$GAME_ROOT/Assets/Plugins/game_metagen.dll",
|
||
|
// "$GAME_ROOT/Assets/Plugins/game_autogen.dll",
|
||
|
// "$GAME_ROOT/Assets/Plugins/game_obscured.dll",
|
||
|
// $bhl_dll
|
||
|
// ),
|
||
|
// is_dev() ? "-debug" : ""
|
||
|
//);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deps unity_defines,cs_autogen,php_autogen
|
||
|
*/
|
||
|
function task_autogen()
|
||
|
{}
|
||
|
|
||
|
/**
|
||
|
* @deps make_client_settings
|
||
|
*/
|
||
|
function task_cs_autogen()
|
||
|
{
|
||
|
global $GAME_ROOT;
|
||
|
|
||
|
include_once("$GAME_ROOT/utils/metagen/metagen.inc.php");
|
||
|
|
||
|
$meta = get_meta(META_FLT_CLIENT);
|
||
|
|
||
|
mtg_run(new CustomCsGenerator(), array(
|
||
|
"codegen" => new CustomCsCodegen(),
|
||
|
"meta" => $meta,
|
||
|
"out-dir" => "$GAME_ROOT/dll_src/metagen/autogen" ,
|
||
|
"bundle" => "$GAME_ROOT/dll_src/metagen/autogen/bundle.cs",
|
||
|
));
|
||
|
}
|
||
|
|
||
|
function task_php_autogen()
|
||
|
{
|
||
|
global $GAME_ROOT;
|
||
|
|
||
|
include_once("$GAME_ROOT/utils/metagen/metagen.inc.php");
|
||
|
include_once("$GAME_ROOT/utils/metagen/targets/php/php_generator.inc.php");
|
||
|
|
||
|
$meta = get_meta(META_FLT_SERVER);
|
||
|
|
||
|
mtg_run(new mtgPHPGenerator(),
|
||
|
array(
|
||
|
"codegen" => new CustomPHPCodegen(array(
|
||
|
'str2num' => 'flt_str2num',
|
||
|
'str2hash' => 'flt_str2hash',
|
||
|
'hex2num' => 'flt_hex2num',
|
||
|
'str2stamp' => 'flt_str2stamp',
|
||
|
'i18n' => 'flt_i18n',
|
||
|
)),
|
||
|
"meta" => $meta,
|
||
|
"out-dir" => "$GAME_ROOT/utils/autogen/" ,
|
||
|
"inc-dir" => "GAME_ROOT.'/utils/autogen/'",
|
||
|
"bundle" => "$GAME_ROOT/utils/autogen/bundle.inc.php"
|
||
|
));
|
||
|
|
||
|
init_php_autogen_bundle();
|
||
|
}
|
||
|
|
||
|
class CustomPHPCodegen extends mtgPHPCodegen
|
||
|
{
|
||
|
function preprocessField(mtgMetaStruct $struct, mtgMetaField $field)
|
||
|
{
|
||
|
if($field->hasToken("i18n"))
|
||
|
{
|
||
|
$new_fld = new mtgMetaField('__' . $field->getName(), new mtgTypeRef(new mtgArrType(new mtgTypeRef(new mtgBuiltinType('string')))));
|
||
|
$new_fld->setTokens(array('default' => '[]'));
|
||
|
|
||
|
$this->addTempField($struct, $new_fld);
|
||
|
}
|
||
|
else
|
||
|
parent::preprocessField($struct, $field);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class CustomCsGenerator extends mtgCsGenerator
|
||
|
{
|
||
|
function genBundle($OUT, array $DEPS, mtgMetaInfo $meta, mtgCsCodegen $codegen, array $units)
|
||
|
{
|
||
|
$str = parent::genBundle($OUT, $DEPS, $meta, $codegen, $units);
|
||
|
$str = "using CodeStage.AntiCheat.ObscuredTypes;\n" . $str;
|
||
|
return $str;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class CustomCsCodegen extends mtgCsCodegen
|
||
|
{
|
||
|
function fillStructRepls(mtgMetaStruct $struct, &$repl)
|
||
|
{
|
||
|
parent::fillStructRepls($struct, $repl);
|
||
|
|
||
|
if($struct->hasToken('diffable'))
|
||
|
{
|
||
|
$all_diff_classes = array();
|
||
|
$repl['%ext_methods%'] .= $this->genStructDiff($struct, $all_diff_classes);
|
||
|
foreach($all_diff_classes as $class)
|
||
|
$repl['%ext_methods%'] .= $this->genDiffHelpers($class);
|
||
|
|
||
|
$repl['%ext_methods%'] .= $this->genRemovedIdsHelpers();
|
||
|
}
|
||
|
|
||
|
if($struct->hasToken("id"))
|
||
|
{
|
||
|
$repl['%ext_methods%'] .=
|
||
|
"\n public ulong getPrimaryId() {".
|
||
|
"\n " . sprintf("return (ulong)%s;", $struct->getToken("id")) .
|
||
|
"\n }";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function genRemovedIdsHelpers()
|
||
|
{
|
||
|
$str = <<<EOD
|
||
|
|
||
|
static public List<ulong> GetClassRemovedIds(List<DataClassIds> removed_ids, uint class_id)
|
||
|
{
|
||
|
if(removed_ids == null)
|
||
|
return null;
|
||
|
DataClassIds res;
|
||
|
if(!FindClassRemovedIds(removed_ids, class_id, out res))
|
||
|
{
|
||
|
res = new DataClassIds();
|
||
|
res.class_id = class_id;
|
||
|
res.ids = new List<ulong>();
|
||
|
removed_ids.Add(res);
|
||
|
}
|
||
|
return res.ids;
|
||
|
}
|
||
|
|
||
|
static bool FindClassRemovedIds(List<DataClassIds> removed_ids, uint class_id, out DataClassIds res)
|
||
|
{
|
||
|
for(int i=0;i<removed_ids.Count;++i)
|
||
|
{
|
||
|
if(removed_ids[i].class_id == class_id)
|
||
|
{
|
||
|
res = removed_ids[i];
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
res = default(DataClassIds);
|
||
|
return false;
|
||
|
}
|
||
|
EOD;
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function preprocessField(mtgMetaStruct $struct, mtgMetaField $field)
|
||
|
{
|
||
|
if($field->hasToken('i18n'))
|
||
|
{
|
||
|
$new_fld = new mtgMetaField('__' . $field->getName(), new mtgTypeRef(new mtgArrType(new mtgTypeRef(new mtgBuiltinType('string')))));
|
||
|
$new_fld->setTokens(array('default' => '[]'));
|
||
|
$this->addTempField($struct, $new_fld);
|
||
|
|
||
|
//NOTE: renaming field, adding a prefix, real field access will be done via property
|
||
|
$this->tempRenameField($field, '_' . $field->getName());
|
||
|
}
|
||
|
else
|
||
|
parent::preprocessField($struct, $field);
|
||
|
}
|
||
|
|
||
|
function genI18NField($field, $prop_name)
|
||
|
{
|
||
|
global $pluralization_mark;
|
||
|
$type = $this->genFieldNativeType($field);
|
||
|
|
||
|
return "\n\n".
|
||
|
" public $type $prop_name {\n".
|
||
|
" get { return plural_$prop_name(double.NaN); }\n".
|
||
|
" set { _{$prop_name} = value; }\n".
|
||
|
" }\n".
|
||
|
|
||
|
" public {$type} plural_${prop_name}(double force_n) { return Meta.I18NPick(_{$prop_name}, __{$prop_name}, \"{$pluralization_mark}\", force_n); }\n";
|
||
|
}
|
||
|
|
||
|
function genFieldDecl(mtgMetaStruct $struct, mtgMetaField $field)
|
||
|
{
|
||
|
$str = parent::genFieldDecl($struct, $field);
|
||
|
|
||
|
$type = $field->getType();
|
||
|
|
||
|
if($field->hasToken('i18n'))
|
||
|
{
|
||
|
$prop_name = substr($field->getName(), 1);
|
||
|
$str .= $this->genI18NField($field, $prop_name);
|
||
|
}
|
||
|
else if($field->hasToken('obscured'))
|
||
|
{
|
||
|
if($type instanceof mtgBuiltinType && $type->isUint32())
|
||
|
$str = str_replace(" uint ", " ObscuredUInt ", $str);
|
||
|
else if($type instanceof mtgBuiltinType && $type->isUint64())
|
||
|
$str = str_replace(" ulong ", " ObscuredULong ", $str);
|
||
|
else if($type instanceof mtgBuiltinType && $type->isInt64())
|
||
|
$str = str_replace(" long ", " ObscuredLong ", $str);
|
||
|
else if($type instanceof mtgBuiltinType && $type->isFloat())
|
||
|
$str = str_replace(" float ", " ObscuredFloat ", $str);
|
||
|
else
|
||
|
throw new Exception("Not supported obscured type: " . $type);
|
||
|
}
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genFieldDiff(mtgMetaField $field, $field_idx, $prefix, array &$all_diff_classes)
|
||
|
{
|
||
|
$str = '';
|
||
|
$type = $field->getType();
|
||
|
$name = $field->getName();
|
||
|
|
||
|
if($type instanceof mtgMetaStruct)
|
||
|
{
|
||
|
if(!$type->hasToken('POD'))
|
||
|
throw new Exception("Diffable struct '{$type->getName()}' must be POD");
|
||
|
$all_diff_classes[] = $type->getName();
|
||
|
$str .= "{\n";
|
||
|
$str .= "var __tmp = {$prefix}{$name};\n";
|
||
|
$str .= "if(DiffOne(ref __tmp, old.{$prefix}{$name})) { no_changes &= false; if(diff != null) { diff.{$prefix}{$name} = __tmp; Meta.SetFieldDirty(ref diff.fields_mask, {$field_idx}); } }\n";
|
||
|
$str .= "}\n";
|
||
|
}
|
||
|
else if($type instanceof mtgArrType)
|
||
|
{
|
||
|
$sub_type = $type->getValue();
|
||
|
if(!$sub_type->hasToken('POD'))
|
||
|
throw new Exception("Diffable struct '{$sub_type->getName()}' must be POD");
|
||
|
$all_diff_classes[] = $sub_type->getName();
|
||
|
$str .= "if(DiffCollection({$prefix}{$name}, old.{$prefix}{$name}, diff == null ? null : diff.{$prefix}{$name}, removed)) { no_changes &= false; if(diff != null) { Meta.SetFieldDirty(ref diff.fields_mask, {$field_idx}); } }\n";
|
||
|
}
|
||
|
else if($type instanceof mtgBuiltinType)
|
||
|
{
|
||
|
$str .= "if(diff != null) { diff.$name = {$prefix}{$name}; } if({$prefix}{$name} != old.{$prefix}{$name}) { no_changes &= false; if(diff != null) { Meta.SetFieldDirty(ref diff.fields_mask, {$field_idx}); } }\n";
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Diff for field '$name' is not supported");
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genStructDiff(mtgMetaStruct $struct, array &$all_diff_classes)
|
||
|
{
|
||
|
$class = $struct->getName();
|
||
|
$str = "\n\n";
|
||
|
$str .= "public bool GetDiff($class old, $class diff = null, List<DataClassIds> removed = null)\n";
|
||
|
$str .= "{\n";
|
||
|
$str .= " if(diff != null) diff.reset();\n";
|
||
|
$str .= " bool no_changes = true;\n";
|
||
|
|
||
|
$fields = $struct->getFields();
|
||
|
$field_idx = -1;
|
||
|
foreach($fields as $field)
|
||
|
{
|
||
|
++$field_idx;
|
||
|
if($field->hasToken('nodiff'))
|
||
|
continue;
|
||
|
$str .= $this->genFieldDiff($field, $field_idx, '', $all_diff_classes);
|
||
|
}
|
||
|
|
||
|
$str .= " return !no_changes;\n";
|
||
|
$str .= "}\n";
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genDiffHelpers($class)
|
||
|
{
|
||
|
$struct = $this->info->findUnit($class)->object;
|
||
|
$compare_fn_str = $this->genCompareFunc($struct);
|
||
|
|
||
|
$has_bitfields_token = $struct->hasToken("bitfields");
|
||
|
$compare_func_name = $has_bitfields_token ? "CompareAndMarkFields" : "IsEqual";
|
||
|
|
||
|
$str = <<<EOD
|
||
|
|
||
|
static public bool DiffOne(ref $class curr, $class old)
|
||
|
{
|
||
|
return !$compare_func_name(ref curr, old);
|
||
|
}
|
||
|
|
||
|
static public bool DiffCollection(List<$class> items, List<$class> old_items, List<$class> changed, List<DataClassIds> removed)
|
||
|
{
|
||
|
bool has_diff = false;
|
||
|
if(changed != null)
|
||
|
changed.Clear();
|
||
|
|
||
|
SortByPrimaryId(ref items);
|
||
|
SortByPrimaryId(ref old_items);
|
||
|
|
||
|
int i = 0;
|
||
|
int old_i = 0;
|
||
|
for(; i < items.Count && old_i < old_items.Count;)
|
||
|
{
|
||
|
var old = old_items[old_i];
|
||
|
var item = items[i];
|
||
|
|
||
|
if(old.getPrimaryId() < item.getPrimaryId())
|
||
|
{
|
||
|
var removed_ids = GetClassRemovedIds(removed, $class.STATIC_CLASS_ID);
|
||
|
if(removed_ids != null)
|
||
|
removed_ids.Add(old.getPrimaryId());
|
||
|
old_i++;
|
||
|
has_diff = true;
|
||
|
}
|
||
|
else if(old.getPrimaryId() > item.getPrimaryId())
|
||
|
{
|
||
|
item.SetDirtyMask();
|
||
|
if(changed != null)
|
||
|
changed.Add(item);
|
||
|
i++;
|
||
|
has_diff = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(!$compare_func_name(ref item, old))
|
||
|
{
|
||
|
if(changed != null)
|
||
|
changed.Add(item);
|
||
|
has_diff = true;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
old_i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//items leftovers are considered changed
|
||
|
for(; i < items.Count; i++)
|
||
|
{
|
||
|
var item = items[i];
|
||
|
item.SetDirtyMask();
|
||
|
if(changed != null)
|
||
|
changed.Add(item);
|
||
|
has_diff = true;
|
||
|
}
|
||
|
|
||
|
//old items leftovers are considered removed
|
||
|
for(; old_i < old_items.Count; old_i++)
|
||
|
{
|
||
|
var removed_ids = GetClassRemovedIds(removed, $class.STATIC_CLASS_ID);
|
||
|
if(removed_ids != null)
|
||
|
removed_ids.Add(old_items[old_i].getPrimaryId());
|
||
|
has_diff = true;
|
||
|
}
|
||
|
|
||
|
//if(changed.Count > 0)
|
||
|
// Meta.LogDebug("Changed in collection $class");
|
||
|
//if(removed_ids.Count > 0)
|
||
|
// Meta.LogDebug("Removed in collection $class");
|
||
|
|
||
|
return has_diff;
|
||
|
}
|
||
|
|
||
|
class {$class}Compare : IComparer<$class>
|
||
|
{
|
||
|
public int Compare($class o1, $class o2)
|
||
|
{
|
||
|
var id1 = o1.getPrimaryId();
|
||
|
var id2 = o2.getPrimaryId();
|
||
|
if(id1 == id2)
|
||
|
return 0;
|
||
|
return id1 > id2 ? 1 : -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static {$class}Compare {$class}_compare = new {$class}Compare();
|
||
|
|
||
|
static void SortByPrimaryId(ref List<$class> list)
|
||
|
{
|
||
|
list.Sort({$class}_compare);
|
||
|
}
|
||
|
|
||
|
public static bool $compare_func_name(ref $class a, $class b)
|
||
|
{
|
||
|
bool is_equal = true;
|
||
|
|
||
|
$compare_fn_str
|
||
|
|
||
|
return is_equal;
|
||
|
}
|
||
|
EOD;
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genCompareFunc(mtgMetaStruct $struct)
|
||
|
{
|
||
|
$has_bitfields_token = $struct->hasToken("bitfields");
|
||
|
|
||
|
$str = '';
|
||
|
$index = 0;
|
||
|
|
||
|
if($has_bitfields_token)
|
||
|
$str .= "a.ResetFieldMask();\n";
|
||
|
|
||
|
foreach($struct->getFields() as $field)
|
||
|
{
|
||
|
$str .= $this->genFieldCompare($field, $index, $has_bitfields_token);
|
||
|
$index++;
|
||
|
}
|
||
|
|
||
|
if($has_bitfields_token)
|
||
|
{
|
||
|
$str .= $this->offset(3)."if(!is_equal)\n";
|
||
|
$str .= $this->offset(4)."a.SetPrimaryFieldsChanged();";
|
||
|
}
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genFieldCompare(mtgMetaField $field, $index, $has_bitfields_token)
|
||
|
{
|
||
|
$name = $this->genFieldName($field);
|
||
|
$str = '';
|
||
|
$type = $field->getType();
|
||
|
|
||
|
if($type instanceof mtgArrType)
|
||
|
{
|
||
|
$str .= "if(a.{$name} == null || b.{$name} == null || a.{$name}.Count != b.{$name}.Count) return false;\n";
|
||
|
$str .= "for(int i=0;i<a.{$name}.Count;++i) {\n ";
|
||
|
|
||
|
$sub_type = $type->getValue();
|
||
|
if($sub_type instanceof mtgMetaStruct)
|
||
|
$str .= "if(!IsEqual(ref a.{$name}[i], b.{$name}[i])) return false;\n";
|
||
|
else
|
||
|
$str .= "if(a.{$name}[i] != b.{$name}[i]) return false;\n";
|
||
|
|
||
|
$str .= "}\n";
|
||
|
}
|
||
|
else if($type instanceof mtgMetaStruct)
|
||
|
$str .= "if(!IsEqual(ref a.{$name}, b.{$name})) return false;\n";
|
||
|
else if($type instanceof mtgBuiltinType && $type->isString())
|
||
|
{
|
||
|
$str .= $this->offset(3)."if((a.{$name} == null ? \"\" : a.{$name}) != (b.{$name} == null ? \"\" : b.{$name}))\n";
|
||
|
if($has_bitfields_token)
|
||
|
{
|
||
|
$str .= $this->offset(3)."{\n";
|
||
|
$str .= $this->offset(4)."Meta.SetFieldDirty(ref a.fields_mask, $index);\n";
|
||
|
$str .= $this->offset(4)."is_equal = false;\n";
|
||
|
$str .= $this->offset(3)."}\n";
|
||
|
}
|
||
|
else
|
||
|
$str .= "return false;\n";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
$str .= $this->offset(3)."if(a.{$name} != b.{$name})\n";
|
||
|
|
||
|
if($has_bitfields_token)
|
||
|
{
|
||
|
$str .= $this->offset(3)."{\n";
|
||
|
$str .= $this->offset(4)."Meta.SetFieldDirty(ref a.fields_mask, $index);\n";
|
||
|
$str .= $this->offset(4)."is_equal = false;\n";
|
||
|
$str .= $this->offset(3)."}\n";
|
||
|
}
|
||
|
else
|
||
|
$str .= "return false;\n";
|
||
|
}
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function init_php_autogen_bundle()
|
||
|
{
|
||
|
global $GAME_ROOT;
|
||
|
include_once("$GAME_ROOT/utils/gme/utils.inc.php");
|
||
|
include_once("$GAME_ROOT/utils/autogen/bundle.inc.php");
|
||
|
}
|
||
|
|
||
|
function mtg_flt_i18n($val, $name, $struct, $args)
|
||
|
{
|
||
|
//NOTE: if value is an array we assume it's an expression
|
||
|
// and assign it to a special property
|
||
|
if(is_array($val))
|
||
|
{
|
||
|
$arr_name = '__' . $name;
|
||
|
|
||
|
foreach($val as $v)
|
||
|
array_push($struct->$arr_name, i18n_decode_string($v));
|
||
|
|
||
|
return '';
|
||
|
}
|
||
|
else
|
||
|
return i18n_decode_string($val);
|
||
|
}
|
||
|
|
||
|
function mtg_flt_str2num($val, $name, $struct, $args)
|
||
|
{
|
||
|
if(is_string($val))
|
||
|
{
|
||
|
if(strlen($val) === 0)
|
||
|
throw new Exception("Bad value, string empty, crc28 can't be generated");
|
||
|
|
||
|
//special case
|
||
|
if(strpos($val, '@') !== 0)
|
||
|
throw new Exception("@ expected");
|
||
|
|
||
|
$val = substr($val, 1) . '.conf.js';
|
||
|
|
||
|
$path = config_base_dir() . '/' . $val;
|
||
|
if(!file_exists($path))
|
||
|
throw new Exception("No such file '$path'");
|
||
|
|
||
|
if(config_get_header($path, $proto_id, $alias))
|
||
|
$val = $proto_id;
|
||
|
else
|
||
|
$val = mtg_crc28($val);
|
||
|
}
|
||
|
|
||
|
if(!is_numeric($val))
|
||
|
throw new Exception("Bad value, not a number(" . serialize($val) . ")");
|
||
|
|
||
|
return 1*$val;
|
||
|
}
|