Skip to content

Commit

Permalink
Merge pull request #29 from colyseus/0.13.0
Browse files Browse the repository at this point in the history
0.13.0
  • Loading branch information
endel authored Apr 22, 2020
2 parents 15f124d + 91071a6 commit 4f77d49
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 67 deletions.
22 changes: 13 additions & 9 deletions example/openfl/Source/Main.hx
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,16 @@ class Main extends Sprite {
trace("STATE CHANGE: " + Std.string(state));
};

this.room.onMessage += function(message) {
trace("ROOM MESSAGE: " + Std.string(message));
};
this.room.onMessage(0, function(message) {
trace("onMessage: 0 => " + message);
});

this.room.onMessage("type", function(message) {
trace("onMessage: 'type' => " + message);
});

this.room.onError += function(message) {
trace("ROOM ERROR: " + message);
this.room.onError += function(code: Int, message: String) {
trace("ROOM ERROR: " + code + " => " + message);
};

this.room.onLeave += function() {
Expand All @@ -96,13 +100,13 @@ class Main extends Sprite {

private function onKeyDown(evt:KeyboardEvent):Void {
if (evt.keyCode == Keyboard.UP) {
this.room.send({y: -1});
this.room.send("move", {y: -1});
} else if (evt.keyCode == Keyboard.DOWN) {
this.room.send({y: 1});
this.room.send("move", {y: 1});
} else if (evt.keyCode == Keyboard.LEFT) {
this.room.send({x: -1});
this.room.send("move", {x: -1});
} else if (evt.keyCode == Keyboard.RIGHT) {
this.room.send({x: 1});
this.room.send("move", {x: 1});
}
}

Expand Down
6 changes: 3 additions & 3 deletions haxelib.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
"license": "MIT",
"tags": ["multiplayer", "networking", "websockets", "netcode"],
"description": "Multiplayer Game Client for Haxe",
"version": "0.12.5",
"version": "0.13.0",
"classPath": "src/",
"releasenote": "Support for version 0.12",
"releasenote": "Support for version 0.13",
"contributors": ["endel"],
"dependencies": {
"colyseus-websocket": "1.0.6"
"colyseus-websocket": "1.0.7"
}
}
29 changes: 16 additions & 13 deletions src/io/colyseus/Client.hx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.colyseus;
import haxe.Constraints.Function;

using io.colyseus.events.EventHandler;
using io.colyseus.error.MatchMakeError;

import haxe.io.Bytes;
import org.msgpack.MsgPack;
Expand Down Expand Up @@ -31,43 +32,43 @@ class Client {
}

@:generic
public function joinOrCreate<T>(roomName: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (String, Room<T>)->Void) {
public function joinOrCreate<T>(roomName: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (MatchMakeError, Room<T>)->Void) {
this.createMatchMakeRequest('joinOrCreate', roomName, options, stateClass, callback);
}

@:generic
public function create<T>(roomName: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (String, Room<T>)->Void) {
public function create<T>(roomName: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (MatchMakeError, Room<T>)->Void) {
this.createMatchMakeRequest('create', roomName, options, stateClass, callback);
}

@:generic
public function join<T>(roomName: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (String, Room<T>)->Void) {
public function join<T>(roomName: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (MatchMakeError, Room<T>)->Void) {
this.createMatchMakeRequest('join', roomName, options, stateClass, callback);
}

@:generic
public function joinById<T>(roomId: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (String, Room<T>)->Void) {
public function joinById<T>(roomId: String, options: Map<String, Dynamic>, stateClass: Class<T>, callback: (MatchMakeError, Room<T>)->Void) {
this.createMatchMakeRequest('joinById', roomId, options, stateClass, callback);
}

@:generic
public function reconnect<T>(roomId: String, sessionId: String, stateClass: Class<T>, callback: (String, Room<T>)->Void) {
public function reconnect<T>(roomId: String, sessionId: String, stateClass: Class<T>, callback: (MatchMakeError, Room<T>)->Void) {
this.createMatchMakeRequest('joinById', roomId, [ "sessionId" => sessionId ], stateClass, callback);
}

public function getAvailableRooms(roomName: String, callback: (String, Array<RoomAvailable>)->Void) {
public function getAvailableRooms(roomName: String, callback: (MatchMakeError, Array<RoomAvailable>)->Void) {
this.request("GET", "/matchmake/" + roomName, null, callback);
}

@:generic
public function consumeSeatReservation<T>(response: Dynamic, stateClass: Class<T>, callback: (String, Room<T>)->Void) {
public function consumeSeatReservation<T>(response: Dynamic, stateClass: Class<T>, callback: (MatchMakeError, Room<T>)->Void) {
var room: Room<T> = new Room<T>(response.room.name, stateClass);

room.id = response.room.roomId;
room.sessionId = response.sessionId;

var onError = function(message) {
callback(message, null);
var onError = function(code: Int, message: String) {
callback(new MatchMakeError(code, message), null);
};
var onJoin = function() {
room.onError -= onError;
Expand All @@ -86,7 +87,7 @@ class Client {
roomName: String,
options: Map<String, Dynamic>,
stateClass: Class<T>,
callback: (String, Room<T>)->Void
callback: (MatchMakeError, Room<T>)->Void
) {
if (this.auth.hasToken()) {
options.set("token", this.auth.token);
Expand All @@ -113,7 +114,7 @@ class Client {
return new Connection(this.endpoint + "/" + path + "?" + params.join('&'));
}

private function request(method: String, segments: String, body: String, callback: (String,Dynamic)->Void) {
private function request(method: String, segments: String, body: String, callback: (MatchMakeError,Dynamic)->Void) {
var req = new haxe.Http("http" + this.endpoint.substring(2) + segments);

if (body != null) {
Expand All @@ -132,15 +133,17 @@ class Client {
var response = haxe.Json.parse(json);

if (response.error) {
callback(cast response.error, null);
var code = cast response.code;
var message = cast response.error;
callback(new MatchMakeError(code, message), null);

} else {
callback(null, response);
}
};

req.onError = function(err) {
callback(err, null);
callback(new MatchMakeError(0, err), null);
};

req.request(method == "POST");
Expand Down
19 changes: 2 additions & 17 deletions src/io/colyseus/Connection.hx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class Connection {
public var reconnectionEnabled: Bool = false;

private var ws: WebSocket;
private var _enqueuedSend: Array<Dynamic> = [];

// callbacks
public dynamic function onOpen():Void {}
Expand All @@ -36,13 +35,6 @@ class Connection {
this.ws = WebSocket.create(url);
this.ws.onopen = function() {
this.onOpen();

for (i in 0...this._enqueuedSend.length) {
this.send(this._enqueuedSend[i]);
}

// reset enqueued calls
this._enqueuedSend = [];
}

this.ws.onmessageBytes = function(bytes) {
Expand Down Expand Up @@ -73,15 +65,8 @@ class Connection {
#end
}

public function send(data: Dynamic) {
if (this.ws.readyState == ReadyState.Open) {
return this.ws.sendBytes( MsgPack.encode(data) );

} else {
// WebSocket not connected.
// Enqueue data to be sent when readyState == OPEN
this._enqueuedSend.push(data);
}
public function send(data: Bytes) {
return this.ws.sendBytes(data);
}

public function close () {
Expand Down
2 changes: 1 addition & 1 deletion src/io/colyseus/Protocol.hx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Protocol {
// Room-related (9~19)
public static var JOIN_REQUEST = 9;
public static var JOIN_ROOM = 10;
public static var JOIN_ERROR = 11;
public static var ERROR = 11;
public static var LEAVE_ROOM = 12;
public static var ROOM_DATA = 13;
public static var ROOM_STATE = 14;
Expand Down
110 changes: 88 additions & 22 deletions src/io/colyseus/Room.hx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package io.colyseus;

import haxe.io.BytesOutput;
import io.colyseus.serializer.schema.Schema;
import io.colyseus.serializer.Serializer;
import io.colyseus.serializer.SchemaSerializer;

import io.colyseus.serializer.schema.Schema.It;
import io.colyseus.serializer.schema.Schema.SPEC;

using io.colyseus.events.EventHandler;

import haxe.io.Bytes;
import haxe.ds.Map;
import org.msgpack.MsgPack;

class Room<T> {
Expand All @@ -17,9 +23,9 @@ class Room<T> {
// callbacks
public var onJoin = new EventHandler<Void->Void>();
public var onStateChange = new EventHandler<Dynamic->Void>();
public var onMessage = new EventHandler<Dynamic->Void>();
public var onError = new EventHandler<String->Void>();
public var onError = new EventHandler<Int->String->Void>();
public var onLeave = new EventHandler<Void->Void>();
private var onMessageHandlers = new Map<String, Dynamic->Void>();

public var connection: Connection;

Expand Down Expand Up @@ -48,7 +54,7 @@ class Room<T> {
}

this.connection.onError = function (e) {
this.onError.dispatch(e);
this.onError.dispatch(0, e);
};
}

Expand All @@ -57,7 +63,9 @@ class Room<T> {

if (this.connection != null) {
if (consented) {
this.connection.send([ Protocol.LEAVE_ROOM ]);
var bytes = new BytesOutput();
bytes.writeByte(Protocol.LEAVE_ROOM);
this.connection.send(bytes.getBytes());

} else {
this.connection.close();
Expand All @@ -68,10 +76,30 @@ class Room<T> {
}
}

public function send(data: Dynamic) {
if (this.connection != null) {
this.connection.send([ Protocol.ROOM_DATA, data ]);
public function send(type: Dynamic, ?message: Dynamic) {
var bytesToSend = new BytesOutput();
bytesToSend.writeByte(Protocol.ROOM_DATA);

if (Std.is(type, String)) {
var encodedType = Bytes.ofString(type);
bytesToSend.writeByte(encodedType.length | 0xa0);
bytesToSend.writeBytes(encodedType, 0, encodedType.length);

} else {
bytesToSend.writeByte(type);
}

if (message != null) {
var encodedMessage = MsgPack.encode(message);
bytesToSend.writeBytes(encodedMessage, 0, encodedMessage.length);
}

this.connection.send(bytesToSend.getBytes());
}

public function onMessage(type: Dynamic, callback: Dynamic->Void) {
this.onMessageHandlers[this.getMessageHandlerKey(type)] = callback;
return this;
}

public var state (get, null): T;
Expand All @@ -93,48 +121,58 @@ class Room<T> {

private function onMessageCallback(data: Bytes) {
var code = data.get(0);
var it:It = {offset: 1};

if (code == Protocol.JOIN_ROOM) {
var offset: Int = 1;

this.serializerId = data.getString(offset + 1, data.get(offset));
offset += this.serializerId.length + 1;
this.serializerId = data.getString(it.offset + 1, data.get(it.offset));
it.offset += this.serializerId.length + 1;

if (this.serializerId == "schema") {
this.serializer = new SchemaSerializer<T>(tmpStateClass);
} else {
throw "FossilDelta serializer has been deprecated! Use SchemaSerializer instead.";
}

if (data.length > offset) {
this.serializer.handshake(data, offset);
if (data.length > it.offset) {
this.serializer.handshake(data, it.offset);
}

this.onJoin.dispatch();

// acknowledge JOIN_ROOM
this.connection.send([ Protocol.JOIN_ROOM ]);
var bytes = new BytesOutput();
bytes.writeByte(Protocol.JOIN_ROOM);
this.connection.send(bytes.getBytes());

} else if (code == Protocol.JOIN_ERROR) {
var err = data.getString(2, data.get(1));
trace("Error: " + err);
this.onError.dispatch(err);
} else if (code == Protocol.ERROR) {
var errorCode: Int = Schema.decoder.number(data, it);
var message = Schema.decoder.string(data, it);
trace("Room error: code => " + errorCode + ", message => " + message);
this.onError.dispatch(errorCode, message);

} else if (code == Protocol.LEAVE_ROOM) {
this.leave();

} else if (code == Protocol.ROOM_STATE) {
this.setState(data.sub(1, data.length - 1));
this.setState(data.sub(it.offset, data.length - 1));

} else if (code == Protocol.ROOM_STATE_PATCH) {
this.patch(data.sub(1, data.length - 1));
this.patch(data.sub(it.offset, data.length - 1));

} else if (code == Protocol.ROOM_DATA) {
this.onMessage.dispatch(MsgPack.decode(data.sub(1, data.length - 1)));
var type = (SPEC.stringCheck(data, it))
? Schema.decoder.string(data, it)
: Schema.decoder.number(data, it);

var message = (data.length > it.offset)
? MsgPack.decode(data.sub(it.offset, data.length - it.offset))
: null;

this.dispatchMessage(type, message);
}
}

public function setState(encodedState: Bytes) {
private function setState(encodedState: Bytes) {
this.serializer.setState(encodedState);
this.onStateChange.dispatch(this.serializer.getState());
}
Expand All @@ -143,4 +181,32 @@ class Room<T> {
this.serializer.patch(binaryPatch);
this.onStateChange.dispatch(this.serializer.getState());
}

private function dispatchMessage(type: Dynamic, message: Dynamic) {
var messageType = this.getMessageHandlerKey(type);

if (this.onMessageHandlers.get(messageType) != null) {
this.onMessageHandlers.get(messageType)(message);

// } else if (this.onMessageHandlers['*'] != null) {
// this.onMessageHandlers.get(messageType)(type, message);

} else {
trace("onMessage not registered for type " + type);
}

}

private function getMessageHandlerKey(type: Dynamic): String {
if (Std.is(type, String)) {
return type;

} else if (Std.is(type, Int)) {
return "i" + type;

} else {
return "$" + Type.getClassName(Type.getClass(type));
}
}

}
Loading

0 comments on commit 4f77d49

Please sign in to comment.