264 lines
6.3 KiB
Haxe
264 lines
6.3 KiB
Haxe
|
package kha.netsync;
|
||
|
|
||
|
import haxe.macro.Context;
|
||
|
import haxe.macro.Expr;
|
||
|
import haxe.macro.Expr.Field;
|
||
|
|
||
|
class SyncBuilder {
|
||
|
public static var nextId: Int = 0;
|
||
|
public static var objects: Array<Dynamic> = new Array<Dynamic>();
|
||
|
|
||
|
macro static public function build(): Array<Field> {
|
||
|
var fields = Context.getBuildFields();
|
||
|
|
||
|
var isBaseEntity = false;
|
||
|
for (i in Context.getLocalClass().get().interfaces) {
|
||
|
var intf = i.t.get();
|
||
|
if (intf.module == "kha.netsync.Sync") {
|
||
|
isBaseEntity = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (field in fields) {
|
||
|
if (field.name == "new") {
|
||
|
switch (field.kind) {
|
||
|
case FFun(f):
|
||
|
var cexpr = f.expr;
|
||
|
cexpr = macro @:mergeBlock {
|
||
|
$cexpr;
|
||
|
kha.netsync.SyncBuilder.objects[_syncId()] = this;
|
||
|
}
|
||
|
f.expr = cexpr;
|
||
|
continue;
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var synced = false;
|
||
|
// TODO: Avoid hardcoding the target ids
|
||
|
var target = 0; // kha.netsync.Session.RPC_SERVER;
|
||
|
var isStatic = field.access.lastIndexOf(AStatic) >= 0;
|
||
|
for (meta in field.meta) {
|
||
|
if (meta.name == "sync" || meta.name == "synced") {
|
||
|
// TODO: Figure out if there is a "nicer" way to do this
|
||
|
for (param in meta.params) {
|
||
|
if (param.expr.equals(EConst(CString("server")))) {
|
||
|
target = 0; // kha.netsync.Session.RPC_SERVER;
|
||
|
break;
|
||
|
}
|
||
|
else if (param.expr.equals(EConst(CString("all")))) {
|
||
|
target = 1; // kha.netsync.Session.RPC_ALL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
synced = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!synced)
|
||
|
continue;
|
||
|
|
||
|
switch (field.kind) {
|
||
|
case FFun(f):
|
||
|
var original = f.expr;
|
||
|
|
||
|
var size = 6;
|
||
|
for (arg in f.args) {
|
||
|
switch (arg.type) {
|
||
|
case TPath(p):
|
||
|
switch (p.name) {
|
||
|
case "Int":
|
||
|
size += 5;
|
||
|
case "Float":
|
||
|
size += 9;
|
||
|
case "Bool":
|
||
|
size += 2;
|
||
|
}
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var expr = macro @:mergeBlock {
|
||
|
var size: Int = $v{size};
|
||
|
};
|
||
|
|
||
|
for (arg in f.args) {
|
||
|
switch (arg.type) {
|
||
|
case TPath(p):
|
||
|
switch (p.name) {
|
||
|
case "String":
|
||
|
var argname = arg.name;
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
size += $i{argname}.length + 3;
|
||
|
}
|
||
|
}
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var classname = Context.getLocalClass().toString();
|
||
|
var methodname = field.name;
|
||
|
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
size += $v{classname}.length + 2;
|
||
|
size += $v{methodname}.length + 2;
|
||
|
var bytes = haxe.io.Bytes.alloc(size);
|
||
|
bytes.set(0, kha.netsync.Session.REMOTE_CALL);
|
||
|
bytes.set(1, $v{target});
|
||
|
}
|
||
|
|
||
|
if (isStatic) {
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
bytes.setInt32(2, -1);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
bytes.setInt32(2, _syncId());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
var index = 6;
|
||
|
|
||
|
bytes.setUInt16(index, $v{classname}.length);
|
||
|
index += 2;
|
||
|
for (i in 0...$v{classname}.length) {
|
||
|
bytes.set(index, $v{classname}.charCodeAt(i));
|
||
|
++index;
|
||
|
}
|
||
|
|
||
|
bytes.setUInt16(index, $v{methodname}.length);
|
||
|
index += 2;
|
||
|
for (i in 0...$v{methodname}.length) {
|
||
|
bytes.set(index, $v{methodname}.charCodeAt(i));
|
||
|
++index;
|
||
|
}
|
||
|
};
|
||
|
for (arg in f.args) {
|
||
|
switch (arg.type) {
|
||
|
case TPath(p):
|
||
|
switch (p.name) {
|
||
|
case "Int":
|
||
|
var argname = arg.name;
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
bytes.set(index, 'I'.charCodeAt(0));
|
||
|
++index;
|
||
|
bytes.setInt32(index, $i{argname});
|
||
|
index += 4;
|
||
|
};
|
||
|
case "String":
|
||
|
var argname = arg.name;
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
bytes.set(index, 'S'.charCodeAt(0));
|
||
|
++index;
|
||
|
bytes.setUInt16(index, $i{argname}.length);
|
||
|
index += 2;
|
||
|
for (i in 0...$i{argname}.length) {
|
||
|
bytes.set(index, $i{argname}.charCodeAt(i));
|
||
|
++index;
|
||
|
}
|
||
|
};
|
||
|
case "Float":
|
||
|
var argname = arg.name;
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
bytes.set(index, 'F'.charCodeAt(0));
|
||
|
++index;
|
||
|
bytes.setDouble(index, $i{argname});
|
||
|
index += 8;
|
||
|
};
|
||
|
case "Bool":
|
||
|
var argname = arg.name;
|
||
|
expr = macro @:mergeBlock {
|
||
|
$expr;
|
||
|
bytes.set(index, 'B'.charCodeAt(0));
|
||
|
++index;
|
||
|
bytes.set(index, $i{argname} ?1:0);
|
||
|
++index;
|
||
|
};
|
||
|
default:
|
||
|
trace("Warning: type '" + p.name + "' of property '" + arg.name + "' cannot be synced");
|
||
|
}
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if sys_server
|
||
|
expr = macro {
|
||
|
if (kha.netsync.Session.the() != null) {
|
||
|
$expr;
|
||
|
kha.netsync.Session.the().processRPC(bytes);
|
||
|
}
|
||
|
};
|
||
|
#else
|
||
|
expr = macro {
|
||
|
if (kha.netsync.Session.the() != null) {
|
||
|
$expr;
|
||
|
kha.netsync.Session.the().sendToServer(bytes);
|
||
|
}
|
||
|
else {
|
||
|
$original;
|
||
|
}
|
||
|
};
|
||
|
#end
|
||
|
|
||
|
fields.push({
|
||
|
name: field.name + "_remotely",
|
||
|
doc: null,
|
||
|
meta: [],
|
||
|
access: (isStatic ? [APublic, AStatic] : [APublic]),
|
||
|
kind: FFun({
|
||
|
ret: f.ret,
|
||
|
params: f.params,
|
||
|
expr: original,
|
||
|
args: f.args
|
||
|
}),
|
||
|
pos: Context.currentPos()
|
||
|
});
|
||
|
|
||
|
f.expr = expr;
|
||
|
default:
|
||
|
trace("Warning: Synced property " + field.name + " is not a function.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fields.push({
|
||
|
name: "_syncId",
|
||
|
doc: null,
|
||
|
meta: [],
|
||
|
access: isBaseEntity ? [APublic] : [APublic, AOverride],
|
||
|
kind: FFun({
|
||
|
ret: Context.toComplexType(Context.getType("Int")),
|
||
|
params: null,
|
||
|
expr: macro {
|
||
|
return __syncId;
|
||
|
},
|
||
|
args: []
|
||
|
}),
|
||
|
pos: Context.currentPos()
|
||
|
});
|
||
|
|
||
|
if (isBaseEntity) {
|
||
|
fields.push({
|
||
|
name: "__syncId",
|
||
|
doc: null,
|
||
|
meta: [],
|
||
|
access: [APublic],
|
||
|
kind: FVar(macro : Int, macro kha.netsync.SyncBuilder.nextId++),
|
||
|
pos: Context.currentPos()
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return fields;
|
||
|
}
|
||
|
}
|