diff --git a/gulpfile.js b/gulpfile.js index 64434f4..ff03917 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -47,7 +47,7 @@ const config = new Project.Config({ `CompilationOption.set('build','${dateformat(new Date(), 'yyyy-mm-dd HH:MM:ss')}')`, ], flags: [ - //'proto_debug', + 'proto_debug', ] }); diff --git a/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx b/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx index 0a21ee1..b8f9268 100644 --- a/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx +++ b/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx @@ -60,6 +60,9 @@ class PuzzlezTheme extends Theme { register(new Style("icon.orange", [ "skin.color" => 0xcc5500, ])); + register(new Style("icon.green", [ + "skin.color" => 0x00ff00, + ])); register(new Style("icon.control", [ "geometry.hAlign" => HAlign.RIGHT, "geometry.vAlign" => VAlign.TOP, diff --git a/src/app/haxe/ru/m/puzzlez/net/Network.hx b/src/app/haxe/ru/m/puzzlez/net/Network.hx index b7e8692..e910398 100644 --- a/src/app/haxe/ru/m/puzzlez/net/Network.hx +++ b/src/app/haxe/ru/m/puzzlez/net/Network.hx @@ -10,26 +10,24 @@ import ru.m.puzzlez.core.Id; import ru.m.puzzlez.proto.core.User; import ru.m.puzzlez.proto.event.GameAction; import ru.m.puzzlez.proto.event.GameEvent; -import ru.m.puzzlez.proto.game.GameItem; +import ru.m.puzzlez.proto.game.GamePreset; import ru.m.puzzlez.proto.game.GameState; +import ru.m.puzzlez.proto.pack.AuthRequest; import ru.m.puzzlez.proto.pack.GameActionRequest; -import ru.m.puzzlez.proto.pack.GameCreateRequest; import ru.m.puzzlez.proto.pack.GameJoinRequest; -import ru.m.puzzlez.proto.pack.LoginRequest; +import ru.m.puzzlez.proto.pack.GameLeaveRequest; +import ru.m.puzzlez.proto.pack.GameListRequest; +import ru.m.puzzlez.proto.pack.GameListResponse; +import ru.m.puzzlez.proto.pack.NotificationResponse; import ru.m.puzzlez.proto.pack.Request; import ru.m.puzzlez.proto.pack.Response; @:provide class Network implements IDataIndex { - public var user(default, null):User; - public var userSignal(default, null):Signal = new Signal(); - - public var gameList(default, null):Array; - public var gameListSignal(default, null):Signal> = new Signal(); - - public var game(default, null):GameItem; - public var gameSignal(default, null):Signal = new Signal(); - - public var gameEventSignal(default, null):Signal = new Signal(); + public var userSignal:Signal = new Signal(); + public var notificationSignal:Signal = new Signal(); + public var listSignal:Signal = new Signal(); + public var joinSignal:Signal = new Signal(); + public var gameEventSignal:Signal = new Signal(); private var connection:IConnection; private var storage:SharedObjectStorage; @@ -37,41 +35,49 @@ import ru.m.puzzlez.proto.pack.Response; private static var USER_KEY = "user"; public function new() { - gameList = []; storage = new SharedObjectStorage("network/2"); - if (storage.exists(USER_KEY)) { - user = storage.read(USER_KEY); - } else { - user = new User().setName('Anonimus #${IdUtil.generate()}'); - storage.write(USER_KEY, user); - } connection = ConnectionFactory.buildClientConnection("127.0.0.1", 5000, Response); connection.handler.connect(onConnectionChange); connection.receiveHandler.connect(onReceivePacket); connection.connect().catchError(_ -> {}); } - public function login():Void { - connection.send(new Request().setLogin(new LoginRequest().setUser(user))); + private function restoreUser():User { + if (storage.exists(USER_KEY)) { + return storage.read(USER_KEY); + } else { + return new User().setName('Anonimus #${IdUtil.generate()}'); + } } - public function startGame(state:GameState):Void { - connection.send(new Request().setGameCreate(new GameCreateRequest().setImageId(state.preset.imageId))); + public function auth():Promise { + connection.send(new Request().setAuth(new AuthRequest().setUser(restoreUser()))); + return userSignal.next(); } - public function joinGame(state:GameState):Void { - connection.send(new Request().setGameJoin(new GameJoinRequest().setGameId(state.id))); + public function createGame(preset:GamePreset):Promise { + connection.send(new Request().setJoin(new GameJoinRequest().setPreset(preset))); + return joinSignal.next(); + } + + public function joinGame(gameId:String):Promise { + connection.send(new Request().setJoin(new GameJoinRequest().setGameId(gameId))); + return joinSignal.next(); + } + + public function leaveGame():Void { + connection.send(new Request().setLeave(new GameLeaveRequest())); } public function sendGameAction(action:GameAction):Void { - connection.send(new Request().setGameAction(new GameActionRequest().setActions([action]))); + connection.send(new Request().setAction(new GameActionRequest().setActions([action]))); } private function onConnectionChange(event:ConnectionEvent):Void { L.i("network", '${event}'); switch event { case CONNECTED: - login(); + auth().then(user -> storage.write(USER_KEY, user)); case DISCONNECTED: // case ERROR(error): @@ -80,34 +86,32 @@ import ru.m.puzzlez.proto.pack.Response; } private function onReceivePacket(packet:Response):Void { - if (packet.hasLogin()) { - user = packet.login.user; - storage.write(USER_KEY, user); - userSignal.emit(user); - } else if (packet.hasLogout()) { - user = null; - userSignal.emit(user); - } else if (packet.hasGameList()) { - gameList = packet.gameList.games; - gameListSignal.emit(gameList); - } else if (packet.hasGame()) { - game = packet.game.game; - gameSignal.emit(game); - } else if (packet.hasGameEvent()) { - for (event in packet.gameEvent.events) { - // ToDo: convert event? - //gameEventSignal.emit(Unserializer.run(event.event)); + if (packet.hasAuth()) { + userSignal.emit(packet.auth.user); + } else if (packet.hasNotification()) { + notificationSignal.emit(packet.notification); + } else if (packet.hasList()) { + listSignal.emit(packet.list); + } else if (packet.hasJoin()) { + joinSignal.emit(packet.join.game); + } else if (packet.hasEvent()) { + for (event in packet.event.events) { + gameEventSignal.emit(event); } } } public function getIndexPage(page:Page):Promise> { - // ToDo: return gameList - var data = { - page: page, - total: 1, - data: [new ImageId('asset', 'resources/image/raccoon.jpg')], - } - return Promise.promise(data); + connection.send(new Request().setList(new GameListRequest().setCount(page.count).setPage(page.index))); + return listSignal.next().then((list:GameListResponse) -> ({ + page: { + index: list.page, + count: list.count, + filter: null, + order: null, + }, + total: list.total, + data: list.games.map(item -> ImageId.fromString(item.preset.imageId)), + })); } } diff --git a/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx b/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx index e46ce5b..5c21f4f 100644 --- a/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx +++ b/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx @@ -1,11 +1,11 @@ package ru.m.puzzlez.net; +import ru.m.puzzlez.proto.event.GameStart; import hw.signal.Signal; import ru.m.puzzlez.core.IGame; import ru.m.puzzlez.proto.event.GameAction; import ru.m.puzzlez.proto.event.GameEvent; import ru.m.puzzlez.proto.game.GameState; -import ru.m.puzzlez.proto.game.GameStatus; class NetworkGame implements IGame { public var state(default, null):GameState; @@ -23,17 +23,13 @@ class NetworkGame implements IGame { } public function start():Void { + events.emit(new GameEvent().setStart(new GameStart().setState(state))); network.gameEventSignal.connect(onEvent); - switch state.status { - case GameStatus.READY: - network.startGame(state); - case _: - network.joinGame(state); - } } public function stop():Void { network.gameEventSignal.disconnect(onEvent); + network.leaveGame(); } public function dispose():Void { diff --git a/src/app/haxe/ru/m/puzzlez/render/Render.hx b/src/app/haxe/ru/m/puzzlez/render/Render.hx index 15e4101..6dc1ad0 100644 --- a/src/app/haxe/ru/m/puzzlez/render/Render.hx +++ b/src/app/haxe/ru/m/puzzlez/render/Render.hx @@ -35,7 +35,8 @@ class Render extends SpriteView implements IRender { private var playerId(get, never):PlayerId; private function get_playerId():PlayerId { - return network.user.hasUuid() ? network.user.uuid : "local"; + // ToDo: network user + return "local"; } private function get_scale():Float { diff --git a/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx b/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx index 11ce281..b15b3f6 100644 --- a/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx @@ -56,8 +56,11 @@ import ru.m.puzzlez.view.common.PresetView; } private function start(online:Bool = false):Void { - imageView.state.online = online; - switcher.change(GameFrame.ID, imageView.state); + if (online) { + network.createGame(imageView.state.preset).then(state -> switcher.change(GameFrame.ID, state)); + } else { + switcher.change(GameFrame.ID, imageView.state); + } } private function back():Void { diff --git a/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx b/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx index cbc3b1f..21489fa 100644 --- a/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx @@ -1,7 +1,5 @@ package ru.m.puzzlez.view; -import ru.m.puzzlez.proto.game.GameStatus; -import ru.m.puzzlez.net.Network; import hw.view.data.DataView; import hw.view.form.ButtonView; import hw.view.frame.FrameSwitcher; @@ -9,6 +7,9 @@ import hw.view.frame.FrameView; import ru.m.data.IDataSource; import ru.m.pixabay.PixabayApi; import ru.m.puzzlez.core.ImageListSource; +import ru.m.puzzlez.net.Network; +import ru.m.puzzlez.proto.game.GameStatus; +import ru.m.puzzlez.proto.pack.NotificationResponse; import ru.m.puzzlez.source.AssetSource; import ru.m.puzzlez.source.FileSource; import ru.m.puzzlez.source.PixabaySource; @@ -22,6 +23,7 @@ import ru.m.update.Updater; @:view var sources:DataView; @:view("load") var loadButton:ButtonView; @:view("complete") var completeButton:ButtonView; + @:view("network") var networkButton:ButtonView; @:view("update") var updateButton:ButtonView; @:provide var storage:ImageStorage; @@ -55,6 +57,13 @@ import ru.m.update.Updater; completeButton.text = 'Complete (${total})'; completeButton.disabled = total == 0; }); + network.notificationSignal.next().then(onNotification); + } + + private function onNotification(notification:NotificationResponse):Void { + var total = notification.games; + networkButton.text = 'Network (${total})'; + networkButton.disabled = total == 0; } override public function onShow(data:Dynamic):Void { @@ -65,6 +74,11 @@ import ru.m.update.Updater; updateButton.text = 'Update ${info.version}'; } }).catchError(error -> L.w('Update', 'failed: ${error}')); + network.notificationSignal.connect(onNotification); + } + + override public function onHide():Void { + network.notificationSignal.disconnect(onNotification); } private function sourceViewFactory(index:Int, source:ImageListSource):ButtonView { diff --git a/src/app/haxe/ru/m/puzzlez/view/common/ImageDataList.hx b/src/app/haxe/ru/m/puzzlez/view/common/ImageDataList.hx index bbebad3..e9f642d 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/ImageDataList.hx +++ b/src/app/haxe/ru/m/puzzlez/view/common/ImageDataList.hx @@ -1,5 +1,6 @@ package ru.m.puzzlez.view.common; +import ru.m.puzzlez.net.Network; import hw.view.data.DataView; import hw.view.form.ToggleButtonView; import hw.view.frame.FrameSwitcher; @@ -24,6 +25,7 @@ import ru.m.puzzlez.view.common.PuzzleImageView; @:provide var switcher:FrameSwitcher; @:provide var gameStorage:GameStorage; @:provide var imageStorage:ImageStorage; + @:provide var network:Network; public var data(default, set):DataPage; @@ -74,6 +76,8 @@ import ru.m.puzzlez.view.common.PuzzleImageView; gameStorage.delete(imageId).then(_ -> refresh()); } }); + case JOIN: + // ToDo: } } diff --git a/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.hx b/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.hx index 2b2b64e..f93748a 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.hx +++ b/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.hx @@ -1,5 +1,6 @@ package ru.m.puzzlez.view.common; +import ru.m.puzzlez.net.Network; import hw.view.data.DataView; import hw.view.form.ButtonView; import hw.view.form.LabelView; @@ -14,6 +15,7 @@ import ru.m.puzzlez.storage.ImageStorage; enum Action { CLEAN; REMOVE; + JOIN; } @:template class PuzzleImageView extends GroupView { @@ -42,14 +44,17 @@ enum Action { @:view("label") var labelView:LabelView; @:view("clean") var cleanButton:ButtonView; @:view("remove") var removeButton:ButtonView; + @:view("join") var joinButton:ButtonView; @:provide static var imageStorage:ImageStorage; @:provide static var gameStorage:GameStorage; + @:provide static var network:Network; private var loading:LoadingWrapper; public function new() { super(); cleanButton.visible = false; removeButton.visible = false; + joinButton.visible = false; loading = new LoadingWrapper(this); } @@ -73,6 +78,8 @@ enum Action { result.removeButton.visible = true; } }); + // ToDo: + result.joinButton.visible = false; return result; } } diff --git a/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.yaml b/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.yaml index 7211f42..03eebc1 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.yaml +++ b/src/app/haxe/ru/m/puzzlez/view/common/PuzzleImageView.yaml @@ -18,3 +18,8 @@ views: propagation: false style: icon.control.small.close.orange +onPress: ~emit(Action.CLEAN) + - id: join + $type: hw.view.form.ButtonView + propagation: false + style: icon.control.small.close.green + +onPress: ~emit(Action.JOIN) diff --git a/src/common/proto/event.proto b/src/common/proto/event.proto index 40d4770..a9b6175 100644 --- a/src/common/proto/event.proto +++ b/src/common/proto/event.proto @@ -26,16 +26,26 @@ message GameAction { ru.m.puzzlez.proto.core.Point position = 4; } +message GamePlayer { + ru.m.puzzlez.proto.core.User player = 1; + enum GamePlayerAction { + JOIN = 0; + LEAVE = 1; + } + GamePlayerAction action = 2; +} + message GameChange { - int32 partId = 1; - ru.m.puzzlez.proto.core.Point position = 2; - ru.m.puzzlez.proto.game.PartLocation location = 3; - string playerId = 4; + string playerId = 1; + int32 partId = 2; + ru.m.puzzlez.proto.core.Point position = 3; + ru.m.puzzlez.proto.game.PartLocation location = 4; } message GameEvent { int32 time = 1; oneof event { + GamePlayer player = 9; GameStart start = 10; GameComplete complete = 11; GameAction action = 12; diff --git a/src/common/proto/game.proto b/src/common/proto/game.proto index b18bf78..055173c 100644 --- a/src/common/proto/game.proto +++ b/src/common/proto/game.proto @@ -55,11 +55,7 @@ message GameState { string id = 1; GameStatus status = 2; GamePreset preset = 3; - repeated Part parts = 4; - bool online = 5; -} - -message GameItem { - GameState state = 2; - repeated ru.m.puzzlez.proto.core.User users = 3; + repeated ru.m.puzzlez.proto.core.User users = 4; + repeated Part parts = 5; + bool online = 6; } diff --git a/src/common/proto/pack.proto b/src/common/proto/pack.proto index 9ba4740..e8d2864 100644 --- a/src/common/proto/pack.proto +++ b/src/common/proto/pack.proto @@ -11,38 +11,47 @@ message ErrorResponse { string message = 2; } -message LoginRequest { +message NotificationResponse { + int32 games = 1; +} + +message AuthRequest { ru.m.puzzlez.proto.core.User user = 1; } -message LoginResponse { +message AuthResponse { ru.m.puzzlez.proto.core.User user = 1; } -message LogoutRequest {} - -message LogoutResponse {} - -message GameCreateRequest { - string imageId = 1; -} - message GameJoinRequest { - string gameId = 1; + oneof content { + ru.m.puzzlez.proto.game.GamePreset preset = 1; + string gameId = 2; + } } -message GameLeaveRequest {} +message GameJoinResponse { + ru.m.puzzlez.proto.game.GameState game = 1; +} + +message GameLeaveRequest { + +} + +message GameLeaveResponse { -message GameResponse { - ru.m.puzzlez.proto.game.GameItem game = 1; } message GameListRequest { - bool subscribe = 1; + int32 page = 1; + int32 count = 2; } message GameListResponse { - repeated ru.m.puzzlez.proto.game.GameItem games = 1; + int32 page = 1; + int32 count = 2; + int32 total = 3; + repeated ru.m.puzzlez.proto.game.GameState games = 4; } message GameActionRequest { @@ -54,31 +63,25 @@ message GameEventResponse { } message Request { + string rid = 1; oneof content { - LoginRequest login = 1; - LogoutRequest logout = 2; - - GameCreateRequest gameCreate = 10; - GameJoinRequest gameJoin = 11; - GameLeaveRequest gameLeave = 12; - - GameListRequest gameList = 20; - - GameActionRequest gameAction = 100; + AuthRequest auth = 10; + GameListRequest list = 20; + GameJoinRequest join = 30; + GameLeaveRequest leave = 40; + GameActionRequest action = 100; } } message Response { + string rid = 1; oneof content { - LoginResponse login = 1; - LogoutResponse logout = 2; - - GameResponse game = 10; - - GameListResponse gameList = 20; - - GameEventResponse gameEvent = 100; - - ErrorResponse error = 999; + AuthResponse auth = 10; + GameListResponse list = 20; + GameJoinResponse join = 30; + GameLeaveResponse leave = 40; + GameEventResponse event = 100; + NotificationResponse notification = 900; + ErrorResponse error = 1000; } } diff --git a/src/server/haxe/ru/m/puzzlez/GameSession.hx b/src/server/haxe/ru/m/puzzlez/GameSession.hx index db766aa..dfa0415 100644 --- a/src/server/haxe/ru/m/puzzlez/GameSession.hx +++ b/src/server/haxe/ru/m/puzzlez/GameSession.hx @@ -1,49 +1,53 @@ package ru.m.puzzlez; +import ru.m.puzzlez.proto.pack.GameListResponse; +import ru.m.puzzlez.proto.pack.GameListRequest; import hw.connect.session.ProtoSession; import hw.log.BaseLogger.LoggerUtil; -import ru.m.puzzlez.game.IGameManager; -import ru.m.puzzlez.game.ServerGame; +import ru.m.puzzlez.core.Game; +import ru.m.puzzlez.core.GameUtil; import ru.m.puzzlez.proto.core.User; +import ru.m.puzzlez.proto.event.GameAction; import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.event.gameplayer.GamePlayerAction; +import ru.m.puzzlez.proto.event.GamePlayer; +import ru.m.puzzlez.proto.game.GamePreset; +import ru.m.puzzlez.proto.pack.AuthRequest; +import ru.m.puzzlez.proto.pack.AuthResponse; import ru.m.puzzlez.proto.pack.ErrorResponse; import ru.m.puzzlez.proto.pack.GameEventResponse; -import ru.m.puzzlez.proto.pack.GameListResponse; -import ru.m.puzzlez.proto.pack.GameResponse; -import ru.m.puzzlez.proto.pack.LoginResponse; -import ru.m.puzzlez.proto.pack.LogoutResponse; +import ru.m.puzzlez.proto.pack.GameJoinResponse; +import ru.m.puzzlez.proto.pack.GameLeaveResponse; +import ru.m.puzzlez.proto.pack.NotificationResponse; import ru.m.puzzlez.proto.pack.Request; import ru.m.puzzlez.proto.pack.Response; import sys.net.Socket; -class GameSession extends ProtoSession implements GameManagerListener { +class GameSession extends ProtoSession { private static inline var TAG = "Session"; - @:provide static var gameManager:IGameManager; + public static var gamesById(default, null):Map = new Map(); + public static var sessionsById(default, null):Map = new Map(); public var user(default, null):User; - public var gameId(default, null):String; + public var game(default, null):Game; private var subscribed:Bool; private var tag(get, never):String; private function get_tag():String { - return '[${id}|${user == null ? '-' : user.name}|${gameId == null ? '-' : gameId}]'; + return '[${id}|${user == null ? '-' : user.uuid}|${game == null ? '-' : game.state.id}]'; } public function new(socket:Socket) { super(socket, Request); + sessionsById.set(id, this); } private function sendError(code:Int, message:String):Void { send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message))); } - private function listGame():GameListResponse { - var games = gameManager.games; - return new GameListResponse().setGames([for (game in games) game.proto]); - } - override public function send(packet:Response):Void { #if proto_debug L.d(TAG, '$tag send: ${packet}'); #end try { @@ -53,61 +57,71 @@ class GameSession extends ProtoSession implements GameManager } } - private function logout(leave:Bool = true):Void { - gameId = null; - gameManager.disconnect(this); - if (user != null && leave) { - gameManager.leave(user); - user = null; + private function auth(auth:AuthRequest):Void { + user = auth.hasUser() ? auth.user : new User().setUuid(IdUtil.generate()).setName('Anonim #${IdUtil.generate()}'); + send(new Response().setAuth(new AuthResponse().setUser(user))); + send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById)))); + } + + private function list(list:GameListRequest):Void { + var games = Lambda.array(gamesById); + var pageGames = games.slice(list.page * list.count, list.count); + send(new Response().setList(new GameListResponse() + .setPage(list.page) + .setCount(list.count) + .setTotal(games.length) + .setGames(pageGames.map(game -> game.state)) + )); + } + + private function create(preset:GamePreset):Void { + var game = new Game(GameUtil.buildState(preset).setOnline(true)); + game.start(); + gamesById.set(game.state.id, game); + join(game.state.id); + for (session in sessionsById) { + session.send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById)))); } } private function join(gameId:String):Void { - this.gameId = gameId; - gameManager.join(gameId, user); - var game = gameManager.gamesById[gameId]; + game = gamesById.get(gameId); + game.events.connect(onGameEvent); + game.events.emit(new GameEvent().setPlayer(new GamePlayer().setPlayer(user).setAction(GamePlayerAction.JOIN))); + send(new Response().setJoin(new GameJoinResponse().setGame(game.state))); + } + + private function leave():Void { + game.events.disconnect(onGameEvent); + game.events.emit(new GameEvent().setPlayer(new GamePlayer().setPlayer(user).setAction(GamePlayerAction.LEAVE))); + send(new Response().setLeave(new GameLeaveResponse())); + } + + private function action(action:GameAction):Void { + game.events.emit(new GameEvent().setAction(action)); } override private function onRequest(request:Request):Void { #if proto_debug L.d(TAG, '$tag onRequest: ${request}'); #end try { - if (!request.hasLogin() && user == null) { + if (!request.hasAuth() && user == null) { throw "Not Authorized"; } - // login - if (request.hasLogin()) { - user = new User() - .setUuid(request.login.user.uuid != null ? request.login.user.uuid : IdUtil.generate()) - .setName(request.login.user.name); - gameManager.connect(this); - send(new Response().setLogin(new LoginResponse().setUser(user))); - if (gameManager.gamesByUser.exists(user.uuid)) { - join(gameManager.gamesByUser[user.uuid].id); + if (request.hasAuth()) { + auth(request.auth); + } else if (request.hasList()) { + list(request.list); + } else if (request.hasJoin()) { + if (request.join.hasPreset()) { + create(request.join.preset); + } else if (request.join.hasGameId()) { + join(request.join.gameId); } - // logout - } else if (request.hasLogout()) { - logout(); - send(new Response().setLogout(new LogoutResponse())); - // game - } else if (request.hasGameCreate()) { - var game = gameManager.create(user, request.gameCreate.imageId); - gameId = game.id; - send(new Response().setGame(new GameResponse().setGame(game.proto))); - } else if (request.hasGameJoin()) { - join(request.gameJoin.gameId); - } else if (request.hasGameLeave()) { - gameManager.leave(user); - // game list - } else if (request.hasGameList()) { - subscribed = request.gameList.subscribe; - if (subscribed) { - send(new Response().setGameList(listGame())); - } - } else if (request.hasGameAction()) { - if (gameManager.gamesById.exists(gameId)) { - for (action in request.gameAction.actions) { - gameManager.gamesById[gameId].events.emit(new GameEvent().setAction(action)); - } + } else if (request.hasLeave()) { + leave(); + } else if (request.hasAction()) { + for (action in request.action.actions) { + this.action(action); } } } catch (error:Dynamic) { @@ -116,49 +130,18 @@ class GameSession extends ProtoSession implements GameManager } } + private function onGameEvent(event:GameEvent):Void { + send(new Response().setEvent(new GameEventResponse().setEvents([event]))); + } + override public function disconnect():Void { L.d(TAG, '$tag disconnect'); - logout(false); + if (game != null) { + leave(); + game = null; + } + user = null; + sessionsById.remove(id); super.disconnect(); } - - public function onCreate(game:ServerGame):Void { - if (subscribed) { - send(new Response().setGameList(listGame())); - } - } - - public function onChange(game:ServerGame, change:GameChange):Void { - if (gameId == game.id) { - switch change { - case LEAVE(user): - if (user.uuid == this.user.uuid) { - gameId = null; - send(new Response().setGame(new GameResponse())); - return; - } - case _: - } - send(new Response().setGame(new GameResponse().setGame(game.proto))); - } - if (subscribed) { - send(new Response().setGameList(listGame())); - } - } - - public function onDelete(game:ServerGame):Void { - if (gameId == game.id) { - gameId = null; - send(new Response().setGame(new GameResponse())); - } - if (subscribed) { - send(new Response().setGameList(listGame())); - } - } - - public function onEvent(game:ServerGame, event:GameEvent):Void { - if (gameId == game.id) { - send(new Response().setGameEvent(new GameEventResponse().setEvents([event]))); - } - } } diff --git a/src/server/haxe/ru/m/puzzlez/game/GameListener.hx b/src/server/haxe/ru/m/puzzlez/game/GameListener.hx deleted file mode 100644 index 7cb53df..0000000 --- a/src/server/haxe/ru/m/puzzlez/game/GameListener.hx +++ /dev/null @@ -1,4 +0,0 @@ -package ru.m.puzzlez.game; - -interface GameListener { -} diff --git a/src/server/haxe/ru/m/puzzlez/game/GameManager.hx b/src/server/haxe/ru/m/puzzlez/game/GameManager.hx deleted file mode 100644 index c16a16c..0000000 --- a/src/server/haxe/ru/m/puzzlez/game/GameManager.hx +++ /dev/null @@ -1,99 +0,0 @@ -package ru.m.puzzlez.game; - -import ru.m.puzzlez.core.Id; -import ru.m.puzzlez.game.IGameManager; -import ru.m.puzzlez.proto.core.User; -import ru.m.puzzlez.proto.event.GameEvent; -import ru.m.puzzlez.proto.game.GameItem; -import ru.m.puzzlez.proto.game.GamePreset; -import ru.m.puzzlez.proto.game.GameState; - -class _GameListener implements GameListener { - private var game:ServerGame; - private var dispatcher:IGameManager; - - public function new(game:ServerGame, dispatcher:IGameManager) { - this.game = game; - this.dispatcher = dispatcher; - } - - public function onGameEvent(event:GameEvent):Void { - dispatcher.dispatchEvent(game, event); - if (event.hasComplete()) { - dispatcher.delete(game.id); - dispose(); - } - } - - public function dispose():Void { - game.disconnect(this); - game = null; - dispatcher = null; - } -} - -@:dispatcher(GameManagerListener) class GameManager implements IGameManager { - public var games(default, null):Array; - public var gamesById(default, null):Map; - public var gamesByUser(default, null):Map; - - public function new() { - games = []; - gamesById = new Map(); - gamesByUser = new Map(); - } - - public function create(user:User, imageId:ImageId):ServerGame { - var gameProto = new GameItem().setState( - new GameState() - .setId(IdUtil.generate()) - .setPreset(new GamePreset().setImageId(imageId)) - ); - var game = new ServerGame(gameProto); - games.push(game); - gamesById[game.id] = game; - createSignal.emit(game); - join(game.id, user); - return game; - } - - public function join(gameId:String, user:User):Void { - if (gamesById.exists(gameId)) { - var game = gamesById[gameId]; - game.join(user); - gamesByUser[user.uuid] = game; - changeSignal.emit(game, JOIN(user)); - } - } - - public function delete(gameId:String):Void { - if (gamesById.exists(gameId)) { - var game = gamesById[gameId]; - games.remove(game); - gamesById.remove(game.id); - deleteSignal.emit(game); - } - } - - public function leave(user:User):Void { - if (gamesByUser.exists(user.uuid)) { - var game = gamesByUser[user.uuid]; - gamesByUser.remove(user.uuid); - game.leave(user); - changeSignal.emit(game, LEAVE(user)); - } - } - - public function start(gameId:String):Void { - if (gamesById.exists(gameId)) { - var game:ServerGame = gamesById[gameId]; - changeSignal.emit(game, START); - game.connect(new _GameListener(game, this)); - game.start(); - } - } - - public function dispatchEvent(game:ServerGame, event:GameEvent):Void { - eventSignal.emit(game, event); - } -} diff --git a/src/server/haxe/ru/m/puzzlez/game/IGameManager.hx b/src/server/haxe/ru/m/puzzlez/game/IGameManager.hx deleted file mode 100644 index a8c94f7..0000000 --- a/src/server/haxe/ru/m/puzzlez/game/IGameManager.hx +++ /dev/null @@ -1,41 +0,0 @@ -package ru.m.puzzlez.game; - -import hw.signal.Signal; -import ru.m.puzzlez.core.Id; -import ru.m.puzzlez.proto.core.User; -import ru.m.puzzlez.proto.event.GameEvent; - -enum GameChange { - JOIN(user:User); - LEAVE(user:User); - START(); -} - -interface GameManagerListener { - public function onCreate(game:ServerGame):Void; - public function onChange(game:ServerGame, change:GameChange):Void; - public function onDelete(game:ServerGame):Void; - public function onEvent(game:ServerGame, event:GameEvent):Void; -} - -@:provide(GameManager) interface IGameManager { - public var games(default, null):Array; - public var gamesById(default, null):Map; - public var gamesByUser(default, null):Map; - - private var createSignal(default, null):Signal; - private var changeSignal(default, null):Signal2; - private var deleteSignal(default, null):Signal; - private var eventSignal(default, null):Signal2; - - public function dispatchEvent(game:ServerGame, event:GameEvent):Void; - - public function connect(listener:GameManagerListener):Void; - public function disconnect(listener:GameManagerListener):Void; - - public function create(user:User, imageId:ImageId):ServerGame; - public function delete(gameId:String):Void; - public function join(gameId:String, user:User):Void; - public function leave(user:User):Void; - public function start(gameId:String):Void; -} diff --git a/src/server/haxe/ru/m/puzzlez/game/ServerGame.hx b/src/server/haxe/ru/m/puzzlez/game/ServerGame.hx deleted file mode 100644 index 6785578..0000000 --- a/src/server/haxe/ru/m/puzzlez/game/ServerGame.hx +++ /dev/null @@ -1,44 +0,0 @@ -package ru.m.puzzlez.game; - -import haxe.Timer; -import ru.m.puzzlez.core.Game; -import ru.m.puzzlez.core.GameUtil; -import ru.m.puzzlez.proto.core.User; -import ru.m.puzzlez.proto.game.GameItem; - -@:dispatcher(GameListener) class ServerGame extends Game { - - public var id(get, null):String; - public var proto(default, default):GameItem; - - private var timer:Timer; - - public function new(proto:GameItem) { - // ToDo: - super(GameUtil.buildState(GameUtil.buildPreset(proto.state.preset.imageId))); - this.proto = proto; - } - - private inline function get_id():String { - return proto.state.id; - } - - public function contains(user:User):Bool { - for (user in proto.users) { - if (user.uuid == user.uuid) { - return true; - } - } - return false; - } - - public function join(user:User):Void { - if (!contains(user)) { - proto.users.push(user); - } - } - - public function leave(user:User):Void { - proto.setUsers(proto.users.filter(function(u:User) return u.uuid != user.uuid)); - } -}