Forráskód Böngészése

review connection / alive / sync, started ownership

ncannasse 9 éve
szülő
commit
c68669c152
4 módosított fájl, 103 hozzáadás és 54 törlés
  1. 14 6
      hxd/net/LocalHost.hx
  2. 15 15
      hxd/net/Macros.hx
  3. 68 29
      hxd/net/NetworkHost.hx
  4. 6 4
      hxd/net/NetworkSerializable.hx

+ 14 - 6
hxd/net/LocalHost.hx

@@ -47,6 +47,14 @@ class LocalClient extends NetworkClient {
 		socket.out.flush();
 		socket.out.flush();
 	}
 	}
 
 
+	override function stop() {
+		super.stop();
+		if( socket != null ) {
+			socket.close();
+			socket = null;
+		}
+	}
+
 }
 }
 
 
 class LocalHost extends NetworkHost {
 class LocalHost extends NetworkHost {
@@ -68,7 +76,7 @@ class LocalHost extends NetworkHost {
 		connected = false;
 		connected = false;
 	}
 	}
 
 
-	public function connect( host : String, port : Int, onConnect : Bool -> Void ) {
+	public function connect( host : String, port : Int, ?onConnect : Bool -> Void ) {
 		close();
 		close();
 		isAuth = false;
 		isAuth = false;
 		socket = new Socket();
 		socket = new Socket();
@@ -79,23 +87,23 @@ class LocalHost extends NetworkHost {
 			} else
 			} else
 				throw msg;
 				throw msg;
 		};
 		};
-		var me = new LocalClient(this, socket);
+		self = new LocalClient(this, socket);
 		socket.connect(host, port, function() {
 		socket.connect(host, port, function() {
 			connected = true;
 			connected = true;
 			if( host == "127.0.0.1" ) enableSound = false;
 			if( host == "127.0.0.1" ) enableSound = false;
-			clients = [me];
+			clients = [self];
 			onConnect(true);
 			onConnect(true);
 		});
 		});
 	}
 	}
 
 
-	public function wait( host : String, port : Int, onClient : NetworkClient -> Void ) {
+	public function wait( host : String, port : Int, ?onConnected : NetworkClient -> Void ) {
 		close();
 		close();
 		isAuth = false;
 		isAuth = false;
 		socket = new Socket();
 		socket = new Socket();
 		socket.bind(host, port, function(s) {
 		socket.bind(host, port, function(s) {
 			var c = new LocalClient(this, s);
 			var c = new LocalClient(this, s);
-			clients.push(c);
-			onClient(c);
+			pendingClients.push(c);
+			if( onConnected != null ) onConnected(c);
 		});
 		});
 		isAuth = true;
 		isAuth = true;
 	}
 	}

+ 15 - 15
hxd/net/Macros.hx

@@ -41,6 +41,7 @@ enum PropTypeDesc {
 typedef PropType = {
 typedef PropType = {
 	var d : PropTypeDesc;
 	var d : PropTypeDesc;
 	var t : ComplexType;
 	var t : ComplexType;
+	@:optional var isProxy : Bool;
 	@:optional var isNull : Bool;
 	@:optional var isNull : Bool;
 	@:optional var increment : Float;
 	@:optional var increment : Float;
 }
 }
@@ -218,7 +219,7 @@ class Macros {
 
 
 	static function serializeExpr( ctx : Expr, v : Expr, t : PropType, skipCheck = false ) {
 	static function serializeExpr( ctx : Expr, v : Expr, t : PropType, skipCheck = false ) {
 
 
-		if( needProxy(t) && !skipCheck )
+		if( t.isProxy && !skipCheck )
 			return serializeExpr(ctx, { expr : EField(v, "__value"), pos : v.pos }, t, true);
 			return serializeExpr(ctx, { expr : EField(v, "__value"), pos : v.pos }, t, true);
 
 
 		if( t.isNull && !skipCheck ) {
 		if( t.isNull && !skipCheck ) {
@@ -614,7 +615,7 @@ class Macros {
 	}
 	}
 
 
 	static function toProxy( p : PropType ) {
 	static function toProxy( p : PropType ) {
-		if( !needProxy(p) )
+		if( !p.isProxy )
 			return p.t;
 			return p.t;
 		var pt = p.t;
 		var pt = p.t;
 		return macro : hxd.net.NetworkSerializable.Proxy<$pt>;
 		return macro : hxd.net.NetworkSerializable.Proxy<$pt>;
@@ -732,22 +733,25 @@ class Macros {
 				@:noCompletion public var __host : hxd.net.NetworkHost;
 				@:noCompletion public var __host : hxd.net.NetworkHost;
 				@:noCompletion public var __bits : Int = 0;
 				@:noCompletion public var __bits : Int = 0;
 				@:noCompletion public var __next : hxd.net.NetworkSerializable;
 				@:noCompletion public var __next : hxd.net.NetworkSerializable;
-				@:noCompletion public function setNetworkBit( b : Int ) {
-					if( __host != null ) {
-						if( __bits == 0 ) @:privateAccess __host.mark(this);
+				@:noCompletion public inline function networkSetBit( b : Int ) {
+					if( __host != null && (__bits != 0 || @:privateAccess __host.mark(this)) )
 						__bits |= 1 << b;
 						__bits |= 1 << b;
-					}
 				}
 				}
 				public var enableReplication(get, set) : Bool;
 				public var enableReplication(get, set) : Bool;
 				inline function get_enableReplication() return __host != null;
 				inline function get_enableReplication() return __host != null;
 				function set_enableReplication(b) {
 				function set_enableReplication(b) {
-					hxd.net.NetworkHost.enableReplication(this, b);
+					@:privateAccess hxd.net.NetworkHost.enableReplication(this, b);
 					return b;
 					return b;
 				}
 				}
 				public inline function networkCancelProperty( props : hxd.net.NetworkSerializable.Property ) {
 				public inline function networkCancelProperty( props : hxd.net.NetworkSerializable.Property ) {
 					__bits &= ~props.toInt();
 					__bits &= ~props.toInt();
 				}
 				}
 			}).fields);
 			}).fields);
+
+			if( !Lambda.exists(fields, function(f) return f.name == "networkGetOwner") )
+				fields = fields.concat((macro class {
+					public function networkGetOwner() : hxd.net.NetworkSerializable { return null; }
+				}).fields);
 		}
 		}
 
 
 		var flushExpr = [];
 		var flushExpr = [];
@@ -791,11 +795,7 @@ class Macros {
 				throw "assert";
 				throw "assert";
 			}
 			}
 
 
-			var markExpr = macro if( __host != null ) {
-				if( !__host.isAuth ) throw "Client can't set "+$v{fname};
-				if( this.__bits == 0 ) @:privateAccess __host.mark(this);
-				this.__bits |= 1 << $v{ bitID };
-			};
+			var markExpr = macro networkSetBit($v{ bitID });
 			markExpr = makeMarkExpr(fields, fname, ftype, markExpr);
 			markExpr = makeMarkExpr(fields, fname, ftype, markExpr);
 
 
 			var setExpr = macro
 			var setExpr = macro
@@ -894,7 +894,7 @@ class Macros {
 				}
 				}
 
 
 				var forwardRPC = macro {
 				var forwardRPC = macro {
-					var __ctx = __host.beginRPC(this,$v{id},$resultCall);
+					var __ctx = @:privateAccess __host.beginRPC(this,$v{id},$resultCall);
 					$b{[
 					$b{[
 						for( a in f.args )
 						for( a in f.args )
 							macro hxd.net.Macros.serializeValue(__ctx,$i{a.name})
 							macro hxd.net.Macros.serializeValue(__ctx,$i{a.name})
@@ -1073,8 +1073,8 @@ class Macros {
 					var bit : Int;
 					var bit : Int;
 					@:noCompletion public var __value(get, never) : $pt;
 					@:noCompletion public var __value(get, never) : $pt;
 					inline function get___value() : $pt return cast this;
 					inline function get___value() : $pt return cast this;
-					inline function mark() if( obj != null ) obj.setNetworkBit(bit);
-					@:noCompletion public function setNetworkBit(_) mark();
+					inline function mark() if( obj != null ) obj.networkSetBit(bit);
+					@:noCompletion public function networkSetBit(_) mark();
 					@:noCompletion public function bindHost(obj, bit) { this.obj = obj; this.bit = bit; }
 					@:noCompletion public function bindHost(obj, bit) { this.obj = obj; this.bit = bit; }
 					@:noCompletion public function unbindHost() this.obj = null;
 					@:noCompletion public function unbindHost() this.obj = null;
 				}).fields;
 				}).fields;

+ 68 - 29
hxd/net/NetworkHost.hx

@@ -4,29 +4,22 @@ class NetworkClient {
 
 
 	var host : NetworkHost;
 	var host : NetworkHost;
 	var resultID : Int;
 	var resultID : Int;
+	public var ownerObject : NetworkSerializable;
 
 
 	public function new(h) {
 	public function new(h) {
 		this.host = h;
 		this.host = h;
 	}
 	}
 
 
-	public function send(bytes : haxe.io.Bytes) {
+	public function sync() {
+		host.fullSync(this);
 	}
 	}
 
 
-	public function fullSync( obj : Serializable ) {
-		var ctx = host.ctx;
-		var refs = ctx.refs;
-		ctx.begin();
-		ctx.addByte(NetworkHost.FULLSYNC);
-		ctx.addAnyRef(obj);
-		for( o in refs )
-			if( o != null )
-				ctx.addAnyRef(o);
-		ctx.addAnyRef(null);
-		@:privateAccess {
-			var bytes = ctx.out.getBytes();
-			ctx.out = new haxe.io.BytesBuffer();
-			send(bytes);
-		}
+	@:allow(hxd.net.NetworkHost)
+	function send(bytes : haxe.io.Bytes) {
+	}
+
+	public function sendMessage( msg : Dynamic ) {
+		host.sendMessage(msg, this);
 	}
 	}
 
 
 	function error( msg : String ) {
 	function error( msg : String ) {
@@ -48,7 +41,7 @@ class NetworkClient {
 		case NetworkHost.REG:
 		case NetworkHost.REG:
 			var o : hxd.net.NetworkSerializable = cast ctx.getAnyRef();
 			var o : hxd.net.NetworkSerializable = cast ctx.getAnyRef();
 			o.__host = host;
 			o.__host = host;
-			if( host.isAlive ) host.makeAlive();
+			host.makeAlive();
 		case NetworkHost.UNREG:
 		case NetworkHost.UNREG:
 			var o : hxd.net.NetworkSerializable = cast ctx.refs[ctx.getInt()];
 			var o : hxd.net.NetworkSerializable = cast ctx.refs[ctx.getInt()];
 			o.enableReplication = false;
 			o.enableReplication = false;
@@ -56,12 +49,11 @@ class NetworkClient {
 		case NetworkHost.FULLSYNC:
 		case NetworkHost.FULLSYNC:
 			ctx.refs = [];
 			ctx.refs = [];
 			@:privateAccess ctx.newObjects = [];
 			@:privateAccess ctx.newObjects = [];
-			var obj = ctx.getAnyRef();
 			while( true ) {
 			while( true ) {
 				var o = ctx.getAnyRef();
 				var o = ctx.getAnyRef();
 				if( o == null ) break;
 				if( o == null ) break;
 			}
 			}
-			host.onSync(obj);
+			host.makeAlive();
 		case NetworkHost.RPC:
 		case NetworkHost.RPC:
 			var o : hxd.net.NetworkSerializable = cast ctx.refs[ctx.getInt()];
 			var o : hxd.net.NetworkSerializable = cast ctx.refs[ctx.getInt()];
 			var fid = ctx.getByte();
 			var fid = ctx.getByte();
@@ -97,6 +89,10 @@ class NetworkClient {
 			host.rpcWaits.remove(resultID);
 			host.rpcWaits.remove(resultID);
 			callb(ctx);
 			callb(ctx);
 
 
+		case NetworkHost.MSG:
+			var msg = haxe.Unserializer.run(ctx.getString());
+			host.onMessage(this, msg);
+
 		case x:
 		case x:
 			error("Unknown message code " + x);
 			error("Unknown message code " + x);
 		}
 		}
@@ -104,12 +100,20 @@ class NetworkClient {
 	}
 	}
 
 
 	function beginRPCResult() {
 	function beginRPCResult() {
-		var ctx = host.ctx;
 		host.flush();
 		host.flush();
+		var ctx = host.ctx;
 		host.hasData = true;
 		host.hasData = true;
 		host.targetClient = this;
 		host.targetClient = this;
 		ctx.addByte(NetworkHost.RPC_RESULT);
 		ctx.addByte(NetworkHost.RPC_RESULT);
 		ctx.addInt(resultID);
 		ctx.addInt(resultID);
+		// after that RPC will add result value then return
+	}
+
+	public function stop() {
+		if( host == null ) return;
+		host.clients.remove(this);
+		host.pendingClients.remove(this);
+		host = null;
 	}
 	}
 
 
 }
 }
@@ -124,6 +128,7 @@ class NetworkHost {
 	static inline var RPC 		= 5;
 	static inline var RPC 		= 5;
 	static inline var RPC_WITH_RESULT = 6;
 	static inline var RPC_WITH_RESULT = 6;
 	static inline var RPC_RESULT = 7;
 	static inline var RPC_RESULT = 7;
+	static inline var MSG		 = 8;
 
 
 	public static var current : NetworkHost = null;
 	public static var current : NetworkHost = null;
 
 
@@ -136,18 +141,20 @@ class NetworkHost {
 	var lastSentBytes = 0;
 	var lastSentBytes = 0;
 	var markHead : NetworkSerializable;
 	var markHead : NetworkSerializable;
 	var ctx : Serializer;
 	var ctx : Serializer;
+	var pendingClients : Array<NetworkClient>;
 	var clients : Array<NetworkClient>;
 	var clients : Array<NetworkClient>;
-	var isAlive = false;
 	var logger : String -> Void;
 	var logger : String -> Void;
 	var hasData = false;
 	var hasData = false;
 	var rpcUID = Std.random(0x1000000);
 	var rpcUID = Std.random(0x1000000);
 	var rpcWaits = new Map<Int,Serializer->Void>();
 	var rpcWaits = new Map<Int,Serializer->Void>();
 	var targetClient : NetworkClient;
 	var targetClient : NetworkClient;
+	public var self(default,null) : NetworkClient;
 
 
 	public function new() {
 	public function new() {
 		current = this;
 		current = this;
 		isAuth = true;
 		isAuth = true;
 		clients = [];
 		clients = [];
+		pendingClients = [];
 		ctx = new Serializer();
 		ctx = new Serializer();
 		@:privateAccess ctx.newObjects = [];
 		@:privateAccess ctx.newObjects = [];
 		ctx.begin();
 		ctx.begin();
@@ -164,12 +171,32 @@ class NetworkHost {
 		return ctx.getKnownRef(c);
 		return ctx.getKnownRef(c);
 	}
 	}
 
 
-	inline function mark(o:NetworkSerializable) {
+	function mark(o:NetworkSerializable) {
+		if( !isAuth ) {
+			var owner = o.networkGetOwner();
+			if( owner == null || clients[0].ownerObject != owner )
+				throw "Client can't set property on " + o + " without ownership ("+owner + " should be "+clients[0].ownerObject+")";
+			// allow to modify the property localy but don't send it to server
+			return false;
+		}
 		o.__next = markHead;
 		o.__next = markHead;
 		markHead = o;
 		markHead = o;
+		return true;
+	}
+
+	public dynamic function onMessage( from : NetworkClient, msg : Dynamic ) {
+	}
+
+	public function sendMessage( msg : Dynamic, ?to : NetworkClient ) {
+		flush();
+		targetClient = to;
+		ctx.addByte(MSG);
+		ctx.addString(haxe.Serializer.run(msg));
+		doSend();
+		targetClient = null;
 	}
 	}
 
 
-	public function beginRPC(o:NetworkSerializable, id:Int, onResult:Serializer->Void) {
+	function beginRPC(o:NetworkSerializable, id:Int, onResult:Serializer->Void) {
 		flushProps();
 		flushProps();
 		hasData = true;
 		hasData = true;
 		if( ctx.refs[o.__uid] == null )
 		if( ctx.refs[o.__uid] == null )
@@ -188,6 +215,23 @@ class NetworkHost {
 		return ctx;
 		return ctx;
 	}
 	}
 
 
+	function fullSync( c : NetworkClient ) {
+		if( !pendingClients.remove(c) )
+			return;
+		flush();
+		clients.push(c);
+		var refs = ctx.refs;
+		ctx.begin();
+		ctx.addByte(NetworkHost.FULLSYNC);
+		for( o in refs )
+			if( o != null )
+				ctx.addAnyRef(o);
+		ctx.addAnyRef(null);
+		targetClient = c;
+		doSend();
+		targetClient = null;
+	}
+
 	public function defaultLogger( ?filter : String -> Bool ) {
 	public function defaultLogger( ?filter : String -> Bool ) {
 		setLogger(function(str) {
 		setLogger(function(str) {
 			if( filter != null && !filter(str) ) return;
 			if( filter != null && !filter(str) ) return;
@@ -198,7 +242,6 @@ class NetworkHost {
 	}
 	}
 
 
 	public function makeAlive() {
 	public function makeAlive() {
-		isAlive = true;
 		var objs = @:privateAccess ctx.newObjects;
 		var objs = @:privateAccess ctx.newObjects;
 		if( objs.length == 0 )
 		if( objs.length == 0 )
 			return;
 			return;
@@ -259,10 +302,6 @@ class NetworkHost {
 		}
 		}
 	}
 	}
 
 
-	public dynamic function onSync( obj : Serializable ) {
-		trace("SYNC " + obj);
-	}
-
 	function flushProps() {
 	function flushProps() {
 		var o = markHead;
 		var o = markHead;
 		while( o != null ) {
 		while( o != null ) {
@@ -296,7 +335,7 @@ class NetworkHost {
 		lastSentBytes = totalSentBytes;
 		lastSentBytes = totalSentBytes;
 	}
 	}
 
 
-	public static function enableReplication( o : NetworkSerializable, b : Bool ) {
+	static function enableReplication( o : NetworkSerializable, b : Bool ) {
 		if( b ) {
 		if( b ) {
 			if( o.__host != null ) return;
 			if( o.__host != null ) return;
 			if( current == null ) throw "No NetworkHost defined";
 			if( current == null ) throw "No NetworkHost defined";

+ 6 - 4
hxd/net/NetworkSerializable.hx

@@ -1,7 +1,7 @@
 package hxd.net;
 package hxd.net;
 
 
 interface ProxyHost {
 interface ProxyHost {
-	public function setNetworkBit( bit : Int ) : Void;
+	public function networkSetBit( bit : Int ) : Void;
 }
 }
 
 
 interface ProxyChild {
 interface ProxyChild {
@@ -15,10 +15,12 @@ interface NetworkSerializable extends Serializable extends ProxyHost {
 	public var __bits : Int;
 	public var __bits : Int;
 	public var __next : NetworkSerializable;
 	public var __next : NetworkSerializable;
 	public var enableReplication(get, set) : Bool;
 	public var enableReplication(get, set) : Bool;
+	public function alive() : Void; // user defined
+
 	public function networkFlush( ctx : Serializer ) : Void;
 	public function networkFlush( ctx : Serializer ) : Void;
 	public function networkSync( ctx : Serializer ) : Void;
 	public function networkSync( ctx : Serializer ) : Void;
 	public function networkRPC( ctx : Serializer, rpcID : Int, clientResult : NetworkHost.NetworkClient ) : Void;
 	public function networkRPC( ctx : Serializer, rpcID : Int, clientResult : NetworkHost.NetworkClient ) : Void;
-	public function alive() : Void;
+	public function networkGetOwner() : NetworkSerializable;
 }
 }
 
 
 @:genericBuild(hxd.net.Macros.buildSerializableProxy())
 @:genericBuild(hxd.net.Macros.buildSerializableProxy())
@@ -28,11 +30,11 @@ class Proxy<T> {
 class BaseProxy implements ProxyHost implements ProxyChild {
 class BaseProxy implements ProxyHost implements ProxyChild {
 	public var obj : ProxyHost;
 	public var obj : ProxyHost;
 	public var bit : Int;
 	public var bit : Int;
-	public inline function setNetworkBit(_) {
+	public inline function networkSetBit(_) {
 		mark();
 		mark();
 	}
 	}
 	public inline function mark() {
 	public inline function mark() {
-		if( obj != null ) obj.setNetworkBit(bit);
+		if( obj != null ) obj.networkSetBit(bit);
 	}
 	}
 	public inline function bindHost(o, bit) {
 	public inline function bindHost(o, bit) {
 		this.obj = o;
 		this.obj = o;