diff --git a/gulpfile.js b/gulpfile.js index 2497393..f12ab13 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -48,6 +48,9 @@ const config = new Project.Config({ assets: [ 'src/common/resources' ], + flags: [ + //'proto_debug', + ], macros: [ `CompilationOption.set('build','${dateformat(new Date(), 'yyyy-mm-dd HH:MM:ss')}')`, ] diff --git a/package.json b/package.json index 983694f..3335b48 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tankz", - "version": "0.13.1", + "version": "0.13.2", "private": true, "devDependencies": { "dateformat": "^3.0.3", diff --git a/src/client/haxe/ru/m/tankz/game/NetworkGame.hx b/src/client/haxe/ru/m/tankz/game/NetworkGame.hx index 736b7b5..2cabfe5 100644 --- a/src/client/haxe/ru/m/tankz/game/NetworkGame.hx +++ b/src/client/haxe/ru/m/tankz/game/NetworkGame.hx @@ -17,6 +17,7 @@ class NetworkGame extends Game { this.network = network; this.controlFactory = new NetworkControlFactory(); network.gameEventSignal.connect(onGameEventProto); + network.stateSignal.connect(onConnectionState); } private function onGameEventProto(game:GameEventResponse):Void { @@ -26,6 +27,16 @@ class NetworkGame extends Game { gameEventSignal.emit(event); } + private function onConnectionState(state:ConnectionState):Void { + switch state { + case ONLINE(user): + if (network.game != null) { + network.joinGame(network.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) { @@ -37,5 +48,6 @@ class NetworkGame extends Game { override public function dispose():Void { super.dispose(); network.gameEventSignal.disconnect(onGameEventProto); + network.stateSignal.disconnect(onConnectionState); } } diff --git a/src/client/haxe/ru/m/tankz/network/NetworkManager.hx b/src/client/haxe/ru/m/tankz/network/NetworkManager.hx index 3c95b17..2b9db79 100644 --- a/src/client/haxe/ru/m/tankz/network/NetworkManager.hx +++ b/src/client/haxe/ru/m/tankz/network/NetworkManager.hx @@ -47,7 +47,11 @@ class NetworkManager { @:provide private var connection:ClientConnection; @:provide private var storage:MultiplayerStorage; + private var reconnectTimer:Timer; + private var reconnectDelay:Int; + public function new() { + reconnectDelay = 500; stateSignal = new Signal(); listGameSignal = new Signal(); gameSignal = new Signal(); @@ -56,10 +60,7 @@ class NetworkManager { updateState(OFFLINE); connection.handler.connect(onConnectionEvent); connection.receiveHandler.connect(onResponse); - var user = storage.user; - if (user != null) { - login(user.name, user.uuid); - } + connect(); } private function updateState(value:ConnectionState):Void { @@ -68,17 +69,12 @@ class NetworkManager { } public function login(name:String, uuid:String = null):Void { - updateState(CONNECT); - connection.connect().then(function(c:ClientConnection) { - updateState(LOGIN); - c.send(new Request().setLogin( - new LoginRequest() - .setUuid(uuid) - .setName(name) - )); - }).catchError(function(error) { - updateState(ERROR(error)); - }); + updateState(LOGIN); + connection.send(new Request().setLogin( + new LoginRequest() + .setUuid(uuid) + .setName(name) + )); } public function logout():Void { @@ -93,8 +89,8 @@ class NetworkManager { connection.send(new Request().setCreateGame(new CreateGameRequest().setType(type).setLevel(level))); } - public function joinGame(gameId:Int):Void { - connection.send(new Request().setJoinGame(new JoinGameRequest().setGameId(gameId))); + public function joinGame(gameId:Int, restore:Bool = false):Void { + connection.send(new Request().setJoinGame(new JoinGameRequest().setGameId(gameId).setRestore(restore))); } public function leaveGame():Void { @@ -111,18 +107,39 @@ class NetworkManager { ))); } + private function connect():Void { + if (reconnectTimer != null) { + reconnectTimer.stop(); + reconnectTimer = null; + } + reconnectTimer = null; + updateState(CONNECT); + connection.connect().catchError(function(error) {}); + } + + private function reconnect():Void { + reconnectDelay = Std.int(Math.min(reconnectDelay * 2, 10000)); + if (reconnectTimer == null) { + reconnectTimer = Timer.delay(connect, reconnectDelay); + } + } + private function onConnectionEvent(event:ConnectionEvent):Void { updateState(switch event { - case CONNECTED: - L.d('Network', '$event'); - CONNECTED; - case DISCONNECTED: - L.d('Network', '$event'); - OFFLINE; - case ERROR(error): - L.e('Network', '$error', error); - ERROR(error); + case CONNECTED: CONNECTED; + case DISCONNECTED: OFFLINE; + case ERROR(error): ERROR(error); }); + switch event { + case CONNECTED: + reconnectDelay = 500; + var user = storage.user; + if (user != null) { + login(user.name, user.uuid); + } + case DISCONNECTED | ERROR(_): + reconnect(); + } } private function onResponse(packet:Response):Void { diff --git a/src/client/haxe/ru/m/tankz/view/ClientView.hx b/src/client/haxe/ru/m/tankz/view/ClientView.hx index b22bfdb..541a33b 100644 --- a/src/client/haxe/ru/m/tankz/view/ClientView.hx +++ b/src/client/haxe/ru/m/tankz/view/ClientView.hx @@ -3,18 +3,30 @@ package ru.m.tankz.view; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import haxework.resources.IResources; +import haxework.view.ButtonView; import haxework.view.frame.FrameSwitcher; +import haxework.view.LabelView; +import haxework.view.VGroupView; +import ru.m.tankz.network.NetworkManager; import ru.m.tankz.sound.SoundManager; +import ru.m.tankz.view.popup.LoginPopup; -@:template class ClientView extends FrameSwitcher { +@:template class ClientView extends VGroupView { + @:view("switcher") var switcherView:FrameSwitcher; + @:view var username:LabelView; + @:view("login") var loginButton:ButtonView; + @:view("logout") var logoutButton:ButtonView; + @:provide var network:NetworkManager; @:provide var resources:IResources; @:provide var switcher:FrameSwitcher; @:provide var soundManager:SoundManager; public function init():Void { resources.text.put('version', '${Const.VERSION}'); - switcher = this; + switcher = switcherView; + network.stateSignal.connect(onConnectionState); + onConnectionState(network.state); } public function launch():Void { @@ -22,11 +34,45 @@ import ru.m.tankz.sound.SoundManager; content.stage.addEventListener(KeyboardEvent.KEY_UP, function(event:KeyboardEvent):Void { switch event.keyCode { case Keyboard.ESCAPE: - change(StartFrame.ID); + switcher.change(StartFrame.ID); case Keyboard.M: soundManager.mute = !soundManager.mute; } }); - change(StartFrame.ID); + switcher.change(StartFrame.ID); + } + + private function onConnectionState(state:ConnectionState):Void { + L.d("ClientView", 'onConnectionState: ${state}'); + switch state { + case ONLINE(user): + username.text = user.name; + logoutButton.visible = true; + loginButton.visible = false; + case CONNECTED: + username.text = ""; + logoutButton.visible = false; + loginButton.visible = true; + case ERROR(error): + L.e("ClientView", 'onConnectionState: ERROR', error); + case _: + username.text = ""; + logoutButton.visible = false; + loginButton.visible = false; + } + } + + private function login():Void { + LoginPopup.instance.show().then(function(user:User):Void { + L.d("Login", 'user: $user'); + }); + } + + private function logout():Void { + network.logout(); + } + + private function close():Void { + switcher.change(StartFrame.ID); } } diff --git a/src/client/haxe/ru/m/tankz/view/ClientView.yaml b/src/client/haxe/ru/m/tankz/view/ClientView.yaml index b648fdf..b1152f8 100755 --- a/src/client/haxe/ru/m/tankz/view/ClientView.yaml +++ b/src/client/haxe/ru/m/tankz/view/ClientView.yaml @@ -1,21 +1,51 @@ --- -$type: haxework.view.frame.FrameSwitcher -geometry.size.stretch: true -skinId: dark views: - - id: start - $type: ru.m.tankz.view.StartFrame - - id: level - $type: ru.m.tankz.view.LevelFrame - - id: game - $type: ru.m.tankz.view.GameFrame - - id: result - $type: ru.m.tankz.view.ResultFrame - - id: settings - $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 + - $type: haxework.view.frame.FrameSwitcher + id: switcher + geometry.size.stretch: true + skinId: dark + views: + - id: start + $type: ru.m.tankz.view.StartFrame + - id: level + $type: ru.m.tankz.view.LevelFrame + - id: game + $type: ru.m.tankz.view.GameFrame + - id: result + $type: ru.m.tankz.view.ResultFrame + - id: settings + $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 + - $type: haxework.view.HGroupView + skinId: panel + layout.margin: 10 + views: + - id: settings + $type: haxework.view.ButtonView + skinId: button.settings + +onPress: $code:switcher.change('settings') + - $type: haxework.view.SpriteView + geometry.size.width: 50% + - id: username + $type: haxework.view.LabelView + skinId: text + - id: login + $type: haxework.view.ButtonView + skinId: button.login + +onPress: $code:login() + - id: logout + $type: haxework.view.ButtonView + skinId: button.logout + +onPress: $code:logout() + visible: false + - $type: haxework.view.SpriteView + geometry.size.width: 50% + - id: close + $type: haxework.view.ButtonView + skinId: button.close + +onPress: $code:close() diff --git a/src/client/haxe/ru/m/tankz/view/GameFrame.yaml b/src/client/haxe/ru/m/tankz/view/GameFrame.yaml index 0b091b8..0e8d03f 100644 --- a/src/client/haxe/ru/m/tankz/view/GameFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/GameFrame.yaml @@ -5,10 +5,3 @@ views: views: - id: game $type: ru.m.tankz.view.game.GameView -# - $type: haxework.view.HGroupView -# skinId: panel -# views: -# - id: close -# $type: haxework.view.ButtonView -# skinId: button.close -# +onPress: $code:close() diff --git a/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml b/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml index afa1fd2..1b22dc1 100644 --- a/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/LevelFrame.yaml @@ -16,9 +16,3 @@ views: factory: $this:levelViewFactory +onItemSelect: $this:onLevelSelect geometry.padding: 10 - - $type: haxework.view.HGroupView - skinId: panel - views: - - $type: haxework.view.ButtonView - skinId: button.close - +onPress: $code:switcher.change('start') diff --git a/src/client/haxe/ru/m/tankz/view/RecordFrame.hx b/src/client/haxe/ru/m/tankz/view/RecordFrame.hx index 93dfda6..1bb919c 100644 --- a/src/client/haxe/ru/m/tankz/view/RecordFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/RecordFrame.hx @@ -25,8 +25,4 @@ import ru.m.tankz.storage.RecordStorage; private function onRecordSelect(item:IListItemView):Void { } - - private function close() { - switcher.change(StartFrame.ID); - } } diff --git a/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml b/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml index a666cf7..9608a14 100644 --- a/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/RecordFrame.yaml @@ -16,9 +16,3 @@ views: scroll: $type: haxework.view.list.VScrollBarView skinId: scroll - - $type: haxework.view.HGroupView - skinId: panel - views: - - $type: haxework.view.ButtonView - skinId: button.close - +onPress: $code:close() diff --git a/src/client/haxe/ru/m/tankz/view/ResultFrame.hx b/src/client/haxe/ru/m/tankz/view/ResultFrame.hx index f8378f6..c403787 100644 --- a/src/client/haxe/ru/m/tankz/view/ResultFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/ResultFrame.hx @@ -14,7 +14,6 @@ import ru.m.tankz.view.common.LifeView; public static var ID(default, never):String = "result"; @:view("result") var resultView:DataView; - @:view("next") var nextButton:ButtonView; @:view("level") var levelLabel:LabelView; @:provide var frames:FrameSwitcher; @@ -37,7 +36,6 @@ import ru.m.tankz.view.common.LifeView; public function onShow() { resultView.data = Lambda.array(state.players); levelLabel.text = 'Level ${state.levelId}'; - nextButton.visible = nextState != null; } private function next() { diff --git a/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml b/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml index 0f7da73..64a0b04 100644 --- a/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/ResultFrame.yaml @@ -14,16 +14,3 @@ views: $type: haxework.view.layout.VerticalLayout hAlign: right margin: 10 - - $type: haxework.view.HGroupView - skinId: panel - views: - - id: close - $type: haxework.view.ButtonView - skinId: button.close - +onPress: $code:close() - - $type: haxework.view.SpriteView - geometry.size.width: 100% - - id: next - $type: haxework.view.ButtonView - skinId: button.next - +onPress: $code:next() diff --git a/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx b/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx index fd45dca..8d143de 100644 --- a/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/SettingsFrame.hx @@ -1,11 +1,7 @@ package ru.m.tankz.view; -import haxework.view.frame.FrameSwitcher; import haxework.view.VGroupView; @:template class SettingsFrame extends VGroupView { - public static var ID(default, never):String = "settings"; - - @:provide var switcher:FrameSwitcher; } diff --git a/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml b/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml index ffb1c58..9f46d1b 100644 --- a/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/SettingsFrame.yaml @@ -13,9 +13,3 @@ views: controlIndex: 0 - $type: ru.m.tankz.view.settings.SettingsEditor controlIndex: 1 - - $type: haxework.view.HGroupView - skinId: panel - views: - - $type: haxework.view.ButtonView - skinId: button.close - +onPress: $code:switcher.change('start') diff --git a/src/client/haxe/ru/m/tankz/view/StartFrame.hx b/src/client/haxe/ru/m/tankz/view/StartFrame.hx index bc0b4fa..bdb1427 100644 --- a/src/client/haxe/ru/m/tankz/view/StartFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/StartFrame.hx @@ -1,12 +1,12 @@ package ru.m.tankz.view; -import haxework.view.ButtonView; -import haxework.view.LabelView; import haxework.view.frame.FrameSwitcher; 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.popup.FontPopup; import ru.m.tankz.view.popup.LoginPopup; @@ -14,54 +14,34 @@ import ru.m.tankz.view.popup.LoginPopup; public static var ID(default, never):String = "start"; - @:view var username:LabelView; - @:view("login") var loginButton:ButtonView; - @:view("logout") var logoutButton:ButtonView; - @:view("network") var networkButton:ButtonView; - @:provide var state:GameState; @:provide var switcher:FrameSwitcher; @:provide var network:NetworkManager; private var fontPopup:FontPopup; - public function onShow():Void { - onConnectionState(network.state); - network.stateSignal.connect(onConnectionState); - } - - public function onHide():Void { - network.stateSignal.disconnect(onConnectionState); - } - - private function onConnectionState(state:ConnectionState):Void { - trace("state", state); - setUser(switch state { - case ONLINE(user): user; - case _: null; - }); - } - - private function setUser(value:User):Void { - username.text = value == null ? "" : value.name; - loginButton.visible = value == null; - logoutButton.visible = value != null; - networkButton.disabled = value == null; - } - private function startGame(type:GameType):Void { state = new GameState(type); switcher.change(LevelFrame.ID); } - private function login():Void { - LoginPopup.instance.show().then(function(user:User):Void { - L.d("Login", 'user: $user'); - }); - } - - private function logout():Void { - network.logout(); + private function startNetwork():Void { + switch network.state { + case ONLINE(user): + if (network.game != null) { + switcher.change(GameRoomFrame.ID); + network.joinGame(network.game.id, true); + } else { + switcher.change(GameListFrame.ID); + } + case CONNECTED: + LoginPopup.instance.show().then(function(user):Void { + if (user != null) { + switcher.change(GameListFrame.ID); + } + }); + case _: + } } private function choiceFont():Void { diff --git a/src/client/haxe/ru/m/tankz/view/StartFrame.yaml b/src/client/haxe/ru/m/tankz/view/StartFrame.yaml index 9d6b5f9..1a65708 100644 --- a/src/client/haxe/ru/m/tankz/view/StartFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/StartFrame.yaml @@ -28,31 +28,9 @@ views: - id: network $type: haxework.view.ButtonView skinId: button - +onPress: $code:switcher.change('game_list') + +onPress: $code:startNetwork() text: Network - disabled: true - - $type: haxework.view.HGroupView - skinId: panel - views: - - id: settings - $type: haxework.view.ButtonView - skinId: button.settings - +onPress: $code:switcher.change('settings') - - $type: haxework.view.SpriteView - geometry.size.width: 100% - - id: username - $type: haxework.view.LabelView - skinId: text - geometry.margin.right: 10 - - id: login - $type: haxework.view.ButtonView - skinId: button.login - +onPress: $code:login() - - id: logout - $type: haxework.view.ButtonView - skinId: button.logout - +onPress: $code:logout() - visible: false + #disabled: true - $type: haxework.view.LabelView geometry.hAlign: right geometry.vAlign: top diff --git a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx b/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx index 2be2152..b865b39 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/network/GameListFrame.hx @@ -17,27 +17,18 @@ import ru.m.tankz.proto.core.GameProto; public function onShow():Void { network.listGameSignal.connect(onGameList); network.gameSignal.connect(onGame); - network.stateSignal.connect(onState); network.listGame(); } public function onHide():Void { network.listGameSignal.disconnect(onGameList); network.gameSignal.disconnect(onGame); - network.stateSignal.disconnect(onState); } private function create():Void { network.createGame("classic", 0); } - private function onState(state:ConnectionState):Void { - switch state { - case ONLINE(_): - case _: switcher.change(StartFrame.ID); - } - } - private function onGameList(data:Array):Void { games.data = data; } @@ -49,6 +40,6 @@ import ru.m.tankz.proto.core.GameProto; } private function selectGame(game:GameProto):Void { - network.joinGame(game.id); + network.joinGame(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/GameListFrame.yaml index 9f75d9c..c1054c2 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameListFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/GameListFrame.yaml @@ -19,9 +19,3 @@ views: factory: $code:ru.m.tankz.view.network.GameItemView.factory geometry.margin: 10 +onItemSelect: $code:function(item) selectGame(item.data) - - $type: haxework.view.HGroupView - skinId: panel - views: - - $type: haxework.view.ButtonView - skinId: button.close - +onPress: $code:switcher.change('start') diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx index fc4cc5e..73ce966 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx +++ b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.hx @@ -30,7 +30,9 @@ import ru.m.tankz.proto.core.PlayerProto; info.text = '[${game.creator.name}] ${game.type} ${game.level} (${game.players.length})'; players.data = game.players; if (game.state == GameStateProto.STARTED) { - this.game = new NetworkGame(network); + if (this.game == null) { + this.game = new NetworkGame(network); + } switcher.change(GameFrame.ID); } } else { @@ -41,25 +43,13 @@ import ru.m.tankz.proto.core.PlayerProto; public function onShow():Void { refresh(network.game); network.gameSignal.connect(onGame); - network.stateSignal.connect(onState); } public function onHide():Void { network.gameSignal.disconnect(onGame); - network.stateSignal.disconnect(onState); - // ToDo: - //network.leaveGame(); } private function onGame(game:GameProto):Void { refresh(game); } - - private function onState(state:ConnectionState):Void { - switch state { - case ONLINE(_): - case _: switcher.change(StartFrame.ID); - } - } - } diff --git a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml index d996f34..7ec4319 100644 --- a/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml +++ b/src/client/haxe/ru/m/tankz/view/network/GameRoomFrame.yaml @@ -23,9 +23,3 @@ views: $type: haxework.view.list.VListView geometry.size.stretch: true factory: $code:ru.m.tankz.view.network.PlayerItemView.factory - - $type: haxework.view.HGroupView - skinId: panel - views: - - $type: haxework.view.ButtonView - skinId: button.close - +onPress: $code:network.leaveGame() diff --git a/src/common/haxe/ru/m/connect/desktop/DesktopConnection.hx b/src/common/haxe/ru/m/connect/desktop/DesktopConnection.hx index 2048080..b264ebc 100644 --- a/src/common/haxe/ru/m/connect/desktop/DesktopConnection.hx +++ b/src/common/haxe/ru/m/connect/desktop/DesktopConnection.hx @@ -38,8 +38,10 @@ class DesktopConnection extends BaseConnection { connected = true; reader = Thread.create(_read); connectDeferred.resolve(this); + handler.emit(ConnectionEvent.CONNECTED); } } catch (error:Dynamic) { + handler.emit(ConnectionEvent.ERROR(error)); Timer.delay(function() connectDeferred.throwError(error), 1); } return connectDeferred.promise(); diff --git a/src/common/haxe/ru/m/connect/js/JsConnection.hx b/src/common/haxe/ru/m/connect/js/JsConnection.hx index 5e11cd1..51aad1d 100644 --- a/src/common/haxe/ru/m/connect/js/JsConnection.hx +++ b/src/common/haxe/ru/m/connect/js/JsConnection.hx @@ -49,7 +49,7 @@ class JsConnection extends BaseConnection { } private function onError(event:Dynamic):Void { - socket.close(); + socket.close(1000); connected = false; handler.emit(ConnectionEvent.ERROR(event)); } @@ -67,18 +67,25 @@ class JsConnection extends BaseConnection { } private function onSocketData(event:Dynamic):Void { + var packet:I = null; try { var bytes = Bytes.ofData(event.data); - var packet:I = PacketUtil.fromBytes(bytes, queue.packetClass); - receive(packet); + packet = PacketUtil.fromBytes(bytes, queue.packetClass); } catch (error:Dynamic) { - handler.emit(ConnectionEvent.ERROR(event)); + handler.emit(ConnectionEvent.ERROR(error)); + } + if (packet != null) { + receive(packet); } } override public function send(packet:O):Void { - super.send(packet); - var bytes = PacketUtil.toBytes(packet); - socket.send(bytes.getData()); + if (connected) { + super.send(packet); + var bytes = PacketUtil.toBytes(packet); + socket.send(bytes.getData()); + } else { + L.w("Connection", "closed"); + } } } diff --git a/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx b/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx index 904fe8f..7093a55 100644 --- a/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx +++ b/src/common/haxe/ru/m/tankz/game/EntityBuilder.hx @@ -48,7 +48,7 @@ class EntityBuilder { var playerConfig = config.getPlayer(playerId); var tankConfig = config.getTank(type); var tank = new Tank(++entityId, buildRect(point, tankConfig.width, tankConfig.height), playerId, tankConfig); - tank.color = color == null ? config.getColor(playerId) : color; + tank.color = color == null || color.zero ? config.getColor(playerId) : color; if (!bonusOff) { tank.bonus = Math.random() < playerConfig.bonus; } diff --git a/src/common/haxe/ru/m/tankz/game/EventUtil.hx b/src/common/haxe/ru/m/tankz/game/EventUtil.hx index 78993c9..5d20500 100644 --- a/src/common/haxe/ru/m/tankz/game/EventUtil.hx +++ b/src/common/haxe/ru/m/tankz/game/EventUtil.hx @@ -1,11 +1,13 @@ package ru.m.tankz.game; -import ru.m.tankz.core.EntityType.EntityTypeResolver; -import ru.m.tankz.core.Entity; +import ru.m.tankz.core.Bonus; +import ru.m.tankz.core.Bullet; import ru.m.tankz.core.Eagle; +import ru.m.tankz.core.Entity; +import ru.m.tankz.core.EntityType; import ru.m.tankz.core.Tank; -import ru.m.tankz.map.Brick; import ru.m.tankz.game.GameEvent; +import ru.m.tankz.map.Brick; import ru.m.tankz.map.LevelMap; class EventUtil { @@ -20,15 +22,27 @@ class EventUtil { type: item.config.type, } }); - return GameEvent.SPAWN(BRICK(bricks)); + return SPAWN(BRICK(bricks)); + } + + public static function buildCellsDestroyed(map:LevelMap):Array { + var result = []; + for (brick in map.bricks) { + for (cell in brick.cells) { + if (cell.destroyed) { + result.push(DESTROY(CELL(brick.id, cell.cellX - brick.cellX * 2, cell.cellY - brick.cellY * 2, {tankId: -1}))); + } + } + } + return result; } public static function buildEagleSpawn(eagle:Eagle):GameEvent { - return GameEvent.SPAWN(EAGLE(eagle.id, eagle.rect, eagle.team)); + return SPAWN(EAGLE(eagle.id, eagle.rect, eagle.team)); } public static function buildTankSpawn(tank:Tank):GameEvent { - return GameEvent.SPAWN(TANK(tank.id, tank.rect.clone(), tank.playerId, { + return SPAWN(TANK(tank.id, tank.rect.clone(), tank.playerId, { type:tank.config.type, hits:tank.hits, bonus:tank.bonus, @@ -36,14 +50,22 @@ class EventUtil { })); } + public static function buildBonusSpawn(bonus:Bonus):GameEvent { + return SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type)); + } + + public static function buildBulletSpawn(bullet:Bullet):GameEvent { + return SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing)); + } + public static function buildMove(entity:Entity):GameEvent { return switch EntityTypeResolver.of(entity) { case EAGLE(eagle): - GameEvent.MOVE(EAGLE(entity.id, entity.rect.position)); + MOVE(EAGLE(entity.id, entity.rect.position)); case TANK(tank): - GameEvent.MOVE(TANK(entity.id, entity.rect.position)); + MOVE(TANK(entity.id, entity.rect.position)); case BULLET(bullet): - GameEvent.MOVE(BULLET(entity.id, entity.rect.position)); + MOVE(BULLET(entity.id, entity.rect.position)); case _: null; } diff --git a/src/common/haxe/ru/m/tankz/game/GameRunner.hx b/src/common/haxe/ru/m/tankz/game/GameRunner.hx index ca73ca8..851d953 100644 --- a/src/common/haxe/ru/m/tankz/game/GameRunner.hx +++ b/src/common/haxe/ru/m/tankz/game/GameRunner.hx @@ -222,7 +222,7 @@ class GameRunner extends Game implements EngineListener { } var bonus = builder.buildBonus(point, type); engine.spawn(bonus); - gameEventSignal.emit(SPAWN(BONUS(bonus.id, bonus.rect.clone(), bonus.config.type))); + gameEventSignal.emit(EventUtil.buildBonusSpawn(bonus)); } private inline function alienTank(team:TeamId):Tank->Bool { @@ -313,7 +313,7 @@ class GameRunner extends Game implements EngineListener { bullet.tank = tank; bullet.move(bullet.rect.direction); engine.spawn(bullet); - gameEventSignal.emit(SPAWN(BULLET(bullet.id, bullet.rect.clone(), bullet.playerId, bullet.config.piercing))); + gameEventSignal.emit(EventUtil.buildBulletSpawn(bullet)); } case ACTION(tankId, MOVE(direction)): engine.move(tankId, direction); diff --git a/src/common/proto/pack.proto b/src/common/proto/pack.proto index dd4c86f..ac70775 100644 --- a/src/common/proto/pack.proto +++ b/src/common/proto/pack.proto @@ -46,11 +46,13 @@ message CreateGameResponse { // 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 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 02c572d..d8a62e0 100644 --- a/src/server/haxe/ru/m/tankz/server/game/GameManager.hx +++ b/src/server/haxe/ru/m/tankz/server/game/GameManager.hx @@ -62,6 +62,9 @@ class _GameListener implements GameListener { var game = new ServerGame(proto); game.joinUser(user); 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; createSignal.emit(game); @@ -88,9 +91,9 @@ class _GameListener implements GameListener { } public function leave(user:UserProto):Void { - if (gamesByCreator.exists(user.uuid)) { + /*if (gamesByCreator.exists(user.uuid)) { delete(gamesByCreator[user.uuid].proto.id); - } else if (gamesByUser.exists(user.uuid)) { + } else*/ if (gamesByUser.exists(user.uuid)) { var game = gamesByUser[user.uuid]; game.leaveUser(user); changeSignal.emit(game, LEAVE(user)); 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 51b8e5a..ab764e8 100644 --- a/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx +++ b/src/server/haxe/ru/m/tankz/server/game/ServerGame.hx @@ -1,12 +1,16 @@ package ru.m.tankz.server.game; 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.server.control.ServerControlFactory; +import ru.m.tankz.Type.PlayerId; class ServerGame extends GameRunner { @@ -19,10 +23,12 @@ class ServerGame extends GameRunner { this.proto = proto; } - public function joinUser(user:UserProto):Void { - var index = proto.players.length; - var teamId = "human"; // ToDo: - proto.players.push(new PlayerProto().setUser(user).setTeam(teamId).setIndex(index)); + public function joinUser(user:UserProto, playerId:PlayerId = null):Void { + leaveUser(user); + if (playerId == null) { + playerId = ["human", proto.players.length]; + } + proto.players.push(new PlayerProto().setUser(user).setTeam(playerId.team).setIndex(playerId.index)); } public function leaveUser(user:UserProto):Void { @@ -36,4 +42,21 @@ class ServerGame extends GameRunner { }); super.start(); } + + public function restore():Array { + var result = []; + result.push(EventUtil.buildBricksSpawn(engine.map)); + result = result.concat(EventUtil.buildCellsDestroyed(engine.map)); + for (entity in engine.entities) { + switch EntityTypeResolver.of(entity) { + case EAGLE(eagle): result.push(EventUtil.buildEagleSpawn(eagle)); + case TANK(tank): result.push(EventUtil.buildTankSpawn(tank)); + case BONUS(bonus): result.push(EventUtil.buildBonusSpawn(bonus)); + case BULLET(bullet): result.push(EventUtil.buildBulletSpawn(bullet)); + case CELL(_): + } + } + result.push(START(state)); + return result; + } } 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 09f5c99..e31d96f 100644 --- a/src/server/haxe/ru/m/tankz/server/session/GameSession.hx +++ b/src/server/haxe/ru/m/tankz/server/session/GameSession.hx @@ -1,5 +1,6 @@ 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; @@ -97,6 +98,12 @@ class GameSession extends ProtoSession implements GameManager } 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)))); + } + } // leave } else if (request.hasLeaveGame()) { gameManager.leave(user);