forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			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;
 | |
| 	}
 | |
| }
 |