瀏覽代碼

Add NodeJS support (#928)

Quentin Dreyer 4 年之前
父節點
當前提交
ddfa6e2eb1
共有 5 個文件被更改,包括 156 次插入16 次删除
  1. 5 1
      h3d/Engine.hx
  2. 5 1
      hxd/Pad.hx
  3. 16 9
      hxd/System.js.hx
  4. 8 1
      hxd/Window.js.hx
  5. 122 4
      hxd/net/Socket.hx

+ 5 - 1
h3d/Engine.hx

@@ -75,7 +75,11 @@ class Engine {
 			driver = new h3d.impl.VulkanDriver();
 		else
 		#end
+		#if js
+		driver = js.Browser.supported ? new h3d.impl.GlDriver(antiAlias) : new h3d.impl.NullDriver();
+		#else
 		driver = new h3d.impl.GlDriver(antiAlias);
+		#end
 		#elseif flash
 		driver = new h3d.impl.Stage3dDriver(antiAlias);
 		#elseif hldx
@@ -429,4 +433,4 @@ class Engine {
 		return Math.ceil(realFps * 100) / 100;
 	}
 
-}
+}

+ 5 - 1
hxd/Pad.hx

@@ -312,6 +312,10 @@ class Pad {
 		Wait until a gamepad gets connected. On some platforms, this might require the user to press a button until it activates
 	**/
 	public static function wait( onPad : Pad -> Void ) {
+		#if js
+		if( !js.Browser.supported )
+			return;
+		#end
 		waitPad = onPad;
 		#if flash
 		if( !initDone ) {
@@ -590,4 +594,4 @@ class Pad {
 
 	#end
 
-}
+}

+ 16 - 9
hxd/System.js.hx

@@ -51,15 +51,22 @@ class System {
 	}
 
 	static function browserLoop() {
-		var window : Dynamic = js.Browser.window;
-		var rqf : Dynamic = window.requestAnimationFrame ||
-			window.webkitRequestAnimationFrame ||
-			window.mozRequestAnimationFrame;
-		if( fpsLimit>0 )
-			js.Browser.window.setTimeout( ()->rqf(browserLoop), 1000/fpsLimit );
-		else
-			rqf(browserLoop);
-
+		if( js.Browser.supported ) {
+			var window : Dynamic = js.Browser.window;
+			var rqf : Dynamic = window.requestAnimationFrame ||
+				window.webkitRequestAnimationFrame ||
+				window.mozRequestAnimationFrame;
+			if( fpsLimit>0 )
+				js.Browser.window.setTimeout( ()->rqf(browserLoop), 1000/fpsLimit );
+			else
+				rqf(browserLoop);
+		} else {
+			#if (nodejs && hxnodejs)
+			js.node.Timers.setTimeout(browserLoop, 0);
+			#else
+			throw "Cannot use browserLoop without Browser support nor defining nodejs + hxnodejs";
+			#end
+		}
 		if( loopFunc != null ) loopFunc();
 	}
 

+ 8 - 1
hxd/Window.js.hx

@@ -41,12 +41,17 @@ class Window {
 		When enabled, the browser zoom does not affect the canvas.
 		(default : true)
 	**/
-	public var useScreenPixels : Bool = true;
+	public var useScreenPixels : Bool = js.Browser.supported;
 
 	public function new( ?canvas : js.html.CanvasElement, ?globalEvents ) : Void {
 		var customCanvas = canvas != null;
 		eventTargets = new List();
 		resizeEvents = new List();
+		
+		if( !js.Browser.supported ) {
+			canvasPos = { "width":0, "top":0, "left":0, "height":0 };
+			return;
+		}
 
 		if( canvas == null ) {
 			canvas = cast js.Browser.document.getElementById("webgl");
@@ -355,6 +360,8 @@ class Window {
 	}
 
 	function set_displayMode( m : DisplayMode ) : DisplayMode {
+		if( !js.Browser.supported )
+			return m;
 		var doc = js.Browser.document;
 		var elt : Dynamic = doc.documentElement;
 		var fullscreen = m != Windowed;

+ 122 - 4
hxd/net/Socket.hx

@@ -35,13 +35,14 @@ class Socket {
 	static var openedSocks = [];
 	#if flash
 	var s : flash.net.Socket;
+	#elseif hl
+	var s : #if (haxe_ver >= 4) hl.uv.Stream #else Dynamic #end;
+	#elseif (nodejs && hxnodejs)
+	var s : js.node.net.Socket;
 	#end
 	#if (flash && air3)
 	var serv : flash.net.ServerSocket;
 	#end
-	#if hl
-	var s : #if (haxe_ver >= 4) hl.uv.Stream #else Dynamic #end;
-	#end
 	public var out(default, null) : SocketOutput;
 	public var input(default, null) : SocketInput;
 	public var timeout(default, set) : Null<Float>;
@@ -149,6 +150,18 @@ class Socket {
 			close();
 			throw e;
 		}
+		#elseif (nodejs && hxnodejs)
+		js.node.Net.createServer(function(sock) {
+			var s = new Socket();
+			s.s = sock;
+			s.out = new NodeSocketOutput(s);
+			s.input = new NodeSocketInput(s);
+			openedSocks.push(s);
+			onConnect(s);
+		}).on('error', function(e) {
+			close();
+			throw e;
+		}).listen(port, host, listenCount);
 		#else
 		throw "Not implemented";
 		#end
@@ -168,6 +181,12 @@ class Socket {
 			out = new SocketOutput();
 			s = null;
 		}
+		#elseif (nodejs && hxnodejs)
+		if( s != null ) {
+			s.destroy();
+			out = new SocketOutput();
+			s = null;
+		}
 		#end
 	}
 
@@ -354,4 +373,103 @@ class HLSocketInput extends SocketInput {
 
 }
 
-#end
+#elseif (nodejs && hxnodejs)
+
+class NodeSocketOutput extends SocketOutput {
+
+	var tmpBuf : js.node.Buffer;
+	var s : Socket;
+
+	public function new(s) {
+		super();
+		this.s = s;
+		@:privateAccess s.s.on('error', () -> writeResult(false));
+		@:privateAccess s.s.on('end', () -> s.close());
+	}
+
+	function writeResult(b) {
+		if( !b ) {
+			s.close();
+			s.onError("Failed to write data");
+		}
+	}
+
+	override function writeByte(c:Int) {
+		if( tmpBuf == null )
+			tmpBuf = js.node.Buffer.alloc(1);
+		tmpBuf.fill(c);
+		@:privateAccess s.s.write(tmpBuf);
+	}
+
+	override function writeBytes(buf:haxe.io.Bytes, pos:Int, len:Int):Int {
+		@:privateAccess s.s.write(buf.sub(pos, len).b);
+		return len;
+	}
+
+}
+
+class NodeSocketInput extends SocketInput {
+
+	var s : Socket;
+	var data : js.node.Buffer;
+	var pos : Int = 0;
+	var len : Int = 0;
+	var size : Int = 0;
+
+	public function new(sock) {
+		this.s = sock;
+		@:privateAccess s.s.on('data', buf -> onData(buf, buf.length));
+		@:privateAccess s.s.on('end', () -> onData(js.node.Buffer.from([]), -4095));
+	}
+
+	function onData(buf:js.node.Buffer, recv:Int) {
+		if( recv < 0 ) {
+			s.close();
+			s.onError("Connection closed");
+			return;
+		}
+		if (data == null)
+			data = js.node.Buffer.alloc(len - pos);
+		var req = pos + len + recv;
+		if( req > size && pos >= (size >> 1) ) {
+			data.copy(data, 0, pos, pos+len);
+			pos = 0;
+			req -= pos;
+		}
+		if( req > size ) {
+			var nsize = size == 0 ? 1024 : size;
+			while( nsize < req ) nsize = (nsize * 3) >> 1;
+			var ndata = js.node.Buffer.alloc(nsize);
+			data.copy(ndata, 0, pos, pos+len);
+			data = ndata;
+			size = nsize;
+			pos = 0;
+		}
+		buf.copy(data, pos + len, 0, recv);
+		len += recv;
+		s.onData();
+	}
+
+	override function get_available() {
+		return len;
+	}
+
+	override function readByte():Int {
+		if( len == 0) throw new haxe.io.Eof();
+		var c = data[pos++];
+		len--;
+		return c;
+	}
+
+	override function readBytes(s:haxe.io.Bytes, pos:Int, len:Int):Int {
+		if( pos < 0 || len < 0  || pos + len > s.length ) throw haxe.io.Error.OutsideBounds;
+		var max = len < this.len ? len : this.len;
+		data.copy(@:privateAccess s.b, pos, this.pos, this.pos+max);
+		this.pos += max;
+		this.len -= max;
+		return max;
+	}
+
+}
+
+#end