[server] update
This commit is contained in:
@@ -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',
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<ImageId> {
|
||||
public var user(default, null):User;
|
||||
public var userSignal(default, null):Signal<User> = new Signal();
|
||||
|
||||
public var gameList(default, null):Array<GameItem>;
|
||||
public var gameListSignal(default, null):Signal<Array<GameItem>> = 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();
|
||||
public var userSignal:Signal<User> = new Signal();
|
||||
public var notificationSignal:Signal<NotificationResponse> = new Signal();
|
||||
public var listSignal:Signal<GameListResponse> = new Signal();
|
||||
public var joinSignal:Signal<GameState> = new Signal();
|
||||
public var gameEventSignal:Signal<GameEvent> = new Signal();
|
||||
|
||||
private var connection:IConnection<Request, Response>;
|
||||
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<User> {
|
||||
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<GameState> {
|
||||
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 {
|
||||
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<DataPage<ImageId>> {
|
||||
// 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)),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<ImageListSource, ButtonView>;
|
||||
@: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 {
|
||||
|
||||
@@ -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<ImageId>;
|
||||
|
||||
@@ -74,6 +76,8 @@ import ru.m.puzzlez.view.common.PuzzleImageView;
|
||||
gameStorage.delete(imageId).then(_ -> refresh());
|
||||
}
|
||||
});
|
||||
case JOIN:
|
||||
// ToDo:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Response, Request> implements GameManagerListener {
|
||||
class GameSession extends ProtoSession<Response, Request> {
|
||||
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 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<Response, Request> 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<Response, Request> 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])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package ru.m.puzzlez.game;
|
||||
|
||||
interface GameListener {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user