[server] update

This commit is contained in:
2020-06-03 18:02:42 +03:00
parent 33d1d77cd3
commit edbc587e2e
18 changed files with 240 additions and 399 deletions

View File

@@ -47,7 +47,7 @@ const config = new Project.Config({
`CompilationOption.set('build','${dateformat(new Date(), 'yyyy-mm-dd HH:MM:ss')}')`, `CompilationOption.set('build','${dateformat(new Date(), 'yyyy-mm-dd HH:MM:ss')}')`,
], ],
flags: [ flags: [
//'proto_debug', 'proto_debug',
] ]
}); });

View File

@@ -60,6 +60,9 @@ class PuzzlezTheme extends Theme {
register(new Style("icon.orange", [ register(new Style("icon.orange", [
"skin.color" => 0xcc5500, "skin.color" => 0xcc5500,
])); ]));
register(new Style("icon.green", [
"skin.color" => 0x00ff00,
]));
register(new Style("icon.control", [ register(new Style("icon.control", [
"geometry.hAlign" => HAlign.RIGHT, "geometry.hAlign" => HAlign.RIGHT,
"geometry.vAlign" => VAlign.TOP, "geometry.vAlign" => VAlign.TOP,

View File

@@ -10,26 +10,24 @@ import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.proto.core.User; import ru.m.puzzlez.proto.core.User;
import ru.m.puzzlez.proto.event.GameAction; import ru.m.puzzlez.proto.event.GameAction;
import ru.m.puzzlez.proto.event.GameEvent; 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.game.GameState;
import ru.m.puzzlez.proto.pack.AuthRequest;
import ru.m.puzzlez.proto.pack.GameActionRequest; 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.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.Request;
import ru.m.puzzlez.proto.pack.Response; import ru.m.puzzlez.proto.pack.Response;
@:provide class Network implements IDataIndex<ImageId> { @:provide class Network implements IDataIndex<ImageId> {
public var user(default, null):User; public var userSignal:Signal<User> = new Signal();
public var userSignal(default, null):Signal<User> = new Signal(); public var notificationSignal:Signal<NotificationResponse> = new Signal();
public var listSignal:Signal<GameListResponse> = new Signal();
public var gameList(default, null):Array<GameItem>; public var joinSignal:Signal<GameState> = new Signal();
public var gameListSignal(default, null):Signal<Array<GameItem>> = new Signal(); public var gameEventSignal:Signal<GameEvent> = new Signal();
public var game(default, null):GameItem;
public var gameSignal(default, null):Signal<GameItem> = new Signal();
public var gameEventSignal(default, null):Signal<GameEvent> = new Signal();
private var connection:IConnection<Request, Response>; private var connection:IConnection<Request, Response>;
private var storage:SharedObjectStorage; private var storage:SharedObjectStorage;
@@ -37,41 +35,49 @@ import ru.m.puzzlez.proto.pack.Response;
private static var USER_KEY = "user"; private static var USER_KEY = "user";
public function new() { public function new() {
gameList = [];
storage = new SharedObjectStorage("network/2"); 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 = ConnectionFactory.buildClientConnection("127.0.0.1", 5000, Response);
connection.handler.connect(onConnectionChange); connection.handler.connect(onConnectionChange);
connection.receiveHandler.connect(onReceivePacket); connection.receiveHandler.connect(onReceivePacket);
connection.connect().catchError(_ -> {}); connection.connect().catchError(_ -> {});
} }
public function login():Void { private function restoreUser():User {
connection.send(new Request().setLogin(new LoginRequest().setUser(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 { public function auth():Promise<User> {
connection.send(new Request().setGameCreate(new GameCreateRequest().setImageId(state.preset.imageId))); connection.send(new Request().setAuth(new AuthRequest().setUser(restoreUser())));
return userSignal.next();
} }
public function joinGame(state:GameState):Void { public function createGame(preset:GamePreset):Promise<GameState> {
connection.send(new Request().setGameJoin(new GameJoinRequest().setGameId(state.id))); connection.send(new Request().setJoin(new GameJoinRequest().setPreset(preset)));
return joinSignal.next();
}
public function joinGame(gameId:String):Promise<GameState> {
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 { 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 { private function onConnectionChange(event:ConnectionEvent):Void {
L.i("network", '${event}'); L.i("network", '${event}');
switch event { switch event {
case CONNECTED: case CONNECTED:
login(); auth().then(user -> storage.write(USER_KEY, user));
case DISCONNECTED: case DISCONNECTED:
// //
case ERROR(error): case ERROR(error):
@@ -80,34 +86,32 @@ import ru.m.puzzlez.proto.pack.Response;
} }
private function onReceivePacket(packet:Response):Void { private function onReceivePacket(packet:Response):Void {
if (packet.hasLogin()) { if (packet.hasAuth()) {
user = packet.login.user; userSignal.emit(packet.auth.user);
storage.write(USER_KEY, user); } else if (packet.hasNotification()) {
userSignal.emit(user); notificationSignal.emit(packet.notification);
} else if (packet.hasLogout()) { } else if (packet.hasList()) {
user = null; listSignal.emit(packet.list);
userSignal.emit(user); } else if (packet.hasJoin()) {
} else if (packet.hasGameList()) { joinSignal.emit(packet.join.game);
gameList = packet.gameList.games; } else if (packet.hasEvent()) {
gameListSignal.emit(gameList); for (event in packet.event.events) {
} else if (packet.hasGame()) { gameEventSignal.emit(event);
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));
} }
} }
} }
public function getIndexPage(page:Page):Promise<DataPage<ImageId>> { public function getIndexPage(page:Page):Promise<DataPage<ImageId>> {
// ToDo: return gameList connection.send(new Request().setList(new GameListRequest().setCount(page.count).setPage(page.index)));
var data = { return listSignal.next().then((list:GameListResponse) -> ({
page: page, page: {
total: 1, index: list.page,
data: [new ImageId('asset', 'resources/image/raccoon.jpg')], count: list.count,
} filter: null,
return Promise.promise(data); order: null,
},
total: list.total,
data: list.games.map(item -> ImageId.fromString(item.preset.imageId)),
}));
} }
} }

View File

@@ -1,11 +1,11 @@
package ru.m.puzzlez.net; package ru.m.puzzlez.net;
import ru.m.puzzlez.proto.event.GameStart;
import hw.signal.Signal; import hw.signal.Signal;
import ru.m.puzzlez.core.IGame; import ru.m.puzzlez.core.IGame;
import ru.m.puzzlez.proto.event.GameAction; import ru.m.puzzlez.proto.event.GameAction;
import ru.m.puzzlez.proto.event.GameEvent; import ru.m.puzzlez.proto.event.GameEvent;
import ru.m.puzzlez.proto.game.GameState; import ru.m.puzzlez.proto.game.GameState;
import ru.m.puzzlez.proto.game.GameStatus;
class NetworkGame implements IGame { class NetworkGame implements IGame {
public var state(default, null):GameState; public var state(default, null):GameState;
@@ -23,17 +23,13 @@ class NetworkGame implements IGame {
} }
public function start():Void { public function start():Void {
events.emit(new GameEvent().setStart(new GameStart().setState(state)));
network.gameEventSignal.connect(onEvent); network.gameEventSignal.connect(onEvent);
switch state.status {
case GameStatus.READY:
network.startGame(state);
case _:
network.joinGame(state);
}
} }
public function stop():Void { public function stop():Void {
network.gameEventSignal.disconnect(onEvent); network.gameEventSignal.disconnect(onEvent);
network.leaveGame();
} }
public function dispose():Void { public function dispose():Void {

View File

@@ -35,7 +35,8 @@ class Render extends SpriteView implements IRender {
private var playerId(get, never):PlayerId; private var playerId(get, never):PlayerId;
private function get_playerId():PlayerId { private function get_playerId():PlayerId {
return network.user.hasUuid() ? network.user.uuid : "local"; // ToDo: network user
return "local";
} }
private function get_scale():Float { private function get_scale():Float {

View File

@@ -56,8 +56,11 @@ import ru.m.puzzlez.view.common.PresetView;
} }
private function start(online:Bool = false):Void { private function start(online:Bool = false):Void {
imageView.state.online = online; if (online) {
switcher.change(GameFrame.ID, imageView.state); network.createGame(imageView.state.preset).then(state -> switcher.change(GameFrame.ID, state));
} else {
switcher.change(GameFrame.ID, imageView.state);
}
} }
private function back():Void { private function back():Void {

View File

@@ -1,7 +1,5 @@
package ru.m.puzzlez.view; 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.data.DataView;
import hw.view.form.ButtonView; import hw.view.form.ButtonView;
import hw.view.frame.FrameSwitcher; import hw.view.frame.FrameSwitcher;
@@ -9,6 +7,9 @@ import hw.view.frame.FrameView;
import ru.m.data.IDataSource; import ru.m.data.IDataSource;
import ru.m.pixabay.PixabayApi; import ru.m.pixabay.PixabayApi;
import ru.m.puzzlez.core.ImageListSource; 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.AssetSource;
import ru.m.puzzlez.source.FileSource; import ru.m.puzzlez.source.FileSource;
import ru.m.puzzlez.source.PixabaySource; import ru.m.puzzlez.source.PixabaySource;
@@ -22,6 +23,7 @@ import ru.m.update.Updater;
@:view var sources:DataView<ImageListSource, ButtonView>; @:view var sources:DataView<ImageListSource, ButtonView>;
@:view("load") var loadButton:ButtonView; @:view("load") var loadButton:ButtonView;
@:view("complete") var completeButton:ButtonView; @:view("complete") var completeButton:ButtonView;
@:view("network") var networkButton:ButtonView;
@:view("update") var updateButton:ButtonView; @:view("update") var updateButton:ButtonView;
@:provide var storage:ImageStorage; @:provide var storage:ImageStorage;
@@ -55,6 +57,13 @@ import ru.m.update.Updater;
completeButton.text = 'Complete (${total})'; completeButton.text = 'Complete (${total})';
completeButton.disabled = total == 0; 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 { override public function onShow(data:Dynamic):Void {
@@ -65,6 +74,11 @@ import ru.m.update.Updater;
updateButton.text = 'Update ${info.version}'; updateButton.text = 'Update ${info.version}';
} }
}).catchError(error -> L.w('Update', 'failed: ${error}')); }).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 { private function sourceViewFactory(index:Int, source:ImageListSource):ButtonView {

View File

@@ -1,5 +1,6 @@
package ru.m.puzzlez.view.common; package ru.m.puzzlez.view.common;
import ru.m.puzzlez.net.Network;
import hw.view.data.DataView; import hw.view.data.DataView;
import hw.view.form.ToggleButtonView; import hw.view.form.ToggleButtonView;
import hw.view.frame.FrameSwitcher; import hw.view.frame.FrameSwitcher;
@@ -24,6 +25,7 @@ import ru.m.puzzlez.view.common.PuzzleImageView;
@:provide var switcher:FrameSwitcher; @:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage; @:provide var gameStorage:GameStorage;
@:provide var imageStorage:ImageStorage; @:provide var imageStorage:ImageStorage;
@:provide var network:Network;
public var data(default, set):DataPage<ImageId>; public var data(default, set):DataPage<ImageId>;
@@ -74,6 +76,8 @@ import ru.m.puzzlez.view.common.PuzzleImageView;
gameStorage.delete(imageId).then(_ -> refresh()); gameStorage.delete(imageId).then(_ -> refresh());
} }
}); });
case JOIN:
// ToDo:
} }
} }

View File

@@ -1,5 +1,6 @@
package ru.m.puzzlez.view.common; package ru.m.puzzlez.view.common;
import ru.m.puzzlez.net.Network;
import hw.view.data.DataView; import hw.view.data.DataView;
import hw.view.form.ButtonView; import hw.view.form.ButtonView;
import hw.view.form.LabelView; import hw.view.form.LabelView;
@@ -14,6 +15,7 @@ import ru.m.puzzlez.storage.ImageStorage;
enum Action { enum Action {
CLEAN; CLEAN;
REMOVE; REMOVE;
JOIN;
} }
@:template class PuzzleImageView extends GroupView { @:template class PuzzleImageView extends GroupView {
@@ -42,14 +44,17 @@ enum Action {
@:view("label") var labelView:LabelView; @:view("label") var labelView:LabelView;
@:view("clean") var cleanButton:ButtonView; @:view("clean") var cleanButton:ButtonView;
@:view("remove") var removeButton:ButtonView; @:view("remove") var removeButton:ButtonView;
@:view("join") var joinButton:ButtonView;
@:provide static var imageStorage:ImageStorage; @:provide static var imageStorage:ImageStorage;
@:provide static var gameStorage:GameStorage; @:provide static var gameStorage:GameStorage;
@:provide static var network:Network;
private var loading:LoadingWrapper; private var loading:LoadingWrapper;
public function new() { public function new() {
super(); super();
cleanButton.visible = false; cleanButton.visible = false;
removeButton.visible = false; removeButton.visible = false;
joinButton.visible = false;
loading = new LoadingWrapper(this); loading = new LoadingWrapper(this);
} }
@@ -73,6 +78,8 @@ enum Action {
result.removeButton.visible = true; result.removeButton.visible = true;
} }
}); });
// ToDo:
result.joinButton.visible = false;
return result; return result;
} }
} }

View File

@@ -18,3 +18,8 @@ views:
propagation: false propagation: false
style: icon.control.small.close.orange style: icon.control.small.close.orange
+onPress: ~emit(Action.CLEAN) +onPress: ~emit(Action.CLEAN)
- id: join
$type: hw.view.form.ButtonView
propagation: false
style: icon.control.small.close.green
+onPress: ~emit(Action.JOIN)

View File

@@ -26,16 +26,26 @@ message GameAction {
ru.m.puzzlez.proto.core.Point position = 4; 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 { message GameChange {
int32 partId = 1; string playerId = 1;
ru.m.puzzlez.proto.core.Point position = 2; int32 partId = 2;
ru.m.puzzlez.proto.game.PartLocation location = 3; ru.m.puzzlez.proto.core.Point position = 3;
string playerId = 4; ru.m.puzzlez.proto.game.PartLocation location = 4;
} }
message GameEvent { message GameEvent {
int32 time = 1; int32 time = 1;
oneof event { oneof event {
GamePlayer player = 9;
GameStart start = 10; GameStart start = 10;
GameComplete complete = 11; GameComplete complete = 11;
GameAction action = 12; GameAction action = 12;

View File

@@ -55,11 +55,7 @@ message GameState {
string id = 1; string id = 1;
GameStatus status = 2; GameStatus status = 2;
GamePreset preset = 3; GamePreset preset = 3;
repeated Part parts = 4; repeated ru.m.puzzlez.proto.core.User users = 4;
bool online = 5; repeated Part parts = 5;
} bool online = 6;
message GameItem {
GameState state = 2;
repeated ru.m.puzzlez.proto.core.User users = 3;
} }

View File

@@ -11,38 +11,47 @@ message ErrorResponse {
string message = 2; string message = 2;
} }
message LoginRequest { message NotificationResponse {
int32 games = 1;
}
message AuthRequest {
ru.m.puzzlez.proto.core.User user = 1; ru.m.puzzlez.proto.core.User user = 1;
} }
message LoginResponse { message AuthResponse {
ru.m.puzzlez.proto.core.User user = 1; ru.m.puzzlez.proto.core.User user = 1;
} }
message LogoutRequest {}
message LogoutResponse {}
message GameCreateRequest {
string imageId = 1;
}
message GameJoinRequest { 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 { message GameListRequest {
bool subscribe = 1; int32 page = 1;
int32 count = 2;
} }
message GameListResponse { 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 { message GameActionRequest {
@@ -54,31 +63,25 @@ message GameEventResponse {
} }
message Request { message Request {
string rid = 1;
oneof content { oneof content {
LoginRequest login = 1; AuthRequest auth = 10;
LogoutRequest logout = 2; GameListRequest list = 20;
GameJoinRequest join = 30;
GameCreateRequest gameCreate = 10; GameLeaveRequest leave = 40;
GameJoinRequest gameJoin = 11; GameActionRequest action = 100;
GameLeaveRequest gameLeave = 12;
GameListRequest gameList = 20;
GameActionRequest gameAction = 100;
} }
} }
message Response { message Response {
string rid = 1;
oneof content { oneof content {
LoginResponse login = 1; AuthResponse auth = 10;
LogoutResponse logout = 2; GameListResponse list = 20;
GameJoinResponse join = 30;
GameResponse game = 10; GameLeaveResponse leave = 40;
GameEventResponse event = 100;
GameListResponse gameList = 20; NotificationResponse notification = 900;
ErrorResponse error = 1000;
GameEventResponse gameEvent = 100;
ErrorResponse error = 999;
} }
} }

View File

@@ -1,49 +1,53 @@
package ru.m.puzzlez; 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.connect.session.ProtoSession;
import hw.log.BaseLogger.LoggerUtil; import hw.log.BaseLogger.LoggerUtil;
import ru.m.puzzlez.game.IGameManager; import ru.m.puzzlez.core.Game;
import ru.m.puzzlez.game.ServerGame; import ru.m.puzzlez.core.GameUtil;
import ru.m.puzzlez.proto.core.User; 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.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.ErrorResponse;
import ru.m.puzzlez.proto.pack.GameEventResponse; import ru.m.puzzlez.proto.pack.GameEventResponse;
import ru.m.puzzlez.proto.pack.GameListResponse; import ru.m.puzzlez.proto.pack.GameJoinResponse;
import ru.m.puzzlez.proto.pack.GameResponse; import ru.m.puzzlez.proto.pack.GameLeaveResponse;
import ru.m.puzzlez.proto.pack.LoginResponse; import ru.m.puzzlez.proto.pack.NotificationResponse;
import ru.m.puzzlez.proto.pack.LogoutResponse;
import ru.m.puzzlez.proto.pack.Request; import ru.m.puzzlez.proto.pack.Request;
import ru.m.puzzlez.proto.pack.Response; import ru.m.puzzlez.proto.pack.Response;
import sys.net.Socket; import sys.net.Socket;
class GameSession extends ProtoSession<Response, Request> implements GameManagerListener { class GameSession extends ProtoSession<Response, Request> {
private static inline var TAG = "Session"; private static inline var TAG = "Session";
@:provide static var gameManager:IGameManager; public static var gamesById(default, null):Map<String, Game> = new Map();
public static var sessionsById(default, null):Map<Int, GameSession> = new Map();
public var user(default, null):User; public var user(default, null):User;
public var gameId(default, null):String; public var game(default, null):Game;
private var subscribed:Bool; private var subscribed:Bool;
private var tag(get, never):String; private var tag(get, never):String;
private function get_tag():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) { public function new(socket:Socket) {
super(socket, Request); super(socket, Request);
sessionsById.set(id, this);
} }
private function sendError(code:Int, message:String):Void { private function sendError(code:Int, message:String):Void {
send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message))); 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 { override public function send(packet:Response):Void {
#if proto_debug L.d(TAG, '$tag send: ${packet}'); #end #if proto_debug L.d(TAG, '$tag send: ${packet}'); #end
try { try {
@@ -53,61 +57,71 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
} }
} }
private function logout(leave:Bool = true):Void { private function auth(auth:AuthRequest):Void {
gameId = null; user = auth.hasUser() ? auth.user : new User().setUuid(IdUtil.generate()).setName('Anonim #${IdUtil.generate()}');
gameManager.disconnect(this); send(new Response().setAuth(new AuthResponse().setUser(user)));
if (user != null && leave) { send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById))));
gameManager.leave(user); }
user = null;
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 { private function join(gameId:String):Void {
this.gameId = gameId; game = gamesById.get(gameId);
gameManager.join(gameId, user); game.events.connect(onGameEvent);
var game = gameManager.gamesById[gameId]; 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 { override private function onRequest(request:Request):Void {
#if proto_debug L.d(TAG, '$tag onRequest: ${request}'); #end #if proto_debug L.d(TAG, '$tag onRequest: ${request}'); #end
try { try {
if (!request.hasLogin() && user == null) { if (!request.hasAuth() && user == null) {
throw "Not Authorized"; throw "Not Authorized";
} }
// login if (request.hasAuth()) {
if (request.hasLogin()) { auth(request.auth);
user = new User() } else if (request.hasList()) {
.setUuid(request.login.user.uuid != null ? request.login.user.uuid : IdUtil.generate()) list(request.list);
.setName(request.login.user.name); } else if (request.hasJoin()) {
gameManager.connect(this); if (request.join.hasPreset()) {
send(new Response().setLogin(new LoginResponse().setUser(user))); create(request.join.preset);
if (gameManager.gamesByUser.exists(user.uuid)) { } else if (request.join.hasGameId()) {
join(gameManager.gamesByUser[user.uuid].id); join(request.join.gameId);
} }
// logout } else if (request.hasLeave()) {
} else if (request.hasLogout()) { leave();
logout(); } else if (request.hasAction()) {
send(new Response().setLogout(new LogoutResponse())); for (action in request.action.actions) {
// game this.action(action);
} 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));
}
} }
} }
} catch (error:Dynamic) { } catch (error:Dynamic) {
@@ -116,49 +130,18 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
} }
} }
private function onGameEvent(event:GameEvent):Void {
send(new Response().setEvent(new GameEventResponse().setEvents([event])));
}
override public function disconnect():Void { override public function disconnect():Void {
L.d(TAG, '$tag disconnect'); L.d(TAG, '$tag disconnect');
logout(false); if (game != null) {
leave();
game = null;
}
user = null;
sessionsById.remove(id);
super.disconnect(); 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])));
}
}
} }

View File

@@ -1,4 +0,0 @@
package ru.m.puzzlez.game;
interface GameListener {
}

View File

@@ -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<ServerGame>;
public var gamesById(default, null):Map<String, ServerGame>;
public var gamesByUser(default, null):Map<String, ServerGame>;
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);
}
}

View File

@@ -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<ServerGame>;
public var gamesById(default, null):Map<String, ServerGame>;
public var gamesByUser(default, null):Map<String, ServerGame>;
private var createSignal(default, null):Signal<ServerGame>;
private var changeSignal(default, null):Signal2<ServerGame, GameChange>;
private var deleteSignal(default, null):Signal<ServerGame>;
private var eventSignal(default, null):Signal2<ServerGame, GameEvent>;
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;
}

View File

@@ -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));
}
}