[proto] update

This commit is contained in:
2020-05-25 17:29:31 +03:00
parent c878bd60d9
commit f7f6423938
17 changed files with 178 additions and 71 deletions

View File

@@ -1,20 +1,24 @@
package ru.m.puzzlez.net;
import haxe.Unserializer;
import com.hurlant.crypto.extra.UUID;
import com.hurlant.crypto.prng.Random;
import hw.connect.ConnectionFactory;
import hw.connect.IConnection;
import hw.signal.Signal;
import hw.storage.SharedObjectStorage;
import promhx.Promise;
import ru.m.data.IDataSource;
import ru.m.puzzlez.core.GameEvent;
import ru.m.puzzlez.core.GameState;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.proto.core.GameProto;
import ru.m.puzzlez.proto.core.UserProto;
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.Request;
import ru.m.puzzlez.proto.pack.Response;
@:provide class Network {
@:provide class Network implements IDataIndex<ImageId> {
public var user(default, null):UserProto;
public var userSignal(default, null):Signal<UserProto> = new Signal();
@@ -33,11 +37,11 @@ import ru.m.puzzlez.proto.pack.Response;
public function new() {
gameList = [];
storage = new SharedObjectStorage("netwok");
storage = new SharedObjectStorage("network");
if (storage.exists(USER_KEY)) {
user = storage.read(USER_KEY);
} else {
user = new UserProto().setName('Anonimus #${UUID.generateRandom(new Random()).toString().split("-").shift()}');
user = new UserProto().setName('Anonimus #${IdUtil.generate()}');
storage.write(USER_KEY, user);
}
connection = ConnectionFactory.buildClientConnection("127.0.0.1", 5000, Response);
@@ -50,6 +54,14 @@ import ru.m.puzzlez.proto.pack.Response;
connection.send(new Request().setLogin(new LoginRequest().setUser(user)));
}
public function startGame(state:GameState):Void {
connection.send(new Request().setGameCreate(new GameCreateRequest().setImageId(state.preset.imageId)));
}
public function joinGame(state:GameState):Void {
connection.send(new Request().setGameJoin(new GameJoinRequest().setGameId(state.id)));
}
private function onConnectionChange(event:ConnectionEvent):Void {
L.i("network", '${event}');
switch event {
@@ -82,4 +94,14 @@ import ru.m.puzzlez.proto.pack.Response;
}
}
}
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);
}
}

View File

@@ -0,0 +1,41 @@
package ru.m.puzzlez.net;
import hw.signal.Signal;
import ru.m.puzzlez.core.GameState;
import ru.m.puzzlez.core.GameEvent;
import ru.m.puzzlez.core.IGame;
class NetworkGame implements IGame {
public var state(default, null):GameState;
public var signal(default, null):Signal<GameEvent>;
@:provide private var network:Network;
public function new(state:GameState) {
this.state = state;
signal = new Signal();
}
private function onEvent(event:GameEvent):Void {
signal.emit(event);
}
public function start():Void {
network.gameEventSignal.connect(onEvent);
switch state.status {
case READY:
network.startGame(state);
case _:
network.joinGame(state);
}
}
public function stop():Void {
network.gameEventSignal.disconnect(onEvent);
}
public function dispose():Void {
stop();
signal.dispose();
}
}

View File

@@ -9,6 +9,7 @@ import ru.m.puzzlez.core.Game;
import ru.m.puzzlez.core.GameEvent;
import ru.m.puzzlez.core.GameState;
import ru.m.puzzlez.core.IGame;
import ru.m.puzzlez.net.NetworkGame;
import ru.m.puzzlez.render.IRender;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.SettingsStorage;
@@ -32,7 +33,11 @@ import ru.m.puzzlez.view.popup.PreviewPopup;
override public function onShow(state:GameState):Void {
onHide();
if (state.online) {
game = new NetworkGame(state);
} else {
game = new Game(state);
}
game.signal.connect(render.onGameEvent);
game.signal.connect(onGameEvent);
render.signal.connect(game.signal.emit);

View File

@@ -1,5 +1,6 @@
package ru.m.puzzlez.view;
import ru.m.puzzlez.net.Network;
import hw.geom.IntPoint;
import hw.view.data.DataView;
import hw.view.form.ToggleButtonView;
@@ -18,6 +19,7 @@ import ru.m.puzzlez.view.common.PresetView;
@:provide var imageStorage:ImageStorage;
@:provide var switcher:FrameSwitcher;
@:provide var network:Network;
private var imageId:ImageId;
@@ -53,7 +55,8 @@ import ru.m.puzzlez.view.common.PresetView;
selectSize(sizesView.data[sizesView.data.length - 1]);
}
private function start():Void {
private function start(online:Bool = false):Void {
imageView.state.online = online;
switcher.change(GameFrame.ID, imageView.state);
}

View File

@@ -24,6 +24,11 @@ views:
geometry.margin.left: 15
text: Start
+onPress: ~start()
- $type: hw.view.form.ButtonView
style: button.active
geometry.margin.left: 15
text: Network
+onPress: ~start(true)
- id: image
$type: ru.m.puzzlez.view.common.PresetView
geometry.stretch: true

View File

@@ -1,5 +1,6 @@
package ru.m.puzzlez.view;
import ru.m.puzzlez.net.Network;
import hw.view.data.DataView;
import hw.view.form.ButtonView;
import hw.view.frame.FrameSwitcher;
@@ -26,6 +27,7 @@ import ru.m.update.Updater;
@:provide var storage:ImageStorage;
@:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage;
@:provide var network:Network;
@:provide static var appUpdater:Updater;
public function new() {
@@ -75,7 +77,11 @@ import ru.m.update.Updater;
switcher.change(ImageListFrame.ID, source);
}
private function games(status:GameStatus):Void {
private function openGames(status:GameStatus):Void {
switcher.change(ImageListFrame.ID, gameStorage.statusSource(status));
}
private function openNetwork():Void {
switcher.change(ImageListFrame.ID, {title: 'Network', source: network});
}
}

View File

@@ -35,11 +35,15 @@ views:
- id: load
$type: hw.view.form.ButtonView
text: Load
+onPress: ~games('started')
+onPress: ~openGames('started')
- id: complete
$type: hw.view.form.ButtonView
text: Complete
+onPress: ~games('complete')
+onPress: ~openGames('complete')
- id: network
$type: hw.view.form.ButtonView
text: Network
+onPress: ~openNetwork()
- $type: hw.view.SpriteView
geometry.width: 100%
- $type: hw.view.form.LabelView

View File

@@ -0,0 +1,10 @@
package ru.m;
import com.hurlant.crypto.prng.Random;
import com.hurlant.crypto.extra.UUID;
class IdUtil {
public static function generate():String {
return UUID.generateRandom(new Random()).toString().split("-").shift();
}
}

View File

@@ -7,7 +7,9 @@ enum abstract GameStatus(String) from String to String {
}
typedef GameState = {
var id:String;
var status:GameStatus;
var preset:GamePreset;
var parts:Array<Part>;
@:optional var online:Bool;
}

View File

@@ -129,6 +129,7 @@ class GameUtil {
}
}
return {
id: IdUtil.generate(),
status: READY,
preset: preset,
parts: parts,

View File

@@ -10,7 +10,5 @@ interface IGame {
public function stop():Void;
public function shuffle():Void;
public function dispose():Void;
}

View File

@@ -7,11 +7,29 @@ message UserProto {
string name = 2;
}
message PuzzlezPartProto {
}
message PuzzlezGridProto {
int32 width = 1;
int32 height = 2;
}
message GamePresetProto {
string imageId = 1;
PuzzlezGridProto grid = 2;
}
message GameStateProto {
string id = 1;
GamePresetProto preset = 2;
repeated PuzzlezPartProto parts = 3;
}
message GameProto {
int32 id = 1;
string imageId = 2;
string status = 3;
repeated UserProto users = 4;
GameStateProto state = 2;
repeated UserProto users = 3;
}
message GameEventProto {

View File

@@ -26,7 +26,7 @@ message GameCreateRequest {
}
message GameJoinRequest {
int32 gameId = 1;
string gameId = 1;
}
message GameLeaveRequest {}
@@ -57,7 +57,7 @@ message Request {
LogoutRequest logout = 2;
GameCreateRequest gameCreate = 10;
GameLeaveRequest gameJoin = 11;
GameJoinRequest gameJoin = 11;
GameLeaveRequest gameLeave = 12;
GameListRequest gameList = 20;

View File

@@ -27,18 +27,17 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
@:provide static var gameManager:IGameManager;
public var user(default, null):UserProto;
public var gameId(default, null):Int;
public var gameId(default, null):String;
private var subscribed:Bool;
private var tag(get, never):String;
private function get_tag():String {
return '[${id}|${user == null ? '-' : user.name}|${gameId == -1 ? '-' : Std.string(gameId)}]';
return '[${id}|${user == null ? '-' : user.name}|${gameId == null ? '-' : gameId}]';
}
public function new(socket:Socket) {
super(socket, Request);
gameId = -1;
}
private function sendError(code:Int, message:String):Void {
@@ -60,7 +59,7 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
}
private function logout(leave:Bool = true):Void {
gameId = -1;
gameId = null;
gameManager.disconnect(this);
if (user != null && leave) {
gameManager.leave(user);
@@ -68,13 +67,10 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
}
}
private function join(gameId:Int, restore:Bool):Void {
private function join(gameId:String):Void {
this.gameId = gameId;
gameManager.join(gameId, user);
var game = gameManager.gamesById[gameId];
if (restore) {
// ToDo: restore
}
}
override private function onRequest(request:Request):Void {
@@ -86,41 +82,35 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
// login
if (request.hasLogin()) {
user = new UserProto()
.setUuid(request.login.uuid != null ? request.login.uuid : UUID.generateRandom(new Random()).toString())
.setName(request.login.name);
.setUuid(request.login.user.uuid != null ? request.login.user.uuid : UUID.generateRandom(new Random()).toString())
.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, false);
join(gameManager.gamesByUser[user.uuid].id);
}
// logout
} else if (request.hasLogout()) {
logout();
send(new Response().setLogout(new LogoutResponse()));
// room
} else if (request.hasRoom()) {
if (request.room.hasCreate()) {
var game = gameManager.create(user);
// game
} else if (request.hasGameCreate()) {
var game = gameManager.create(user, request.gameCreate.imageId);
gameId = game.id;
send(new Response().setRoom(new RoomResponse().setRoom(game.room)));
} else if (request.room.hasJoin()) {
join(request.room.join.gameId, request.room.join.restore);
} else if (request.room.hasLeave()) {
send(new Response().setGame(new GameResponse().setGame(game.proto)));
} else if (request.hasGameJoin()) {
join(request.gameJoin.gameId);
} else if (request.hasGameLeave()) {
gameManager.leave(user);
} else if (request.room.hasSlot()) {
gameManager.slot(user, request.room.slot.slot);
} else if (request.room.hasStart()) {
gameManager.start(gameId);
}
// room list
} else if (request.hasRoomList()) {
subscribed = request.roomList.subscribe;
// game list
} else if (request.hasGameList()) {
subscribed = request.gameList.subscribe;
if (subscribed) {
send(new Response().setRoomList(listGame()));
send(new Response().setGameList(listGame()));
}
} else if (request.hasGameEvent()) {
if (gameManager.gamesById.exists(gameId)) {
var event:GameEvent = Unserializer.run(request.gameEvent.event.event);
var events:Array<GameEvent> = cast request.gameEvent.events.map(item -> Unserializer.run(item.event));
// ToDo: emit event
///gameManager.gamesById[gameId].gameEventSignal.emit(event);
}
@@ -148,7 +138,7 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
switch change {
case LEAVE(user):
if (user.uuid == this.user.uuid) {
gameId = -1;
gameId = null;
send(new Response().setGame(new GameResponse()));
return;
}
@@ -163,7 +153,7 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
public function onDelete(game:ServerGame):Void {
if (gameId == game.id) {
gameId = -1;
gameId = null;
send(new Response().setGame(new GameResponse()));
}
if (subscribed) {

View File

@@ -1,5 +1,8 @@
package ru.m.puzzlez.game;
import ru.m.puzzlez.proto.core.GamePresetProto;
import ru.m.puzzlez.proto.core.GameStateProto;
import ru.m.puzzlez.core.GameState;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.core.GameEvent;
import ru.m.puzzlez.game.IGameManager;
@@ -34,24 +37,21 @@ class _GameListener implements GameListener {
@:dispatcher(GameManagerListener) class GameManager implements IGameManager {
public var games(default, null):Array<ServerGame>;
public var gamesById(default, null):Map<Int, ServerGame>;
public var gamesById(default, null):Map<String, ServerGame>;
public var gamesByUser(default, null):Map<String, ServerGame>;
private var counter:Int;
public function new() {
counter = 0;
games = [];
gamesById = new Map();
gamesByUser = new Map();
}
public function create(user:UserProto, imageId:ImageId):ServerGame {
if (gamesByCreator.exists(user.uuid)) {
delete(gamesByCreator[user.uuid].id);
}
var gameProto = new GameProto().setId(++counter).setImageId(imageId);
gameProto.users.push(user);
var gameProto = new GameProto().setState(
new GameStateProto()
.setId(IdUtil.generate())
.setPreset(new GamePresetProto().setImageId(imageId))
);
var game = new ServerGame(gameProto);
games.push(game);
gamesById[game.id] = game;
@@ -60,7 +60,7 @@ class _GameListener implements GameListener {
return game;
}
public function join(gameId:Int, user:UserProto):Void {
public function join(gameId:String, user:UserProto):Void {
if (gamesById.exists(gameId)) {
var game = gamesById[gameId];
game.join(user);
@@ -69,7 +69,7 @@ class _GameListener implements GameListener {
}
}
public function delete(gameId:Int):Void {
public function delete(gameId:String):Void {
if (gamesById.exists(gameId)) {
var game = gamesById[gameId];
games.remove(game);
@@ -87,7 +87,7 @@ class _GameListener implements GameListener {
}
}
public function start(gameId:Int):Void {
public function start(gameId:String):Void {
if (gamesById.exists(gameId)) {
var game:ServerGame = gamesById[gameId];
changeSignal.emit(game, START);

View File

@@ -20,8 +20,7 @@ interface GameManagerListener {
@:provide(GameManager) interface IGameManager {
public var games(default, null):Array<ServerGame>;
public var gamesById(default, null):Map<Int, ServerGame>;
public var gamesByCreator(default, null):Map<String, ServerGame>;
public var gamesById(default, null):Map<String, ServerGame>;
public var gamesByUser(default, null):Map<String, ServerGame>;
private var createSignal(default, null):Signal<ServerGame>;
@@ -35,8 +34,8 @@ interface GameManagerListener {
public function disconnect(listener:GameManagerListener):Void;
public function create(user:UserProto, imageId:ImageId):ServerGame;
public function delete(gameId:Int):Void;
public function join(gameId:Int, user:UserProto):Void;
public function delete(gameId:String):Void;
public function join(gameId:String, user:UserProto):Void;
public function leave(user:UserProto):Void;
public function start(gameId:Int):Void;
public function start(gameId:String):Void;
}

View File

@@ -1,5 +1,6 @@
package ru.m.puzzlez.game;
import ru.m.puzzlez.core.GameUtil;
import haxe.Timer;
import ru.m.puzzlez.core.Game;
import ru.m.puzzlez.proto.core.GameProto;
@@ -7,17 +8,19 @@ import ru.m.puzzlez.proto.core.UserProto;
@:dispatcher(GameListener) class ServerGame extends Game {
public var id(get, null):Int;
public var id(get, null):String;
public var proto(default, default):GameProto;
private var timer:Timer;
public function new(proto:GameProto) {
// ToDo:
super(GameUtil.buildState(GameUtil.buildPreset(proto.state.preset.imageId)));
this.proto = proto;
}
private inline function get_id():Int {
return proto.id;
private inline function get_id():String {
return proto.state.id;
}
public function contains(user:UserProto):Bool {