[client] update proto

This commit is contained in:
2018-02-28 22:06:00 +03:00
parent 336896b37e
commit 34e5ac2b9e
10 changed files with 249 additions and 343 deletions

View File

@@ -1,8 +1,12 @@
package ru.m.tankz; package ru.m.tankz;
import flash.events.KeyboardEvent; import openfl.Assets;
import flash.text.Font; import ru.m.tankz.frame.StartFrame;
import flash.ui.Keyboard; import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
import ru.m.tankz.proto.pack.Response;
import ru.m.tankz.proto.pack.Request;
import flash.text.Font;
import haxework.gui.frame.IFrameSwitcher; import haxework.gui.frame.IFrameSwitcher;
import haxework.gui.Root; import haxework.gui.Root;
import haxework.gui.VGroupView; import haxework.gui.VGroupView;
@@ -11,10 +15,7 @@ import haxework.log.TraceLogger;
import haxework.provider.Provider; import haxework.provider.Provider;
import haxework.resources.IResources; import haxework.resources.IResources;
import haxework.resources.Resources; import haxework.resources.Resources;
import openfl.Assets;
import ru.m.connect.IConnection; import ru.m.connect.IConnection;
import ru.m.tankz.frame.StartFrame;
import ru.m.tankz.PacketBuilder;
#if flash import haxework.log.JSLogger; #end #if flash import haxework.log.JSLogger; #end
#if debug import haxework.log.SocketLogger; #end #if debug import haxework.log.SocketLogger; #end
@@ -23,9 +24,7 @@ interface ClientLayout {
var switcher(default, null):IFrameSwitcher; var switcher(default, null):IFrameSwitcher;
} }
@:template('ru/m/tankz/Client.yaml', 'ru/m/tankz/Style.yaml') class Client {
class Client extends VGroupView implements ClientLayout implements ViewBuilder {
private static inline var TAG = 'Tankz'; private static inline var TAG = 'Tankz';
public static function main() { public static function main() {
@@ -41,29 +40,35 @@ class Client extends VGroupView implements ClientLayout implements ViewBuilder {
L.d(TAG, 'Debug: ${Const.DEBUG}'); L.d(TAG, 'Debug: ${Const.DEBUG}');
L.i(TAG, 'Version: ${Const.VERSION}'); L.i(TAG, 'Version: ${Const.VERSION}');
L.i(TAG, 'Build: ${Const.BUILD}'); L.i(TAG, 'Build: ${Const.BUILD}');
var client:Client = new Client(); var view:ClientView = new ClientView();
Root.bind(client); Root.bind(view);
view.launch();
} }
public function init() { }
Provider.setFactory(IResources, Resources);
@:template('ru/m/tankz/Client.yaml', 'ru/m/tankz/Style.yaml')
class ClientView extends VGroupView implements ClientLayout implements ViewBuilder {
private static inline var TAG = 'Tankz';
public function init():Void {
var font:Font = Font.enumerateFonts()[0]; var font:Font = Font.enumerateFonts()[0];
Provider.get(IResources).text.put('font', 'Bookman Old Style'); Provider.get(IResources).text.put('font', 'Bookman Old Style');
Provider.get(IResources).text.put('version', 'v${Const.VERSION} b${Const.BUILD}'); Provider.get(IResources).text.put('version', 'v${Const.VERSION} b${Const.BUILD}');
Provider.set(IPacketBuilder, new PacketBuilder());
#if flash #if flash
Provider.set(IConnection, new ru.m.connect.flash.FlashConnection('localhost', 5001)); Provider.set(IConnection, new ru.m.connect.flash.FlashConnection<Request, Response>('localhost', 5001, Response));
#elseif html5 #elseif html5
Provider.set(IConnection, new ru.m.connect.js.JsConnection('localhost', 5001)); Provider.set(IConnection, new ru.m.connect.js.JsConnection('localhost', 5001));
#else #else
Provider.set(IConnection, new ru.m.connect.fake.FakeConnection()); Provider.set(IConnection, new ru.m.connect.fake.FakeConnection());
#end #end
Provider.get(IConnection).handler.addListener(this);
Provider.set(IFrameSwitcher, switcher); Provider.set(IFrameSwitcher, switcher);
}
public function launch():Void {
content.stage.stageFocusRect = false; content.stage.stageFocusRect = false;
content.stage.addEventListener(KeyboardEvent.KEY_UP, function(event:KeyboardEvent):Void { content.stage.addEventListener(KeyboardEvent.KEY_UP, function(event:KeyboardEvent):Void {

View File

@@ -1,8 +1,8 @@
package ru.m.tankz; package ru.m.tankz;
import haxework.provider.Provider; import haxework.provider.Provider;
import ru.m.tankz.bundle.ConfigBundle; import haxework.resources.IResources;
import ru.m.tankz.bundle.IConfigBundle; import haxework.resources.Resources;
import ru.m.tankz.bundle.ILevelBundle; import ru.m.tankz.bundle.ILevelBundle;
import ru.m.tankz.bundle.LevelBundle; import ru.m.tankz.bundle.LevelBundle;
import ru.m.tankz.game.ClassicGame; import ru.m.tankz.game.ClassicGame;
@@ -17,7 +17,8 @@ import ru.m.tankz.storage.UserStorage;
class Init { class Init {
public static function init():Void { public static function init():Void {
Provider.setFactory(IConfigBundle, ConfigBundle); Provider.setFactory(IResources, Resources);
Provider.setFactory(ILevelBundle, LevelBundle);
Provider.setFactory(ILevelBundle, LevelBundle); Provider.setFactory(ILevelBundle, LevelBundle);
Provider.setFactory(SaveStorage, SaveStorage); Provider.setFactory(SaveStorage, SaveStorage);
Provider.setFactory(UserStorage, UserStorage); Provider.setFactory(UserStorage, UserStorage);

View File

@@ -1,6 +1,5 @@
package ru.m.tankz.frame; package ru.m.tankz.frame;
import ru.m.tankz.sound.SoundManager;
import flash.events.Event; import flash.events.Event;
import haxe.ds.Option; import haxe.ds.Option;
import haxe.Timer; import haxe.Timer;
@@ -9,13 +8,11 @@ import haxework.gui.LabelView;
import haxework.gui.VGroupView; import haxework.gui.VGroupView;
import haxework.gui.ViewBuilder; import haxework.gui.ViewBuilder;
import haxework.provider.Provider; import haxework.provider.Provider;
import protohx.Message;
import ru.m.connect.IConnection;
import ru.m.tankz.game.Game; import ru.m.tankz.game.Game;
import ru.m.tankz.game.GameSave; import ru.m.tankz.game.GameSave;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
import ru.m.tankz.proto.pack.GameUpdateResponse;
import ru.m.tankz.render.Render; import ru.m.tankz.render.Render;
import ru.m.tankz.sound.SoundManager;
import ru.m.tankz.storage.SaveStorage; import ru.m.tankz.storage.SaveStorage;
@@ -25,7 +22,7 @@ interface GameFrameLayout {
} }
@:template("ru/m/tankz/frame/GameFrame.yaml", "ru/m/tankz/Style.yaml") @:template("ru/m/tankz/frame/GameFrame.yaml", "ru/m/tankz/Style.yaml")
class GameFrame extends VGroupView implements ViewBuilder implements IPacketHandler implements GameFrameLayout { class GameFrame extends VGroupView implements ViewBuilder implements GameFrameLayout {
private static inline var TAG = "GameFrame"; private static inline var TAG = "GameFrame";
@@ -126,11 +123,4 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
private function redraw(_):Void { private function redraw(_):Void {
render.draw(game.engine); render.draw(game.engine);
} }
public function onGameUpdateResponse(packet:GameUpdateResponse):Void {
//engine.updateFromChanges(packet.changes);
render.draw(game.engine);
}
public function onPacket(packet:Message):Void {}
} }

View File

@@ -2,23 +2,25 @@ package ru.m.tankz.network;
import haxework.provider.Provider; import haxework.provider.Provider;
import hxsignal.impl.Signal1; import hxsignal.impl.Signal1;
import protohx.Message;
import ru.m.connect.IConnection; import ru.m.connect.IConnection;
import ru.m.tankz.proto.pack.LoginRequest; import ru.m.tankz.proto.pack.LoginRequest;
import ru.m.tankz.proto.pack.LoginResponse; import ru.m.tankz.proto.pack.Request;
import ru.m.tankz.proto.pack.Response;
import ru.m.tankz.storage.UserStorage; import ru.m.tankz.storage.UserStorage;
class NetworkManager implements IPacketHandler implements IConnectionHandler { typedef ClientConnection = IConnection<Request, Response>;
class NetworkManager {
public var state(default, null):String; public var state(default, null):String;
public var stateSignal:Signal1<String>; public var stateSignal:Signal1<String>;
public var user(default, null):User; public var user(default, null):User;
private var connection(get, never):IConnection; private var connection(get, never):ClientConnection;
private var storage(get, never):UserStorage; private var storage(get, never):UserStorage;
inline private function get_connection():IConnection { inline private function get_connection():ClientConnection {
return Provider.get(IConnection); return Provider.get(IConnection);
} }
@@ -29,8 +31,8 @@ class NetworkManager implements IPacketHandler implements IConnectionHandler {
public function new() { public function new() {
stateSignal = new Signal1<String>(); stateSignal = new Signal1<String>();
updateState('offline'); updateState('offline');
connection.handler.addListener(this); connection.handler.connect(onConnectionEvent);
connection.packetHandler.addListener(this); connection.packetHandler.connect(onResponse);
user = storage.read(); user = storage.read();
if (user == null) { if (user == null) {
user = {name: 'User', uuid: null}; user = {name: 'User', uuid: null};
@@ -44,39 +46,29 @@ class NetworkManager implements IPacketHandler implements IConnectionHandler {
public function login(name:String):Void { public function login(name:String):Void {
user.name = name; user.name = name;
if (!connection.connected) { updateState('connect...');
updateState('connect...'); connection.connect().then(function(c:ClientConnection) {
connection.connect(); updateState('login...');
} else { c.send(new Request().setLogin(
onConnected(); new LoginRequest()
.setUuid(user.uuid)
.setName(user.name)
));
}).catchError(function(_) {});
}
private function onConnectionEvent(event:ConnectionEvent):Void {
updateState(Std.string(event));
}
private function onResponse(packet:Response):Void {
if (packet.hasLogin()) {
user = {
uuid: packet.login.user.uuid,
name: packet.login.user.name,
};
storage.write(user);
updateState('online');
} }
} }
public function onConnected():Void {
updateState('login...');
connection.send(
new LoginRequest()
.setUuid(user.uuid)
.setName(user.name)
);
}
public function onDisconnected():Void {
updateState('offline');
}
public function onError(error:Dynamic):Void {
updateState('error');
}
public function onLoginResponse(packet:LoginResponse):Void {
user = {
uuid: packet.user.uuid,
name: packet.user.name,
};
storage.write(user);
updateState('online');
}
public function onPacket(packet:Message):Void {}
} }

View File

@@ -1,60 +1,45 @@
package ru.m.connect; package ru.m.connect;
import haxework.dispath.Dispatcher; import promhx.Deferred;
import haxework.dispath.IDispatcher; import hxsignal.impl.Signal1;
import haxework.provider.Provider;
import haxe.io.Bytes; import haxe.io.Bytes;
import promhx.Promise;
import protohx.Message; import protohx.Message;
import ru.m.connect.IConnection; import ru.m.connect.IConnection;
class BaseConnection implements IConnection {
public var handler(default,default):IDispatcher<IConnectionHandler>;
public var packetHandler(default,default):IDispatcher<IPacketHandler>;
public var connected(default, null):Bool;
public var queue(default, null):PacketQueue;
public var builder(default, null):IPacketBuilder;
public function new() { class BaseConnection<O:Message, I:Message> implements IConnection<O, I> {
this.builder = Provider.get(IPacketBuilder); public var handler(default, default):Signal1<ConnectionEvent>;
this.queue = new PacketQueue(builder); public var packetHandler(default, default):Signal1<I>;
this.handler = new Dispatcher<IConnectionHandler>(); public var connected(default, null):Bool;
this.packetHandler = new Dispatcher<IPacketHandler>(); public var queue(default, null):PacketQueue<I>;
}
public function connect():Void { private var connectDeferred:Deferred<IConnection<O, I>>;
throw "Not implemented";
}
public function disconnect():Void { public function new(i:Class<I>) {
throw "Not implemented"; queue = new PacketQueue<I>(i);
} handler = new Signal1<ConnectionEvent>();
packetHandler = new Signal1<I>();
public function pushData(bytes:Bytes):Void { connectDeferred = new Deferred();
queue.addBytes(bytes);
while (queue.hasMsg()) {
var packet:Message = queue.popMsg();
try {
receive(packet);
} catch (error:Dynamic) {
trace(error);
handler.dispatch(function(h) h.onError(error));
}
} }
}
public function send(packet:Message):Void {
#if proto_debug L.d("Send", Type.getClassName(Type.getClass(packet)).split(".").pop()); #end
}
public function receive(packet:Message):Void { public function connect():Promise<IConnection<O, I>> {
#if proto_debug L.d("Receive", Type.getClassName(Type.getClass(packet)).split(".").pop()); #end throw "Not implemented";
var name = "on" + Type.getClassName(Type.getClass(packet)).split(".").pop(); }
packetHandler.dispatch(function(h) {
var method = Reflect.field(h, name); public function disconnect():Void {
if (method != null && Reflect.isFunction(method)) { throw "Not implemented";
Reflect.callMethod(h, method, [packet]); }
} else {
h.onPacket(packet); public function pushData(bytes:Bytes):Void {
} queue.addBytes(bytes);
}); while (queue.hasMsg()) {
} var packet:I = queue.popMsg();
packetHandler.emit(packet);
}
}
public function send(packet:O):Void {
#if proto_debug L.d("Send", Type.getClassName(Type.getClass(packet)).split(".").pop()); #end
}
} }

View File

@@ -6,37 +6,19 @@ import promhx.Promise;
import protohx.Message; import protohx.Message;
interface IConnection { enum ConnectionEvent {
CONNECTED;
DISCONNECTED;
ERROR(error:Dynamic);
}
interface IConnection<O:Message, I:Message> {
public var connected(default, null):Bool; public var connected(default, null):Bool;
public var handler(default, default):Signal1<IConnectionHandler>; public var handler(default, null):Signal1<ConnectionEvent>;
public var packetHandler(default, default):Signal1<IPacketHandler>; public var packetHandler(default, null):Signal1<I>;
public var builder(default, null):IPacketBuilder; public function connect():Promise<IConnection<O, I>>;
public function connect():Promise<IConnection>;
public function disconnect():Void; public function disconnect():Void;
public function send(packet:Message):Void; public function send(packet:O):Void;
public function pushData(bytes:Bytes):Void; public function pushData(bytes:Bytes):Void;
public function receive(packet:Message):Void;
}
interface IConnectionHandler {
public function onConnected():Void;
public function onDisconnected():Void;
public function onError(error:Dynamic):Void;
}
interface IPacketHandler {
public function onPacket(packet:Message):Void;
}
typedef PacketMeta = {
var family:Int;
var id:Int;
}
interface IPacketBuilder {
public function packetMeta(packet:Message):PacketMeta;
public function buildPacket(meta:PacketMeta):Message;
} }

View File

@@ -1,80 +1,75 @@
package ru.m.connect; package ru.m.connect;
import ru.m.connect.IConnection.IPacketBuilder;
import protohx.Message;
import haxe.io.BytesInput;
import haxe.io.BytesBuffer;
import haxe.io.Bytes; import haxe.io.Bytes;
import haxe.io.BytesBuffer;
import haxe.io.BytesInput;
import protohx.Message;
class PacketQueue {
public static inline var HEADER_SIZE:Int = 4; class PacketQueue<P:Message> {
private var builder:IPacketBuilder; private var packetClass:Class<P>;
private var bytesBuff:Bytes; private var bytesBuff:Bytes;
private var msgs:List<Message>; private var msgs:List<P>;
public function new(builder:IPacketBuilder) { public function new(packetClass:Class<P>) {
this.builder = builder; this.packetClass = packetClass;
msgs = new List<Message>(); msgs = new List<P>();
}
public inline function hasMsg():Bool {
return !msgs.isEmpty();
}
public inline function popMsg():Message {
return msgs.pop();
}
public inline function addMsg(msg:Message):Void {
msgs.add(msg);
}
public function addBytes(bytes:Bytes) {
if (bytes == null) {
return;
} }
if (bytesBuff == null) {
bytesBuff = bytes; public inline function hasMsg():Bool {
} else { return !msgs.isEmpty();
var buffer = new BytesBuffer();
buffer.add(bytesBuff);
buffer.add(bytes);
bytesBuff = buffer.getBytes();
} }
if (bytesBuff == null || bytesBuff.length < HEADER_SIZE) {
return; public inline function popMsg():P {
return msgs.pop();
} }
var available = bytesBuff.length;
var bi = new BytesInput(bytesBuff); public inline function addMsg(msg:P):Void {
bi.bigEndian = false; msgs.add(msg);
while (available >= HEADER_SIZE) {
var family = bi.readByte();
var id = bi.readByte();
var packetSize = bi.readUInt16();
available -= HEADER_SIZE;
if (packetSize <= available) {
available -= packetSize;
var msgBytes = bi.read(packetSize);
var packet = builder.buildPacket({family:family, id:id});
packet.mergeFrom(msgBytes);
addMsg(packet);
} else {
available += HEADER_SIZE;
break;
}
} }
if (available == 0) {
bytesBuff = null; public function addBytes(bytes:Bytes):Void {
} else if (available > 0) { if (bytes == null) {
if (bytesBuff.length != available) { return;
var pos = bytesBuff.length - available; }
bytesBuff = bytesBuff.sub(pos, available); if (bytesBuff == null) {
} bytesBuff = bytes;
} else { } else {
throw "Wrong available: " + available; var buffer = new BytesBuffer();
buffer.add(bytesBuff);
buffer.add(bytes);
bytesBuff = buffer.getBytes();
}
if (bytesBuff == null || bytesBuff.length < 1) {
return;
}
var available = bytesBuff.length;
var bi = new BytesInput(bytesBuff);
bi.bigEndian = false;
while (available > 0) {
var packetSize = bi.readUInt16();
available -= 1;
if (packetSize <= available) {
var msgBytes = bi.read(packetSize);
var packet:P = Type.createInstance(packetClass, []);
packet.mergeFrom(msgBytes);
addMsg(packet);
available -= packetSize;
} else {
break;
}
}
if (available == 0) {
bytesBuff = null;
} else if (available > 0) {
if (bytesBuff.length != available) {
var pos = bytesBuff.length - available;
bytesBuff = bytesBuff.sub(pos, available);
}
} else {
throw "Wrong available: " + available;
}
} }
}
} }

View File

@@ -1,6 +1,7 @@
package ru.m.connect.flash; package ru.m.connect.flash;
import ru.m.connect.IConnection.IConnectionHandler; import ru.m.connect.IConnection.ConnectionEvent;
import promhx.Promise;
import flash.utils.Endian; import flash.utils.Endian;
import haxe.io.BytesOutput; import haxe.io.BytesOutput;
import protohx.Message; import protohx.Message;
@@ -12,76 +13,77 @@ import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent; import flash.events.IOErrorEvent;
import flash.net.Socket; import flash.net.Socket;
class FlashConnection extends BaseConnection {
private var host:String; class FlashConnection<O:Message, I:Message> extends BaseConnection<O, I> {
private var port:Int;
private var socket:Socket;
public function new(host:String, port:Int) { private var host:String;
super(); private var port:Int;
this.host = host; private var socket:Socket;
this.port = port;
connected = false;
socket = new Socket();
socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
socket.endian = Endian.LITTLE_ENDIAN;
}
override public function connect():Void { public function new(host:String, port:Int, i:Class<I>) {
socket.connect(host, port); super(i);
} this.host = host;
this.port = port;
override public function disconnect():Void { connected = false;
if (socket.connected) { socket = new Socket();
socket.close(); socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
connected = false; socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
handler.dispatch(function(h) h.onDisconnected()); socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
socket.endian = Endian.LITTLE_ENDIAN;
} }
}
private function onError(event:ErrorEvent):Void { override public function connect():Promise<IConnection<O, I>> {
socket.close(); socket.connect(host, port);
connected = false; return connectDeferred.promise();
handler.dispatch(function(h) h.onError(event));
}
private function onConnect(_):Void {
connected = true;
handler.dispatch(function(h) h.onConnected());
}
private function onClose(_):Void {
socket.close();
connected = false;
handler.dispatch(function(h) h.onDisconnected());
}
private function onSocketData(_):Void {
try {
var b = new flash.utils.ByteArray();
socket.readBytes(b);
var bs = Bytes.ofData(cast b);
pushData(bs);
} catch (error:Dynamic) {
handler.dispatch(function(h) h.onError(error));
} }
}
override public function send(packet:Message):Void { override public function disconnect():Void {
super.send(packet); if (socket.connected) {
var meta = builder.packetMeta(packet); socket.close();
socket.writeByte(meta.family); //connected = false;
socket.writeByte(meta.id); //handler.emit(ConnectionEvent.DISCONNECTED);
var out = new BytesOutput(); }
packet.writeTo(out); }
var bytes = out.getBytes();
socket.writeShort(bytes.length); private function onError(event:ErrorEvent):Void {
socket.writeBytes(cast bytes.getData()); socket.close();
socket.flush(); connected = false;
} handler.emit(ConnectionEvent.ERROR(event));
connectDeferred.throwError(event);
}
private function onConnect(_):Void {
connected = true;
handler.emit(ConnectionEvent.CONNECTED);
connectDeferred.resolve(this);
}
private function onClose(_):Void {
socket.close();
connected = false;
handler.emit(ConnectionEvent.DISCONNECTED);
}
private function onSocketData(_):Void {
try {
var b = new flash.utils.ByteArray();
socket.readBytes(b);
var bs = Bytes.ofData(cast b);
pushData(bs);
} catch (error:Dynamic) {
handler.emit(ConnectionEvent.ERROR(error));
}
}
override public function send(packet:O):Void {
super.send(packet);
var out = new BytesOutput();
packet.writeTo(out);
var bytes = out.getBytes();
socket.writeShort(bytes.length);
socket.writeBytes(cast bytes.getData());
socket.flush();
}
} }

View File

@@ -1,63 +0,0 @@
package ru.m.tankz;
import protohx.Message;
import ru.m.connect.IConnection;
import ru.m.tankz.proto.pack.*;
import Type;
class PacketBuilder implements IPacketBuilder {
private static var MAP:Map<Int, Map<Int, Class<Message>>> = [
0x00 => [
0x0001 => ErrorResponse
],
0x01 => [
0x0001 => LoginRequest,
0x0002 => LoginResponse,
],
0x02 => [
0x0001 => GameListRequest,
0x0002 => GameListResponse,
0x0003 => CreateGameRequest,
0x0004 => CreateGameResponse,
0x0005 => GameListResponse,
0x0006 => JoinGameRequest,
0x0007 => JoinGameResponse,
0x0008 => StartGameRequest,
0x0009 => StartGameResponse,
0x000a => LeaveGameRequest,
0x000b => LeaveGameResponse
],
0x03 => [
0x0001 => GameActionRequest,
0x0002 => GameUpdateResponse
]
];
public function new() {}
public function packetMeta(packet:Message):PacketMeta {
for (family in MAP.keys()) {
var subMap = MAP[family];
for (id in subMap.keys()) {
var packetClass = subMap[id];
if (Std.is(packet, packetClass)) {
return {
family:family,
id:id
}
}
}
}
throw "Unsupported packet(" + Type.getClassName(Type.getClass(packet)).split(".").pop() + ")";
return null;
}
public function buildPacket(meta:PacketMeta):Message {
if (!MAP.exists(meta.family)) throw "Unsupported family(" + meta.family + ")";
if (!MAP[meta.family].exists(meta.id)) throw "Unsupported family(" + meta.family + ") id(" + meta.id + ")";
var packetClass = MAP[meta.family][meta.id];
return Type.createInstance(packetClass, []);
}
}

View File

@@ -65,3 +65,20 @@ message GameActionRequest {
message GameUpdateResponse { message GameUpdateResponse {
repeated ru.m.tankz.proto.game.GameChange changes = 1; repeated ru.m.tankz.proto.game.GameChange changes = 1;
} }
message Request {
oneof content {
LoginRequest login = 1;
CreateGameRequest createGame = 2;
}
}
message Response {
oneof content {
LoginResponse login = 1;
CreateGameResponse createGame = 2;
}
}