288 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			288 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package kha.netsync; | ||
|  | 
 | ||
|  | import haxe.macro.Context; | ||
|  | import haxe.macro.Expr.Field; | ||
|  | 
 | ||
|  | class ControllerBuilder { | ||
|  | 	public static var nextId: Int = 0; | ||
|  | 
 | ||
|  | 	macro static public function build(): Array<Field> { | ||
|  | 		var fields = Context.getBuildFields(); | ||
|  | 
 | ||
|  | 		#if (!kha_server && (kha_html5 || kha_kore)) | ||
|  | 		{ | ||
|  | 			var funcindex = 0; | ||
|  | 			for (field in fields) { | ||
|  | 				var input = false; | ||
|  | 				for (meta in field.meta) { | ||
|  | 					if (meta.name == "input") { | ||
|  | 						input = true; | ||
|  | 						break; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				if (!input) | ||
|  | 					continue; | ||
|  | 
 | ||
|  | 				switch (field.kind) { | ||
|  | 					case FFun(f): | ||
|  | 						var size = 4; | ||
|  | 						for (arg in f.args) { | ||
|  | 							switch (arg.type) { | ||
|  | 								case TPath(p): | ||
|  | 									switch (p.name) { | ||
|  | 										case "Int": | ||
|  | 											size += 4; | ||
|  | 										case "String": | ||
|  | 											size += 1; | ||
|  | 										case "Float": | ||
|  | 											size += 8; | ||
|  | 										case "Bool": | ||
|  | 											size += 1; | ||
|  | 										case "KeyCode": | ||
|  | 											size += 1; | ||
|  | 									} | ||
|  | 								default: | ||
|  | 							} | ||
|  | 						} | ||
|  | 
 | ||
|  | 						var expr = macro @:mergeBlock { | ||
|  | 							var bytes = haxe.io.Bytes.alloc($v{size}); | ||
|  | 							bytes.setInt32(0, $v{funcindex}); | ||
|  | 						}; | ||
|  | 						var index: Int = 4; | ||
|  | 						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.setInt32($v{index}, $i{argname}); | ||
|  | 											}; | ||
|  | 											index += 4; | ||
|  | 										case "String": | ||
|  | 											var argname = arg.name; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												bytes.set($v{index}, $i{argname}.charCodeAt(0)); | ||
|  | 											}; | ||
|  | 											index += 1; | ||
|  | 										case "Float": | ||
|  | 											var argname = arg.name; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												bytes.setDouble($v{index}, $i{argname}); | ||
|  | 											}; | ||
|  | 											index += 8; | ||
|  | 										case "Bool": | ||
|  | 											var argname = arg.name; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												bytes.set($v{index}, $i{argname} ?1:0); | ||
|  | 											}; | ||
|  | 											index += 1; | ||
|  | 										case "KeyCode": | ||
|  | 											var argname = arg.name; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												bytes.set($v{index}, $i{argname}); | ||
|  | 											}; | ||
|  | 											index += 1; | ||
|  | 									} | ||
|  | 								default: | ||
|  | 							} | ||
|  | 						} | ||
|  | 						var original = f.expr; | ||
|  | 						expr = macro { | ||
|  | 							if (kha.netsync.Session.the() != null) { | ||
|  | 								$expr; | ||
|  | 								kha.netsync.Session.the().sendControllerUpdate(_id(), bytes); | ||
|  | 							} | ||
|  | 							$original; | ||
|  | 						}; | ||
|  | 						f.expr = expr; | ||
|  | 					default: | ||
|  | 				} | ||
|  | 				++funcindex; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		#end | ||
|  | 
 | ||
|  | 		// macros failing everywhere but in JavaScript? | ||
|  | 		#if (kha_server || kha_html5 || kha_kore) | ||
|  | 		var receive = macro @:mergeBlock { | ||
|  | 			var funcindex = bytes.getInt32(0); | ||
|  | 		}; | ||
|  | 		{ | ||
|  | 			var funcindex = 0; | ||
|  | 			for (field in fields) { | ||
|  | 				var input = false; | ||
|  | 				for (meta in field.meta) { | ||
|  | 					if (meta.name == "input") { | ||
|  | 						input = true; | ||
|  | 						break; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				if (!input) | ||
|  | 					continue; | ||
|  | 
 | ||
|  | 				switch (field.kind) { | ||
|  | 					case FFun(f): | ||
|  | 						var expr = macro {}; | ||
|  | 						var index: Int = 4; | ||
|  | 						var varindex: Int = 0; | ||
|  | 						for (arg in f.args) { | ||
|  | 							switch (arg.type) { | ||
|  | 								case TPath(p): | ||
|  | 									switch (p.name) { | ||
|  | 										case "Int": | ||
|  | 											var argname = arg.name; | ||
|  | 											var varname = "input" + varindex; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												var $varname:Int = bytes.getInt32($v{index}); | ||
|  | 											}; | ||
|  | 											index += 4; | ||
|  | 										case "String": | ||
|  | 											var argname = arg.name; | ||
|  | 											var varname = "input" + varindex; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												var $varname:String = String.fromCharCode(bytes.get($v{index})); | ||
|  | 											}; | ||
|  | 											index += 1; | ||
|  | 										case "Float": | ||
|  | 											var argname = arg.name; | ||
|  | 											var varname = "input" + varindex; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												var $varname:Float = bytes.getDouble($v{index}); | ||
|  | 											}; | ||
|  | 											index += 8; | ||
|  | 										case "Bool": | ||
|  | 											var argname = arg.name; | ||
|  | 											var varname = "input" + varindex; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												var $varname:Bool = bytes.get($v{index}) != 0; | ||
|  | 											}; | ||
|  | 											index += 1; | ||
|  | 										case "KeyCode": | ||
|  | 											var argname = arg.name; | ||
|  | 											var varname = "input" + varindex; | ||
|  | 											expr = macro @:mergeBlock { | ||
|  | 												$expr; | ||
|  | 												var $varname:kha.input.KeyCode = cast bytes.get($v{index}); | ||
|  | 											}; | ||
|  | 											index += 1; | ||
|  | 									} | ||
|  | 								default: | ||
|  | 							} | ||
|  | 							++varindex; | ||
|  | 						} | ||
|  | 						switch (varindex) { | ||
|  | 							case 1: | ||
|  | 								var funcname = field.name; | ||
|  | 								receive = macro @:mergeBlock { | ||
|  | 									$receive; | ||
|  | 									if (funcindex == $v{funcindex}) { | ||
|  | 										$expr; | ||
|  | 										$i{funcname}(input0); | ||
|  | 										return; | ||
|  | 									} | ||
|  | 								}; | ||
|  | 							case 2: | ||
|  | 								var funcname = field.name; | ||
|  | 								receive = macro @:mergeBlock { | ||
|  | 									$receive; | ||
|  | 									if (funcindex == $v{funcindex}) { | ||
|  | 										$expr; | ||
|  | 										$i{funcname}(input0, input1); | ||
|  | 										return; | ||
|  | 									} | ||
|  | 								}; | ||
|  | 							case 3: | ||
|  | 								var funcname = field.name; | ||
|  | 								receive = macro @:mergeBlock { | ||
|  | 									$receive; | ||
|  | 									if (funcindex == $v{funcindex}) { | ||
|  | 										$expr; | ||
|  | 										$i{funcname}(input0, input1, input2); | ||
|  | 										return; | ||
|  | 									} | ||
|  | 								}; | ||
|  | 							case 4: | ||
|  | 								var funcname = field.name; | ||
|  | 								receive = macro @:mergeBlock { | ||
|  | 									$receive; | ||
|  | 									if (funcindex == $v{funcindex}) { | ||
|  | 										$expr; | ||
|  | 										$i{funcname}(input0, input1, input2, input3); | ||
|  | 										return; | ||
|  | 									} | ||
|  | 								}; | ||
|  | 							case 5: | ||
|  | 								var funcname = field.name; | ||
|  | 								receive = macro @:mergeBlock { | ||
|  | 									$receive; | ||
|  | 									if (funcindex == $v{funcindex}) { | ||
|  | 										$expr; | ||
|  | 										$i{funcname}(input0, input1, input2, input3, input4); | ||
|  | 										return; | ||
|  | 									} | ||
|  | 								}; | ||
|  | 						} | ||
|  | 					default: | ||
|  | 				} | ||
|  | 				++funcindex; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		fields.push({ | ||
|  | 			name: "_receive", | ||
|  | 			doc: null, | ||
|  | 			meta: [], | ||
|  | 			access: [APublic, AOverride], | ||
|  | 			kind: FFun({ | ||
|  | 				ret: null, | ||
|  | 				params: null, | ||
|  | 				expr: receive, | ||
|  | 				args: [ | ||
|  | 					{ | ||
|  | 						value: null, | ||
|  | 						type: Context.toComplexType(Context.getType("haxe.io.Bytes")), | ||
|  | 						opt: null, | ||
|  | 						name: "bytes" | ||
|  | 					} | ||
|  | 				] | ||
|  | 			}), | ||
|  | 			pos: Context.currentPos() | ||
|  | 		}); | ||
|  | 		#else | ||
|  | 		fields.push({ | ||
|  | 			name: "_receive", | ||
|  | 			doc: null, | ||
|  | 			meta: [], | ||
|  | 			access: [APublic, AOverride], | ||
|  | 			kind: FFun({ | ||
|  | 				ret: null, | ||
|  | 				params: null, | ||
|  | 				expr: macro {}, | ||
|  | 				args: [ | ||
|  | 					{ | ||
|  | 						value: null, | ||
|  | 						type: Context.toComplexType(Context.getType("haxe.io.Bytes")), | ||
|  | 						opt: null, | ||
|  | 						name: "bytes" | ||
|  | 					} | ||
|  | 				] | ||
|  | 			}), | ||
|  | 			pos: Context.currentPos() | ||
|  | 		}); | ||
|  | 		#end | ||
|  | 
 | ||
|  | 		return fields; | ||
|  | 	} | ||
|  | } |