// load source object into destination object recursively
function loadObject(src: Dynamic, dst: Dynamic, name: String, depth: Int)
{
for (f in Reflect.fields(src))
{
// ignore class ID marker
if (f == '_classID')
continue;
var srcval: Dynamic = Reflect.field(src, f);
var dstval = Reflect.field(dst, f);
var isEnum: Bool = untyped srcval._isEnum;
var classID: String = srcval._classID;
// enum cases
switch (Type.typeof(dstval)) {
case TEnum(e):
Reflect.setField(dst, f, initEnum(name, srcval, depth + 1));
continue;
default:
}
if (isEnum)
{
Reflect.setField(dst, f, initEnum(name, srcval, depth + 1));
continue;
}
if (Std.isOfType(srcval, Int) ||
Std.isOfType(srcval, Float) ||
Std.isOfType(srcval, Bool) ||
Std.isOfType(srcval, String))
Reflect.setField(dst, f, srcval);
else if (
Std.isOfType(srcval, Array) ||
Std.isOfType(dstval, Array) ||
Std.isOfType(dstval, List))
{
var dsttmp = new Array<Dynamic>();
var srctmp: Array<Dynamic> = untyped srcval;
for (el in srctmp)
{
if (Std.isOfType(el, Int) ||
Std.isOfType(el, Float) ||
Std.isOfType(el, Bool) ||
Std.isOfType(el, String))
dsttmp.push(el);
// NOTE: we only use Array<Array<Int>> currently
else if (Std.isOfType(el, Array))
{
// assume int atm
dsttmp.push(el);
continue;
}
var elClassID: String = untyped el._classID;
var isEnum: Bool = untyped el._isEnum;
if (elClassID == null)
dsttmp.push(el);
else if (isEnum)
dsttmp.push(initEnum(name, el, depth + 1));
else
{
var dstel = initObject(name + '.' + f + '[][]', el, depth);
dsttmp.push(dstel);
}
}
if (Std.isOfType(dstval, List))
Reflect.setField(dst, f, Lambda.list(dsttmp));
else Reflect.setField(dst, f, dsttmp);
}
else if (Std.isOfType(dstval, haxe.ds.IntMap))
{
var dsttmp = new Map<Int, Dynamic>();
for (ff in Reflect.fields(srcval))
{
var el = Reflect.field(srcval, ff);
var key = Std.parseInt(ff);
if (Std.isOfType(el, Int) ||
Std.isOfType(el, Float) ||
Std.isOfType(el, Bool) ||
Std.isOfType(el, String))
dsttmp.set(key, el);
var elClassID: String = untyped el._classID;
if (elClassID == null)
dsttmp.set(key, el);
else
{
var dstel = initObject(name + '[' + ff + ']', el, depth);
dsttmp.set(key, dstel);
}
}
Reflect.setField(dst, f, dsttmp);
}
else if (Std.isOfType(dstval, haxe.ds.StringMap))
{
var dsttmp = new Map<String, Dynamic>();
for (ff in Reflect.fields(srcval))
{
var el = Reflect.field(srcval, ff);
if (Std.isOfType(el, Int) ||
Std.isOfType(el, Float) ||
Std.isOfType(el, Bool) ||
Std.isOfType(el, String))
dsttmp.set(ff, el);
var elClassID: String = untyped el._classID;
if (elClassID == null)
dsttmp.set(ff, el);
else
{
var dstel = initObject(name + '[' + ff + ']', el, depth);
dsttmp.set(ff, dstel);
}
}
Reflect.setField(dst, f, dsttmp);
}
else if (Std.isOfType(dstval, _SaveObject))
{
loadObject(srcval, dstval, f, depth + 1);
Reflect.setField(dst, f, dstval);
}
else if (dstval == null)
{
dstval = initObject(name + '.' + f, srcval, depth);
Reflect.setField(dst, f, dstval);
}
else trace(name + '.' + f + ' type is unsupported (' +
classID + ').');
}
// common fields
var hasUI: Bool = untyped src._hasUI;
if (hasUI == null)
hasUI = false;
if (hasUI)
dst.ui = this.ui;
var hasGame: Bool = untyped src._hasGame;
if (hasGame == null)
hasGame = false;
if (hasGame)
dst.game = this;
}
// will init enum from src data { classID, isEnum, val }
function initEnum(name: String, src: Dynamic, depth: Int): Dynamic
{
var classID: String = untyped src._classID;
var ee = Type.resolveEnum(classID);
if (ee == null)
throw "No such enum: " + classID;
return Type.createEnum(ee, untyped src.val);
}
// will create a new class instance and populate it with data from save object
function initObject(name: String, src: Dynamic, depth: Int): Dynamic
{
var isEnum: Bool = untyped src._isEnum;
if (isEnum)
return initEnum(name, src, depth);
// common fields
var hasUI: Bool = untyped src._hasUI;
if (hasUI == null)
hasUI = false;
var hasGame: Bool = untyped src._hasGame;
if (hasGame == null)
hasGame = false;
var srcClassID: String = untyped src._classID;
var srcClass = Type.resolveClass(srcClassID);
if (srcClass == null)
throw 'Could not resolve class ' + srcClassID + ' src:' + src;
var dst = Type.createEmptyInstance(srcClass);
if (hasGame)
dst.game = this;
if (hasUI)
dst.ui = this.ui;
if (dst.init != null)
dst.init();
else trace('no init for ' + name);
loadObject(src, dst, name, depth + 1);
if (dst.initPost != null)
dst.initPost(true);
return dst;
}