From 78bbf5264ea3551755881351a11edfd869aef8c4 Mon Sep 17 00:00:00 2001 From: shmyga Date: Tue, 4 Jun 2019 12:13:27 +0300 Subject: [PATCH] [proto] add rooms and slots --- protohx.json | 3 +- .../haxe/ru/m/tankz/game/NetworkGame.hx | 13 +-- .../haxe/ru/m/tankz/network/NetworkManager.hx | 68 +++++------- .../haxe/ru/m/tankz/view/ClientView.yaml | 8 +- src/client/haxe/ru/m/tankz/view/StartFrame.hx | 14 +-- .../ru/m/tankz/view/network/GameItemView.hx | 24 ----- .../ru/m/tankz/view/network/GameListFrame.hx | 45 -------- .../ru/m/tankz/view/network/GameRoomFrame.hx | 55 ---------- .../ru/m/tankz/view/network/PlayerItemView.hx | 24 ----- .../haxe/ru/m/tankz/view/network/RoomFrame.hx | 54 ++++++++++ .../{GameRoomFrame.yaml => RoomFrame.yaml} | 5 +- .../ru/m/tankz/view/network/RoomItemView.hx | 24 +++++ .../{GameItemView.yaml => RoomItemView.yaml} | 0 .../ru/m/tankz/view/network/RoomListFrame.hx | 47 ++++++++ ...{GameListFrame.yaml => RoomListFrame.yaml} | 4 +- .../ru/m/tankz/view/network/SlotItemView.hx | 24 +++++ ...{PlayerItemView.yaml => SlotItemView.yaml} | 0 src/common/proto/core.proto | 16 +-- src/common/proto/game.proto | 25 ----- src/common/proto/pack.proto | 69 ++---------- src/common/proto/room.proto | 63 +++++++++++ .../ru/m/tankz/server/game/GameManager.hx | 59 +++++++---- .../ru/m/tankz/server/game/IGameManager.hx | 5 +- .../haxe/ru/m/tankz/server/game/ServerGame.hx | 59 ++++++++--- .../ru/m/tankz/server/session/GameSession.hx | 100 ++++++++---------- 25 files changed, 405 insertions(+), 403 deletions(-) delete mode 100644 src/client/haxe/ru/m/tankz/view/network/GameItemView.hx delete mode 100644 src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx delete mode 100644 src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx delete mode 100644 src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx create mode 100644 src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx rename src/client/haxe/ru/m/tankz/view/network/{GameRoomFrame.yaml => RoomFrame.yaml} (80%) create mode 100644 src/client/haxe/ru/m/tankz/view/network/RoomItemView.hx rename src/client/haxe/ru/m/tankz/view/network/{GameItemView.yaml => RoomItemView.yaml} (100%) create mode 100644 src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx rename src/client/haxe/ru/m/tankz/view/network/{GameListFrame.yaml => RoomListFrame.yaml} (81%) create mode 100644 src/client/haxe/ru/m/tankz/view/network/SlotItemView.hx rename src/client/haxe/ru/m/tankz/view/network/{PlayerItemView.yaml => SlotItemView.yaml} (100%) create mode 100644 src/common/proto/room.proto diff --git a/protohx.json b/protohx.json index b162cd2..4990425 100755 --- a/protohx.json +++ b/protohx.json @@ -3,9 +3,10 @@ "protoFiles": [ "src/common/proto/core.proto", "src/common/proto/game.proto", + "src/common/proto/room.proto", "src/common/proto/pack.proto" ], "cleanOut": true, "haxeOut": "src-gen/haxe", "javaOut": null -} \ No newline at end of file +} diff --git a/src/client/haxe/ru/m/tankz/game/NetworkGame.hx b/src/client/haxe/ru/m/tankz/game/NetworkGame.hx index 2cabfe5..87a5a10 100644 --- a/src/client/haxe/ru/m/tankz/game/NetworkGame.hx +++ b/src/client/haxe/ru/m/tankz/game/NetworkGame.hx @@ -7,13 +7,14 @@ import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameState; import ru.m.tankz.network.NetworkManager; import ru.m.tankz.proto.pack.GameEventResponse; +import ru.m.tankz.proto.room.RoomSlotProto; class NetworkGame extends Game { private var network:NetworkManager; public function new(network:NetworkManager) { - super(new GameState(network.game.type, 0, network.game.level)); + super(new GameState(network.room.game.type, 0, network.room.game.level)); this.network = network; this.controlFactory = new NetworkControlFactory(); network.gameEventSignal.connect(onGameEventProto); @@ -30,17 +31,17 @@ class NetworkGame extends Game { private function onConnectionState(state:ConnectionState):Void { switch state { case ONLINE(user): - if (network.game != null) { - network.joinGame(network.game.id); + if (network.room != null) { + network.joinGame(network.room.game.id); } case _: } } override public function start():Void { - var player = Lambda.find(network.game.players, function(player) return player.user.uuid == network.user.uuid); - if (player != null) { - state.controls.push({playerId: [player.team, player.index], control: "human-0"}); + var slot:RoomSlotProto = Lambda.find(network.room.slots, function(slot:RoomSlotProto) return slot.hasUser() && slot.user.uuid == network.user.uuid); + if (slot != null) { + state.controls.push({playerId: [slot.slot.team, slot.slot.index], control: "human-0"}); } super.start(); } diff --git a/src/client/haxe/ru/m/tankz/network/NetworkManager.hx b/src/client/haxe/ru/m/tankz/network/NetworkManager.hx index 2b9db79..17f495f 100644 --- a/src/client/haxe/ru/m/tankz/network/NetworkManager.hx +++ b/src/client/haxe/ru/m/tankz/network/NetworkManager.hx @@ -1,24 +1,26 @@ package ru.m.tankz.network; +import ru.m.tankz.proto.room.SlotProto; +import ru.m.tankz.proto.room.SlotRequest; import haxe.Serializer; import haxework.signal.Signal; import ru.m.connect.IConnection; import ru.m.tankz.control.Control; import ru.m.tankz.game.GameEvent; -import ru.m.tankz.proto.core.GameProto; import ru.m.tankz.proto.core.UserProto; -import ru.m.tankz.proto.game.GameChangeProto; -import ru.m.tankz.proto.pack.CreateGameRequest; import ru.m.tankz.proto.pack.GameEventRequest; import ru.m.tankz.proto.pack.GameEventResponse; -import ru.m.tankz.proto.pack.JoinGameRequest; -import ru.m.tankz.proto.pack.LeaveGameRequest; -import ru.m.tankz.proto.pack.ListGameRequest; import ru.m.tankz.proto.pack.LoginRequest; import ru.m.tankz.proto.pack.LogoutRequest; import ru.m.tankz.proto.pack.Request; import ru.m.tankz.proto.pack.Response; -import ru.m.tankz.proto.pack.StartGameRequest; +import ru.m.tankz.proto.room.CreateRequest; +import ru.m.tankz.proto.room.JoinRequest; +import ru.m.tankz.proto.room.LeaveRequest; +import ru.m.tankz.proto.room.RoomListRequest; +import ru.m.tankz.proto.room.RoomProto; +import ru.m.tankz.proto.room.RoomRequest; +import ru.m.tankz.proto.room.StartRequest; import ru.m.tankz.storage.MultiplayerStorage; typedef ClientConnection = IConnection; @@ -35,13 +37,12 @@ enum ConnectionState { class NetworkManager { public var state(default, null):ConnectionState; - public var game(default, null):GameProto; + public var room(default, null):RoomProto; public var user(default, null):UserProto; public var stateSignal:Signal; - public var listGameSignal:Signal>; - public var gameSignal:Signal; - public var gameUpdateSignal:Signal>; + public var listRoomSignal:Signal>; + public var roomSignal:Signal; public var gameEventSignal:Signal; @:provide private var connection:ClientConnection; @@ -53,9 +54,8 @@ class NetworkManager { public function new() { reconnectDelay = 500; stateSignal = new Signal(); - listGameSignal = new Signal(); - gameSignal = new Signal(); - gameUpdateSignal = new Signal(); + listRoomSignal = new Signal(); + roomSignal = new Signal(); gameEventSignal = new Signal(); updateState(OFFLINE); connection.handler.connect(onConnectionEvent); @@ -81,24 +81,28 @@ class NetworkManager { connection.send(new Request().setLogout(new LogoutRequest())); } - public function listGame():Void { - connection.send(new Request().setListGame(new ListGameRequest())); + public function listGame(subscribe:Bool):Void { + connection.send(new Request().setRoomList(new RoomListRequest().setSubscribe(subscribe))); } public function createGame(type:String, level:Int):Void { - connection.send(new Request().setCreateGame(new CreateGameRequest().setType(type).setLevel(level))); + connection.send(new Request().setRoom(new RoomRequest().setCreate(new CreateRequest().setType(type).setLevel(level)))); } public function joinGame(gameId:Int, restore:Bool = false):Void { - connection.send(new Request().setJoinGame(new JoinGameRequest().setGameId(gameId).setRestore(restore))); + connection.send(new Request().setRoom(new RoomRequest().setJoin(new JoinRequest().setGameId(gameId)))); + } + + public function selectSlot(slot:SlotProto):Void { + connection.send(new Request().setRoom(new RoomRequest().setSlot(new SlotRequest().setSlot(slot)))); } public function leaveGame():Void { - connection.send(new Request().setLeaveGame(new LeaveGameRequest())); + connection.send(new Request().setRoom(new RoomRequest().setLeave(new LeaveRequest()))); } public function startGame():Void { - connection.send(new Request().setStartGame(new StartGameRequest())); + connection.send(new Request().setRoom(new RoomRequest().setStart(new StartRequest()))); } public function action(tankId:Int, action:TankAction):Void { @@ -154,25 +158,11 @@ class NetworkManager { } else if (packet.hasLogout()) { storage.user = null; updateState(CONNECTED); - } else if (packet.hasListGame()) { - listGameSignal.emit(packet.listGame.games); - } else if (packet.hasCreateGame()) { - game = packet.createGame.game; - gameSignal.emit(game); - } else if (packet.hasJoinGame()) { - game = packet.joinGame.game; - gameSignal.emit(game); - } else if (packet.hasLeaveGame()) { - if (packet.leaveGame.user.uuid == user.uuid) { - game = null; - gameSignal.emit(null); - } else { - game = packet.leaveGame.game; - gameSignal.emit(game); - } - } else if (packet.hasStartGame()) { - game = packet.startGame.game; - gameSignal.emit(game); + } else if (packet.hasRoomList()) { + listRoomSignal.emit(packet.roomList.rooms); + } else if (packet.hasRoom()) { + room = packet.room.room; + roomSignal.emit(room); } else if (packet.hasGameEvent()) { gameEventSignal.emit(packet.gameEvent); } diff --git a/src/client/haxe/ru/m/tankz/view/ClientView.yaml b/src/client/haxe/ru/m/tankz/view/ClientView.yaml index b1152f8..fdda0f4 100755 --- a/src/client/haxe/ru/m/tankz/view/ClientView.yaml +++ b/src/client/haxe/ru/m/tankz/view/ClientView.yaml @@ -17,10 +17,10 @@ views: $type: ru.m.tankz.view.SettingsFrame - id: record $type: ru.m.tankz.view.RecordFrame - - id: game_list - $type: ru.m.tankz.view.network.GameListFrame - - id: game_room - $type: ru.m.tankz.view.network.GameRoomFrame + - id: room_list + $type: ru.m.tankz.view.network.RoomListFrame + - id: room + $type: ru.m.tankz.view.network.RoomFrame - $type: haxework.view.HGroupView skinId: panel layout.margin: 10 diff --git a/src/client/haxe/ru/m/tankz/view/StartFrame.hx b/src/client/haxe/ru/m/tankz/view/StartFrame.hx index bdb1427..1a43649 100644 --- a/src/client/haxe/ru/m/tankz/view/StartFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/StartFrame.hx @@ -5,8 +5,8 @@ import haxework.view.VGroupView; import ru.m.tankz.game.GameState; import ru.m.tankz.network.NetworkManager; import ru.m.tankz.Type.GameType; -import ru.m.tankz.view.network.GameListFrame; -import ru.m.tankz.view.network.GameRoomFrame; +import ru.m.tankz.view.network.RoomListFrame; +import ru.m.tankz.view.network.RoomFrame; import ru.m.tankz.view.popup.FontPopup; import ru.m.tankz.view.popup.LoginPopup; @@ -28,16 +28,16 @@ import ru.m.tankz.view.popup.LoginPopup; private function startNetwork():Void { switch network.state { case ONLINE(user): - if (network.game != null) { - switcher.change(GameRoomFrame.ID); - network.joinGame(network.game.id, true); + if (network.room != null) { + switcher.change(RoomFrame.ID); + network.joinGame(network.room.game.id, true); } else { - switcher.change(GameListFrame.ID); + switcher.change(RoomListFrame.ID); } case CONNECTED: LoginPopup.instance.show().then(function(user):Void { if (user != null) { - switcher.change(GameListFrame.ID); + switcher.change(RoomListFrame.ID); } }); case _: diff --git a/src/client/haxe/ru/m/tankz/view/network/GameItemView.hx b/src/client/haxe/ru/m/tankz/view/network/GameItemView.hx deleted file mode 100644 index 4042ee3..0000000 --- a/src/client/haxe/ru/m/tankz/view/network/GameItemView.hx +++ /dev/null @@ -1,24 +0,0 @@ -package ru.m.tankz.view.network; - -import haxework.view.LabelView; -import haxework.view.HGroupView; -import haxework.view.list.ListView; -import ru.m.tankz.proto.core.GameProto; - -@:template class GameItemView extends HGroupView implements IListItemView { - - public var item_index(default, default):Int; - public var data(default, set):GameProto; - - @:view var label:LabelView; - - private function set_data(value:GameProto):GameProto { - data = value; - label.text = '[${value.creator.name}] ${value.type} ${value.level} (${value.players.length})'; - return data; - } - - public static function factory():GameItemView { - return new GameItemView(); - } -} diff --git a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx b/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx deleted file mode 100644 index b865b39..0000000 --- a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx +++ /dev/null @@ -1,45 +0,0 @@ -package ru.m.tankz.view.network; - -import haxework.view.frame.FrameSwitcher; -import haxework.view.list.VListView; -import haxework.view.VGroupView; -import ru.m.tankz.network.NetworkManager; -import ru.m.tankz.proto.core.GameProto; - -@:template class GameListFrame extends VGroupView { - public static inline var ID = "game_list"; - - @:view var games:VListView; - - @:provide var switcher:FrameSwitcher; - @:provide var network:NetworkManager; - - public function onShow():Void { - network.listGameSignal.connect(onGameList); - network.gameSignal.connect(onGame); - network.listGame(); - } - - public function onHide():Void { - network.listGameSignal.disconnect(onGameList); - network.gameSignal.disconnect(onGame); - } - - private function create():Void { - network.createGame("classic", 0); - } - - private function onGameList(data:Array):Void { - games.data = data; - } - - private function onGame(game:GameProto):Void { - if (game != null) { - switcher.change(GameRoomFrame.ID); - } - } - - private function selectGame(game:GameProto):Void { - network.joinGame(game.id, true); - } -} diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx deleted file mode 100644 index 73ce966..0000000 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx +++ /dev/null @@ -1,55 +0,0 @@ -package ru.m.tankz.view.network; - -import haxework.view.ButtonView; -import haxework.view.frame.FrameSwitcher; -import haxework.view.list.VListView; -import haxework.view.TextView; -import haxework.view.VGroupView; -import ru.m.tankz.game.IGame; -import ru.m.tankz.game.NetworkGame; -import ru.m.tankz.network.NetworkManager; -import ru.m.tankz.proto.core.GameProto; -import ru.m.tankz.proto.core.GameStateProto; -import ru.m.tankz.proto.core.PlayerProto; - -@:template class GameRoomFrame extends VGroupView { - - public static inline var ID = "game_room"; - - @:view var start:ButtonView; - @:view var info:TextView; - @:view var players:VListView; - - @:provide var switcher:FrameSwitcher; - @:provide var network:NetworkManager; - @:provide var game:IGame; - - private function refresh(game:GameProto):Void { - if (game != null) { - start.visible = game.creator.uuid == network.user.uuid; - info.text = '[${game.creator.name}] ${game.type} ${game.level} (${game.players.length})'; - players.data = game.players; - if (game.state == GameStateProto.STARTED) { - if (this.game == null) { - this.game = new NetworkGame(network); - } - switcher.change(GameFrame.ID); - } - } else { - Timer.delay(function() switcher.change(GameListFrame.ID), 1); - } - } - - public function onShow():Void { - refresh(network.game); - network.gameSignal.connect(onGame); - } - - public function onHide():Void { - network.gameSignal.disconnect(onGame); - } - - private function onGame(game:GameProto):Void { - refresh(game); - } -} diff --git a/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx b/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx deleted file mode 100644 index 8e27971..0000000 --- a/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.hx +++ /dev/null @@ -1,24 +0,0 @@ -package ru.m.tankz.view.network; - -import haxework.view.HGroupView; -import haxework.view.LabelView; -import haxework.view.list.ListView; -import ru.m.tankz.proto.core.PlayerProto; - -@:template class PlayerItemView extends HGroupView implements IListItemView { - - public var item_index(default, default):Int; - public var data(default, set):PlayerProto; - - @:view var label:LabelView; - - private function set_data(value:PlayerProto):PlayerProto { - data = value; - label.text = '${value.user.name}'; - return data; - } - - public static function factory():PlayerItemView { - return new PlayerItemView(); - } -} diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx new file mode 100644 index 0000000..1d6e71c --- /dev/null +++ b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.hx @@ -0,0 +1,54 @@ +package ru.m.tankz.view.network; + +import haxework.view.ButtonView; +import haxework.view.frame.FrameSwitcher; +import haxework.view.list.VListView; +import haxework.view.TextView; +import haxework.view.VGroupView; +import ru.m.tankz.game.IGame; +import ru.m.tankz.game.NetworkGame; +import ru.m.tankz.network.NetworkManager; +import ru.m.tankz.proto.room.RoomProto; +import ru.m.tankz.proto.room.RoomSlotProto; + +@:template class RoomFrame extends VGroupView { + + public static inline var ID = "room"; + + @:view var start:ButtonView; + @:view var info:TextView; + @:view var slots:VListView; + + @:provide var switcher:FrameSwitcher; + @:provide var network:NetworkManager; + @:provide var game:IGame; + + private function refresh(room:RoomProto):Void { + if (room != null) { + start.visible = room.creator.uuid == network.user.uuid; + info.text = '[${room.creator.name}] ${room.game.type} ${room.game.level} (${room.users.length})'; + slots.data = room.slots; + if (room.game.started) { + if (this.game == null) { + this.game = new NetworkGame(network); + } + switcher.change(GameFrame.ID); + } + } else { + Timer.delay(function() switcher.change(RoomListFrame.ID), 1); + } + } + + private function selectSlot(slot:RoomSlotProto):Void { + network.selectSlot(slot.slot); + } + + public function onShow():Void { + refresh(network.room); + network.roomSignal.connect(refresh); + } + + public function onHide():Void { + network.roomSignal.disconnect(refresh); + } +} diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml similarity index 80% rename from src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml rename to src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml index 7ec4319..4a7dc2c 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/RoomFrame.yaml @@ -19,7 +19,8 @@ views: $type: haxework.view.LabelView geometry.size.width: 100% skinId: text.box - - id: players + - id: slots $type: haxework.view.list.VListView geometry.size.stretch: true - factory: $code:ru.m.tankz.view.network.PlayerItemView.factory + factory: $code:ru.m.tankz.view.network.SlotItemView.factory + +onItemSelect: $code:function(item) selectSlot(item.data) diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomItemView.hx b/src/client/haxe/ru/m/tankz/view/network/RoomItemView.hx new file mode 100644 index 0000000..c4750c8 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/view/network/RoomItemView.hx @@ -0,0 +1,24 @@ +package ru.m.tankz.view.network; + +import haxework.view.HGroupView; +import haxework.view.LabelView; +import haxework.view.list.ListView; +import ru.m.tankz.proto.room.RoomProto; + +@:template class RoomItemView extends HGroupView implements IListItemView { + + public var item_index(default, default):Int; + public var data(default, set):RoomProto; + + @:view var label:LabelView; + + private function set_data(value:RoomProto):RoomProto { + data = value; + label.text = '[${value.creator.name}] ${value.game.type} ${value.game.level} (${value.users.length})'; + return data; + } + + public static function factory():RoomItemView { + return new RoomItemView(); + } +} diff --git a/src/client/haxe/ru/m/tankz/view/network/GameItemView.yaml b/src/client/haxe/ru/m/tankz/view/network/RoomItemView.yaml similarity index 100% rename from src/client/haxe/ru/m/tankz/view/network/GameItemView.yaml rename to src/client/haxe/ru/m/tankz/view/network/RoomItemView.yaml diff --git a/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx new file mode 100644 index 0000000..bb2e998 --- /dev/null +++ b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.hx @@ -0,0 +1,47 @@ +package ru.m.tankz.view.network; + +import haxework.view.frame.FrameSwitcher; +import haxework.view.list.VListView; +import haxework.view.VGroupView; +import ru.m.tankz.network.NetworkManager; +import ru.m.tankz.proto.room.RoomProto; + +@:template class RoomListFrame extends VGroupView { + public static inline var ID = "room_list"; + + @:view var games:VListView; + + @:provide var switcher:FrameSwitcher; + @:provide var network:NetworkManager; + + public function onShow():Void { + network.listRoomSignal.connect(onRoomList); + network.roomSignal.connect(onRoom); + network.listGame(true); + } + + public function onHide():Void { + network.listRoomSignal.disconnect(onRoomList); + network.roomSignal.disconnect(onRoom); + network.listGame(false); + } + + private function create():Void { + network.createGame("classic", 0); + } + + private function onRoomList(data:Array):Void { + games.data = data; + } + + private function onRoom(room:RoomProto):Void { + if (room != null) { + switcher.change(RoomFrame.ID); + } + } + + private function selectRoom(room:RoomProto):Void { + network.joinGame(room.game.id, true); + } + +} diff --git a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.yaml b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml similarity index 81% rename from src/client/haxe/ru/m/tankz/view/network/GameListFrame.yaml rename to src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml index c1054c2..6b17259 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/RoomListFrame.yaml @@ -16,6 +16,6 @@ views: - id: games $type: haxework.view.list.VListView geometry.size.stretch: true - factory: $code:ru.m.tankz.view.network.GameItemView.factory + factory: $code:ru.m.tankz.view.network.RoomItemView.factory geometry.margin: 10 - +onItemSelect: $code:function(item) selectGame(item.data) + +onItemSelect: $code:function(item) selectRoom(item.data) diff --git a/src/client/haxe/ru/m/tankz/view/network/SlotItemView.hx b/src/client/haxe/ru/m/tankz/view/network/SlotItemView.hx new file mode 100644 index 0000000..37f70fe --- /dev/null +++ b/src/client/haxe/ru/m/tankz/view/network/SlotItemView.hx @@ -0,0 +1,24 @@ +package ru.m.tankz.view.network; + +import haxework.view.HGroupView; +import haxework.view.LabelView; +import haxework.view.list.ListView; +import ru.m.tankz.proto.room.RoomSlotProto; + +@:template class SlotItemView extends HGroupView implements IListItemView { + + public var item_index(default, default):Int; + public var data(default, set):RoomSlotProto; + + @:view var label:LabelView; + + private function set_data(value:RoomSlotProto):RoomSlotProto { + data = value; + label.text = '${value.slot.team}-${value.slot.index} ${value.hasUser() ? value.user.name : '(NONE)'}'; + return data; + } + + public static function factory():SlotItemView { + return new SlotItemView(); + } +} diff --git a/src/client/haxe/ru/m/tankz/view/network/PlayerItemView.yaml b/src/client/haxe/ru/m/tankz/view/network/SlotItemView.yaml similarity index 100% rename from src/client/haxe/ru/m/tankz/view/network/PlayerItemView.yaml rename to src/client/haxe/ru/m/tankz/view/network/SlotItemView.yaml diff --git a/src/common/proto/core.proto b/src/common/proto/core.proto index 6422cf0..cf7bcd6 100644 --- a/src/common/proto/core.proto +++ b/src/common/proto/core.proto @@ -7,23 +7,9 @@ message UserProto { string name = 2; } -enum GameStateProto { - READY = 0; - STARTED = 1; - ENDED = 2; -} - -message PlayerProto { - UserProto user = 1; - string team = 2; - int32 index = 3; -} - message GameProto { int32 id = 1; string type = 2; int32 level = 3; - UserProto creator = 4; - repeated PlayerProto players = 5; - GameStateProto state = 6; + bool started = 4; } diff --git a/src/common/proto/game.proto b/src/common/proto/game.proto index f290470..3ed9f3f 100644 --- a/src/common/proto/game.proto +++ b/src/common/proto/game.proto @@ -1,28 +1,3 @@ syntax = "proto3"; package ru.m.tankz.proto.game; - - -enum GameActionTypeProto { - MOVE = 0; - SHOT = 1; - STOP = 2; -} - -enum GameChangeTypeProto { - MOVED = 0; - DESTROED = 1; - MODIFIED = 2; - APPEND = 3; - DIRECTION = 4; -} - -message GameChangeProto { - GameChangeTypeProto type = 1; - string entityType = 2; - int32 entityId = 3; - float x = 4; - float y = 5; - int32 directionX = 6; - int32 directionY = 7; -} \ No newline at end of file diff --git a/src/common/proto/pack.proto b/src/common/proto/pack.proto index ac70775..1c925ed 100644 --- a/src/common/proto/pack.proto +++ b/src/common/proto/pack.proto @@ -2,16 +2,15 @@ syntax = "proto3"; import "core.proto"; import "game.proto"; +import "room.proto"; package ru.m.tankz.proto.pack; - message ErrorResponse { int32 code = 1; string message = 2; } -// Login message LoginRequest { string uuid = 1; string name = 2; @@ -21,56 +20,10 @@ message LoginResponse { ru.m.tankz.proto.core.UserProto user = 1; } -// Logout message LogoutRequest {} message LogoutResponse {} -// List Game -message ListGameRequest {} - -message ListGameResponse { - repeated ru.m.tankz.proto.core.GameProto games = 1; -} - -// Create Game -message CreateGameRequest { - string type = 1; - int32 level = 2; -} - -message CreateGameResponse { - ru.m.tankz.proto.core.GameProto game = 1; -} - -// Join Game -message JoinGameRequest { - int32 game_id = 1; - bool restore = 2; -} - -message JoinGameResponse { - ru.m.tankz.proto.core.GameProto game = 1; - ru.m.tankz.proto.core.UserProto user = 2; - repeated string events = 3; -} - -// Leave Game -message LeaveGameRequest {} - -message LeaveGameResponse { - ru.m.tankz.proto.core.GameProto game = 1; - ru.m.tankz.proto.core.UserProto user = 2; -} - -// Start Game -message StartGameRequest {} - -message StartGameResponse { - ru.m.tankz.proto.core.GameProto game = 1; -} - -// Game message GameEventRequest { int32 time = 1; string event = 2; @@ -81,31 +34,23 @@ message GameEventResponse { string event = 2; } -// Request message Request { oneof content { LoginRequest login = 1; LogoutRequest logout = 2; - ListGameRequest listGame = 3; - CreateGameRequest createGame = 4; - JoinGameRequest joinGame = 5; - LeaveGameRequest leaveGame = 6; - StartGameRequest startGame = 7; - GameEventRequest gameEvent = 8; + ru.m.tankz.proto.room.RoomRequest room = 3; + ru.m.tankz.proto.room.RoomListRequest roomList = 4; + GameEventRequest gameEvent = 6; } } -// Response message Response { oneof content { LoginResponse login = 1; LogoutResponse logout = 2; - ListGameResponse listGame = 3; - CreateGameResponse createGame = 4; - JoinGameResponse joinGame = 5; - LeaveGameResponse leaveGame = 6; - StartGameResponse startGame = 7; - GameEventResponse gameEvent = 8; + ru.m.tankz.proto.room.RoomResponse room = 3; + ru.m.tankz.proto.room.RoomListResponse roomList = 4; + GameEventResponse gameEvent = 6; ErrorResponse error = 999; } diff --git a/src/common/proto/room.proto b/src/common/proto/room.proto new file mode 100644 index 0000000..038d188 --- /dev/null +++ b/src/common/proto/room.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +import "core.proto"; + +package ru.m.tankz.proto.room; + +message SlotProto { + string team = 3; + int32 index = 4; +} + +message RoomSlotProto { + SlotProto slot = 1; + ru.m.tankz.proto.core.UserProto user = 2; +} + +message RoomProto { + ru.m.tankz.proto.core.GameProto game = 1; + ru.m.tankz.proto.core.UserProto creator = 2; + repeated ru.m.tankz.proto.core.UserProto users = 3; + repeated RoomSlotProto slots = 4; +} + +message CreateRequest { + string type = 2; + int32 level = 3; +} + +message JoinRequest { + int32 gameId = 1; +} + +message LeaveRequest { +} + +message SlotRequest { + SlotProto slot = 3; +} + +message StartRequest { +} + +message RoomRequest { + oneof content { + CreateRequest create = 1; + JoinRequest join = 2; + LeaveRequest leave = 3; + SlotRequest slot = 4; + StartRequest start = 5; + } +} + +message RoomResponse { + RoomProto room = 1; +} + +message RoomListRequest { + bool subscribe = 1; +} + +message RoomListResponse { + repeated RoomProto rooms = 1; +} diff --git a/src/server/haxe/ru/m/tankz/server/game/GameManager.hx b/src/server/haxe/ru/m/tankz/server/game/GameManager.hx index d8a62e0..7aafacb 100644 --- a/src/server/haxe/ru/m/tankz/server/game/GameManager.hx +++ b/src/server/haxe/ru/m/tankz/server/game/GameManager.hx @@ -1,10 +1,13 @@ package ru.m.tankz.server.game; +import ru.m.tankz.config.Config.PlayerControl; +import ru.m.tankz.proto.room.RoomSlotProto; +import ru.m.tankz.proto.room.SlotProto; +import ru.m.tankz.proto.room.RoomProto; import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.IGame.GameListener; import ru.m.tankz.game.IGame; import ru.m.tankz.proto.core.GameProto; -import ru.m.tankz.proto.core.GameStateProto; import ru.m.tankz.proto.core.UserProto; import ru.m.tankz.server.game.IGameManager; @@ -21,7 +24,7 @@ class _GameListener implements GameListener { dispatcher.dispatchEvent(game, event); switch event { case COMPLETE(_, _): - dispatcher.delete(game.proto.id); + dispatcher.delete(game.id); dispose(); case _: } @@ -52,29 +55,36 @@ class _GameListener implements GameListener { public function create(user:UserProto, type:String, level:Int):ServerGame { if (gamesByCreator.exists(user.uuid)) { - delete(gamesByCreator[user.uuid].proto.id); + delete(gamesByCreator[user.uuid].id); } - var proto = new GameProto() - .setId(++counter) - .setCreator(user) - .setType(type) - .setLevel(level); - var game = new ServerGame(proto); - game.joinUser(user); + var room = new RoomProto() + .setGame( + new GameProto() + .setId(++counter) + .setType(type) + .setLevel(level) + ) + .setCreator(user); + var game = new ServerGame(room); + var slots:Array = []; + for (team in game.state.teams) { + for (player in team.players) { + slots.push(new RoomSlotProto().setSlot(new SlotProto().setTeam(player.id.team).setIndex(player.id.index))); + } + } + game.room.setSlots(slots); games.push(game); - /*if (gamesByCreator.exists(user.uuid)) { - delete(gamesByCreator[user.uuid].proto.id); - } else*/ - gamesById[game.proto.id] = game; - gamesByCreator[game.proto.creator.uuid] = game; + gamesById[game.id] = game; + gamesByCreator[game.room.creator.uuid] = game; createSignal.emit(game); + join(game.id, user); return game; } public function join(gameId:Int, user:UserProto):Void { if (gamesById.exists(gameId)) { var game = gamesById[gameId]; - game.joinUser(user); + game.join(user); gamesByUser[user.uuid] = game; changeSignal.emit(game, JOIN(user)); } @@ -84,8 +94,8 @@ class _GameListener implements GameListener { if (gamesById.exists(gameId)) { var game = gamesById[gameId]; games.remove(game); - gamesById.remove(game.proto.id); - gamesByCreator.remove(game.proto.creator.uuid); + gamesById.remove(game.id); + gamesByCreator.remove(game.room.creator.uuid); deleteSignal.emit(game); } } @@ -95,15 +105,24 @@ class _GameListener implements GameListener { delete(gamesByCreator[user.uuid].proto.id); } else*/ if (gamesByUser.exists(user.uuid)) { var game = gamesByUser[user.uuid]; - game.leaveUser(user); + gamesByUser.remove(user.uuid); + game.leave(user); changeSignal.emit(game, LEAVE(user)); } } + public function slot(user:UserProto, slot:SlotProto):Void { + if (gamesByUser.exists(user.uuid)) { + var game = gamesByUser[user.uuid]; + game.slot(user, slot); + changeSignal.emit(game, SLOT(user, slot)); + } + } + public function start(gameId:Int):Void { if (gamesById.exists(gameId)) { var game:ServerGame = gamesById[gameId]; - game.proto.setState(GameStateProto.STARTED); + game.room.game.setStarted(true); changeSignal.emit(game, START); game.connect(new _GameListener(game, this)); game.start(); diff --git a/src/server/haxe/ru/m/tankz/server/game/IGameManager.hx b/src/server/haxe/ru/m/tankz/server/game/IGameManager.hx index b03d62c..ca5acba 100644 --- a/src/server/haxe/ru/m/tankz/server/game/IGameManager.hx +++ b/src/server/haxe/ru/m/tankz/server/game/IGameManager.hx @@ -1,12 +1,14 @@ package ru.m.tankz.server.game; -import ru.m.tankz.game.GameEvent; import haxework.signal.Signal; +import ru.m.tankz.game.GameEvent; import ru.m.tankz.proto.core.UserProto; +import ru.m.tankz.proto.room.SlotProto; enum GameChange { JOIN(user:UserProto); LEAVE(user:UserProto); + SLOT(user:UserProto, slot:SlotProto); START(); } @@ -35,6 +37,7 @@ interface IGameManager { public function create(user:UserProto, type:String, level:Int):ServerGame; public function delete(gameId:Int):Void; public function join(gameId:Int, user:UserProto):Void; + public function slot(user:UserProto, slot:SlotProto):Void; public function leave(user:UserProto):Void; public function start(gameId:Int):Void; } diff --git a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx index ab764e8..9208e31 100644 --- a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx +++ b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx @@ -1,44 +1,69 @@ package ru.m.tankz.server.game; +import ru.m.tankz.proto.room.RoomSlotProto; import ru.m.tankz.config.Config; import ru.m.tankz.core.EntityType; import ru.m.tankz.game.EventUtil; import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameRunner; import ru.m.tankz.game.GameState; -import ru.m.tankz.proto.core.GameProto; -import ru.m.tankz.proto.core.PlayerProto; import ru.m.tankz.proto.core.UserProto; +import ru.m.tankz.proto.room.RoomProto; +import ru.m.tankz.proto.room.SlotProto; import ru.m.tankz.server.control.ServerControlFactory; -import ru.m.tankz.Type.PlayerId; class ServerGame extends GameRunner { public var runner(default, null):GameRunner; - public var proto(default, null):GameProto; + public var room(default, null):RoomProto; + public var id(get, null):Int; - public function new(proto:GameProto) { - super(new GameState(proto.type, 0, proto.level)); + public function new(room:RoomProto) { + super(new GameState(room.game.type, 0, room.game.level)); this.controlFactory = new ServerControlFactory(); - this.proto = proto; + this.room = room; } - public function joinUser(user:UserProto, playerId:PlayerId = null):Void { - leaveUser(user); - if (playerId == null) { - playerId = ["human", proto.players.length]; + private inline function get_id():Int { + return room.game.id; + } + + public function join(user:UserProto):Void { + leave(user); + room.users.push(user); + } + + public function slot(user:UserProto, slot:SlotProto):Void { + for (s in room.slots) { + if (s.hasUser() && s.user.uuid == user.uuid) { + s.clearUser(); + break; + } + } + for (s in room.slots) { + if (s.slot.team == slot.team && s.slot.index == slot.index) { + s.setUser(user); + break; + } } - proto.players.push(new PlayerProto().setUser(user).setTeam(playerId.team).setIndex(playerId.index)); } - public function leaveUser(user:UserProto):Void { - proto.setPlayers(proto.players.filter(function(player) return player.user.uuid != user.uuid)); + public function leave(user:UserProto):Void { + for (slot in room.slots) { + if (slot.user != null && slot.user.uuid == user.uuid) { + slot.clearUser(); + break; + } + } + room.setUsers(room.users.filter(function(u:UserProto) return u.uuid != user.uuid)); } override public function start():Void { - state.controls = proto.players.map(function(player):PlayerControl return { - playerId: [player.team, player.index], - control: 'human-0' + state.controls = room.slots + .filter(function(slot:RoomSlotProto) return slot.hasUser()) + .map(function(slot:RoomSlotProto):PlayerControl return { + playerId: [slot.slot.team, slot.slot.index], + control: "human-0", }); super.start(); } diff --git a/src/server/haxe/ru/m/tankz/server/session/GameSession.hx b/src/server/haxe/ru/m/tankz/server/session/GameSession.hx index e31d96f..c03296a 100644 --- a/src/server/haxe/ru/m/tankz/server/session/GameSession.hx +++ b/src/server/haxe/ru/m/tankz/server/session/GameSession.hx @@ -1,24 +1,20 @@ package ru.m.tankz.server.session; -import ru.m.tankz.proto.core.GameStateProto; -import haxe.Unserializer; -import haxe.Serializer; -import ru.m.tankz.proto.pack.GameEventResponse; -import ru.m.tankz.game.GameEvent; import com.hurlant.crypto.extra.UUID; import com.hurlant.crypto.prng.Random; +import haxe.Serializer; +import haxe.Unserializer; import haxework.log.BaseLogger.LoggerUtil; +import ru.m.tankz.game.GameEvent; import ru.m.tankz.proto.core.UserProto; -import ru.m.tankz.proto.pack.CreateGameResponse; import ru.m.tankz.proto.pack.ErrorResponse; -import ru.m.tankz.proto.pack.JoinGameResponse; -import ru.m.tankz.proto.pack.LeaveGameResponse; -import ru.m.tankz.proto.pack.ListGameResponse; +import ru.m.tankz.proto.pack.GameEventResponse; import ru.m.tankz.proto.pack.LoginResponse; import ru.m.tankz.proto.pack.LogoutResponse; import ru.m.tankz.proto.pack.Request; import ru.m.tankz.proto.pack.Response; -import ru.m.tankz.proto.pack.StartGameResponse; +import ru.m.tankz.proto.room.RoomListResponse; +import ru.m.tankz.proto.room.RoomResponse; import ru.m.tankz.server.game.IGameManager; import ru.m.tankz.server.game.ServerGame; import sys.net.Socket; @@ -31,6 +27,7 @@ class GameSession extends ProtoSession implements GameManager public var user(default, null):UserProto; public var gameId(default, null):Int; + private var subscribed:Bool; private var tag(get, never):String; private function get_tag():String { @@ -46,9 +43,9 @@ class GameSession extends ProtoSession implements GameManager send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message))); } - private function listGame():ListGameResponse { + private function listGame():RoomListResponse { var games = gameManager.games; - return new ListGameResponse().setGames([for (game in games) game.proto]); + return new RoomListResponse().setRooms([for (game in games) game.room]); } override public function send(packet:Response):Void { @@ -86,30 +83,28 @@ class GameSession extends ProtoSession implements GameManager } else if (request.hasLogout()) { logout(); send(new Response().setLogout(new LogoutResponse())); - // create - } else if (request.hasCreateGame()) { - var game = gameManager.create(user, request.createGame.type, request.createGame.level); - gameId = game.proto.id; - send(new Response().setCreateGame(new CreateGameResponse().setGame(game.proto))); - // list - } else if (request.hasListGame()) { - send(new Response().setListGame(listGame())); - // join - } else if (request.hasJoinGame()) { - gameId = request.joinGame.gameId; - gameManager.join(request.joinGame.gameId, user); - var game = gameManager.gamesById[gameId]; - if (request.joinGame.restore && game.proto.state == GameStateProto.STARTED) { - for (event in game.restore()) { - send(new Response().setGameEvent(new GameEventResponse().setTime(0).setEvent(Serializer.run(event)))); - } + // room + } else if (request.hasRoom()) { + if (request.room.hasCreate()) { + var game = gameManager.create(user, request.room.create.type, request.room.create.level); + gameId = game.id; + send(new Response().setRoom(new RoomResponse().setRoom(game.room))); + } else if (request.room.hasJoin()) { + gameId = request.room.join.gameId; + gameManager.join(gameId, user); + } else if (request.room.hasLeave()) { + gameManager.leave(user); + } else if (request.room.hasSlot()) { + gameManager.slot(user, request.room.slot.slot); + } else if (request.room.hasStart()) { + gameManager.start(gameId); + } + // room list + } else if (request.hasRoomList()) { + subscribed = request.roomList.subscribe; + if (subscribed) { + send(new Response().setRoomList(listGame())); } - // leave - } else if (request.hasLeaveGame()) { - gameManager.leave(user); - // start - } else if (request.hasStartGame()) { - gameManager.start(gameId); } else if (request.hasGameEvent()) { if (gameManager.gamesById.exists(gameId)) { var event:GameEvent = Unserializer.run(request.gameEvent.event); @@ -129,44 +124,41 @@ class GameSession extends ProtoSession implements GameManager } public function onCreate(game:ServerGame):Void { - if (gameId == -1) { - send(new Response().setListGame(listGame())); + if (subscribed) { + send(new Response().setRoomList(listGame())); } } public function onChange(game:ServerGame, change:GameChange):Void { - if (gameId == game.proto.id) { + if (gameId == game.id) { switch change { - case JOIN(user): - if (user.uuid == this.user.uuid) { - gameId = game.proto.id; - } - send(new Response().setJoinGame(new JoinGameResponse().setGame(game.proto).setUser(user))); case LEAVE(user): if (user.uuid == this.user.uuid) { gameId = -1; + send(new Response().setRoom(new RoomResponse())); + return; } - send(new Response().setLeaveGame(new LeaveGameResponse().setGame(game.proto).setUser(user))); - case START: - send(new Response().setStartGame(new StartGameResponse().setGame(game.proto))); + case _: } - } else { - // ToDo: change game event - send(new Response().setListGame(listGame())); + send(new Response().setRoom(new RoomResponse().setRoom(game.room))); + } + if (subscribed) { + send(new Response().setRoomList(listGame())); } } public function onDelete(game:ServerGame):Void { - if (gameId == -1) { - send(new Response().setListGame(listGame())); - } else if (gameId == game.proto.id) { + if (gameId == game.id) { gameId = -1; - send(new Response().setLeaveGame(new LeaveGameResponse().setGame(game.proto).setUser(user))); + send(new Response().setRoom(new RoomResponse())); + } + if (subscribed) { + send(new Response().setRoomList(listGame())); } } public function onEvent(game:ServerGame, event:GameEvent):Void { - if (gameId == game.proto.id) { + if (gameId == game.id) { send(new Response().setGameEvent(new GameEventResponse().setTime(0).setEvent(Serializer.run(event)))); } }