[proto] add rooms and slots

This commit is contained in:
2019-06-04 12:13:27 +03:00
parent 4c8ae66624
commit 78bbf5264e
25 changed files with 405 additions and 403 deletions

View File

@@ -3,9 +3,10 @@
"protoFiles": [
"src/common/proto/core.proto",
"src/common/proto/game.proto",
"src/common/proto/room.proto",
"src/common/proto/pack.proto"
],
"cleanOut": true,
"haxeOut": "src-gen/haxe",
"javaOut": null
}
}

View File

@@ -7,13 +7,14 @@ import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.proto.pack.GameEventResponse;
import ru.m.tankz.proto.room.RoomSlotProto;
class NetworkGame extends Game {
private var network:NetworkManager;
public function new(network:NetworkManager) {
super(new GameState(network.game.type, 0, network.game.level));
super(new GameState(network.room.game.type, 0, network.room.game.level));
this.network = network;
this.controlFactory = new NetworkControlFactory();
network.gameEventSignal.connect(onGameEventProto);
@@ -30,17 +31,17 @@ class NetworkGame extends Game {
private function onConnectionState(state:ConnectionState):Void {
switch state {
case ONLINE(user):
if (network.game != null) {
network.joinGame(network.game.id);
if (network.room != null) {
network.joinGame(network.room.game.id);
}
case _:
}
}
override public function start():Void {
var player = Lambda.find(network.game.players, function(player) return player.user.uuid == network.user.uuid);
if (player != null) {
state.controls.push({playerId: [player.team, player.index], control: "human-0"});
var slot:RoomSlotProto = Lambda.find(network.room.slots, function(slot:RoomSlotProto) return slot.hasUser() && slot.user.uuid == network.user.uuid);
if (slot != null) {
state.controls.push({playerId: [slot.slot.team, slot.slot.index], control: "human-0"});
}
super.start();
}

View File

@@ -1,24 +1,26 @@
package ru.m.tankz.network;
import ru.m.tankz.proto.room.SlotProto;
import ru.m.tankz.proto.room.SlotRequest;
import haxe.Serializer;
import haxework.signal.Signal;
import ru.m.connect.IConnection;
import ru.m.tankz.control.Control;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.game.GameChangeProto;
import ru.m.tankz.proto.pack.CreateGameRequest;
import ru.m.tankz.proto.pack.GameEventRequest;
import ru.m.tankz.proto.pack.GameEventResponse;
import ru.m.tankz.proto.pack.JoinGameRequest;
import ru.m.tankz.proto.pack.LeaveGameRequest;
import ru.m.tankz.proto.pack.ListGameRequest;
import ru.m.tankz.proto.pack.LoginRequest;
import ru.m.tankz.proto.pack.LogoutRequest;
import ru.m.tankz.proto.pack.Request;
import ru.m.tankz.proto.pack.Response;
import ru.m.tankz.proto.pack.StartGameRequest;
import ru.m.tankz.proto.room.CreateRequest;
import ru.m.tankz.proto.room.JoinRequest;
import ru.m.tankz.proto.room.LeaveRequest;
import ru.m.tankz.proto.room.RoomListRequest;
import ru.m.tankz.proto.room.RoomProto;
import ru.m.tankz.proto.room.RoomRequest;
import ru.m.tankz.proto.room.StartRequest;
import ru.m.tankz.storage.MultiplayerStorage;
typedef ClientConnection = IConnection<Request, Response>;
@@ -35,13 +37,12 @@ enum ConnectionState {
class NetworkManager {
public var state(default, null):ConnectionState;
public var game(default, null):GameProto;
public var room(default, null):RoomProto;
public var user(default, null):UserProto;
public var stateSignal:Signal<ConnectionState>;
public var listGameSignal:Signal<Array<GameProto>>;
public var gameSignal:Signal<GameProto>;
public var gameUpdateSignal:Signal<Array<GameChangeProto>>;
public var listRoomSignal:Signal<Array<RoomProto>>;
public var roomSignal:Signal<RoomProto>;
public var gameEventSignal:Signal<GameEventResponse>;
@:provide private var connection:ClientConnection;
@@ -53,9 +54,8 @@ class NetworkManager {
public function new() {
reconnectDelay = 500;
stateSignal = new Signal();
listGameSignal = new Signal();
gameSignal = new Signal();
gameUpdateSignal = new Signal();
listRoomSignal = new Signal();
roomSignal = new Signal();
gameEventSignal = new Signal();
updateState(OFFLINE);
connection.handler.connect(onConnectionEvent);
@@ -81,24 +81,28 @@ class NetworkManager {
connection.send(new Request().setLogout(new LogoutRequest()));
}
public function listGame():Void {
connection.send(new Request().setListGame(new ListGameRequest()));
public function listGame(subscribe:Bool):Void {
connection.send(new Request().setRoomList(new RoomListRequest().setSubscribe(subscribe)));
}
public function createGame(type:String, level:Int):Void {
connection.send(new Request().setCreateGame(new CreateGameRequest().setType(type).setLevel(level)));
connection.send(new Request().setRoom(new RoomRequest().setCreate(new CreateRequest().setType(type).setLevel(level))));
}
public function joinGame(gameId:Int, restore:Bool = false):Void {
connection.send(new Request().setJoinGame(new JoinGameRequest().setGameId(gameId).setRestore(restore)));
connection.send(new Request().setRoom(new RoomRequest().setJoin(new JoinRequest().setGameId(gameId))));
}
public function selectSlot(slot:SlotProto):Void {
connection.send(new Request().setRoom(new RoomRequest().setSlot(new SlotRequest().setSlot(slot))));
}
public function leaveGame():Void {
connection.send(new Request().setLeaveGame(new LeaveGameRequest()));
connection.send(new Request().setRoom(new RoomRequest().setLeave(new LeaveRequest())));
}
public function startGame():Void {
connection.send(new Request().setStartGame(new StartGameRequest()));
connection.send(new Request().setRoom(new RoomRequest().setStart(new StartRequest())));
}
public function action(tankId:Int, action:TankAction):Void {
@@ -154,25 +158,11 @@ class NetworkManager {
} else if (packet.hasLogout()) {
storage.user = null;
updateState(CONNECTED);
} else if (packet.hasListGame()) {
listGameSignal.emit(packet.listGame.games);
} else if (packet.hasCreateGame()) {
game = packet.createGame.game;
gameSignal.emit(game);
} else if (packet.hasJoinGame()) {
game = packet.joinGame.game;
gameSignal.emit(game);
} else if (packet.hasLeaveGame()) {
if (packet.leaveGame.user.uuid == user.uuid) {
game = null;
gameSignal.emit(null);
} else {
game = packet.leaveGame.game;
gameSignal.emit(game);
}
} else if (packet.hasStartGame()) {
game = packet.startGame.game;
gameSignal.emit(game);
} else if (packet.hasRoomList()) {
listRoomSignal.emit(packet.roomList.rooms);
} else if (packet.hasRoom()) {
room = packet.room.room;
roomSignal.emit(room);
} else if (packet.hasGameEvent()) {
gameEventSignal.emit(packet.gameEvent);
}

View File

@@ -17,10 +17,10 @@ views:
$type: ru.m.tankz.view.SettingsFrame
- id: record
$type: ru.m.tankz.view.RecordFrame
- id: game_list
$type: ru.m.tankz.view.network.GameListFrame
- id: game_room
$type: ru.m.tankz.view.network.GameRoomFrame
- id: room_list
$type: ru.m.tankz.view.network.RoomListFrame
- id: room
$type: ru.m.tankz.view.network.RoomFrame
- $type: haxework.view.HGroupView
skinId: panel
layout.margin: 10

View File

@@ -5,8 +5,8 @@ import haxework.view.VGroupView;
import ru.m.tankz.game.GameState;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.Type.GameType;
import ru.m.tankz.view.network.GameListFrame;
import ru.m.tankz.view.network.GameRoomFrame;
import ru.m.tankz.view.network.RoomListFrame;
import ru.m.tankz.view.network.RoomFrame;
import ru.m.tankz.view.popup.FontPopup;
import ru.m.tankz.view.popup.LoginPopup;
@@ -28,16 +28,16 @@ import ru.m.tankz.view.popup.LoginPopup;
private function startNetwork():Void {
switch network.state {
case ONLINE(user):
if (network.game != null) {
switcher.change(GameRoomFrame.ID);
network.joinGame(network.game.id, true);
if (network.room != null) {
switcher.change(RoomFrame.ID);
network.joinGame(network.room.game.id, true);
} else {
switcher.change(GameListFrame.ID);
switcher.change(RoomListFrame.ID);
}
case CONNECTED:
LoginPopup.instance.show().then(function(user):Void {
if (user != null) {
switcher.change(GameListFrame.ID);
switcher.change(RoomListFrame.ID);
}
});
case _:

View File

@@ -1,24 +0,0 @@
package ru.m.tankz.view.network;
import haxework.view.LabelView;
import haxework.view.HGroupView;
import haxework.view.list.ListView;
import ru.m.tankz.proto.core.GameProto;
@:template class GameItemView extends HGroupView implements IListItemView<GameProto> {
public var item_index(default, default):Int;
public var data(default, set):GameProto;
@:view var label:LabelView;
private function set_data(value:GameProto):GameProto {
data = value;
label.text = '[${value.creator.name}] ${value.type} ${value.level} (${value.players.length})';
return data;
}
public static function factory():GameItemView {
return new GameItemView();
}
}

View File

@@ -1,45 +0,0 @@
package ru.m.tankz.view.network;
import haxework.view.frame.FrameSwitcher;
import haxework.view.list.VListView;
import haxework.view.VGroupView;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.proto.core.GameProto;
@:template class GameListFrame extends VGroupView {
public static inline var ID = "game_list";
@:view var games:VListView<GameProto>;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;
public function onShow():Void {
network.listGameSignal.connect(onGameList);
network.gameSignal.connect(onGame);
network.listGame();
}
public function onHide():Void {
network.listGameSignal.disconnect(onGameList);
network.gameSignal.disconnect(onGame);
}
private function create():Void {
network.createGame("classic", 0);
}
private function onGameList(data:Array<GameProto>):Void {
games.data = data;
}
private function onGame(game:GameProto):Void {
if (game != null) {
switcher.change(GameRoomFrame.ID);
}
}
private function selectGame(game:GameProto):Void {
network.joinGame(game.id, true);
}
}

View File

@@ -1,55 +0,0 @@
package ru.m.tankz.view.network;
import haxework.view.ButtonView;
import haxework.view.frame.FrameSwitcher;
import haxework.view.list.VListView;
import haxework.view.TextView;
import haxework.view.VGroupView;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.NetworkGame;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.GameStateProto;
import ru.m.tankz.proto.core.PlayerProto;
@:template class GameRoomFrame extends VGroupView {
public static inline var ID = "game_room";
@:view var start:ButtonView;
@:view var info:TextView;
@:view var players:VListView<PlayerProto>;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;
@:provide var game:IGame;
private function refresh(game:GameProto):Void {
if (game != null) {
start.visible = game.creator.uuid == network.user.uuid;
info.text = '[${game.creator.name}] ${game.type} ${game.level} (${game.players.length})';
players.data = game.players;
if (game.state == GameStateProto.STARTED) {
if (this.game == null) {
this.game = new NetworkGame(network);
}
switcher.change(GameFrame.ID);
}
} else {
Timer.delay(function() switcher.change(GameListFrame.ID), 1);
}
}
public function onShow():Void {
refresh(network.game);
network.gameSignal.connect(onGame);
}
public function onHide():Void {
network.gameSignal.disconnect(onGame);
}
private function onGame(game:GameProto):Void {
refresh(game);
}
}

View File

@@ -1,24 +0,0 @@
package ru.m.tankz.view.network;
import haxework.view.HGroupView;
import haxework.view.LabelView;
import haxework.view.list.ListView;
import ru.m.tankz.proto.core.PlayerProto;
@:template class PlayerItemView extends HGroupView implements IListItemView<PlayerProto> {
public var item_index(default, default):Int;
public var data(default, set):PlayerProto;
@:view var label:LabelView;
private function set_data(value:PlayerProto):PlayerProto {
data = value;
label.text = '${value.user.name}';
return data;
}
public static function factory():PlayerItemView {
return new PlayerItemView();
}
}

View File

@@ -0,0 +1,54 @@
package ru.m.tankz.view.network;
import haxework.view.ButtonView;
import haxework.view.frame.FrameSwitcher;
import haxework.view.list.VListView;
import haxework.view.TextView;
import haxework.view.VGroupView;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.NetworkGame;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.proto.room.RoomProto;
import ru.m.tankz.proto.room.RoomSlotProto;
@:template class RoomFrame extends VGroupView {
public static inline var ID = "room";
@:view var start:ButtonView;
@:view var info:TextView;
@:view var slots:VListView<RoomSlotProto>;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;
@:provide var game:IGame;
private function refresh(room:RoomProto):Void {
if (room != null) {
start.visible = room.creator.uuid == network.user.uuid;
info.text = '[${room.creator.name}] ${room.game.type} ${room.game.level} (${room.users.length})';
slots.data = room.slots;
if (room.game.started) {
if (this.game == null) {
this.game = new NetworkGame(network);
}
switcher.change(GameFrame.ID);
}
} else {
Timer.delay(function() switcher.change(RoomListFrame.ID), 1);
}
}
private function selectSlot(slot:RoomSlotProto):Void {
network.selectSlot(slot.slot);
}
public function onShow():Void {
refresh(network.room);
network.roomSignal.connect(refresh);
}
public function onHide():Void {
network.roomSignal.disconnect(refresh);
}
}

View File

@@ -19,7 +19,8 @@ views:
$type: haxework.view.LabelView
geometry.size.width: 100%
skinId: text.box
- id: players
- id: slots
$type: haxework.view.list.VListView
geometry.size.stretch: true
factory: $code:ru.m.tankz.view.network.PlayerItemView.factory
factory: $code:ru.m.tankz.view.network.SlotItemView.factory
+onItemSelect: $code:function(item) selectSlot(item.data)

View File

@@ -0,0 +1,24 @@
package ru.m.tankz.view.network;
import haxework.view.HGroupView;
import haxework.view.LabelView;
import haxework.view.list.ListView;
import ru.m.tankz.proto.room.RoomProto;
@:template class RoomItemView extends HGroupView implements IListItemView<RoomProto> {
public var item_index(default, default):Int;
public var data(default, set):RoomProto;
@:view var label:LabelView;
private function set_data(value:RoomProto):RoomProto {
data = value;
label.text = '[${value.creator.name}] ${value.game.type} ${value.game.level} (${value.users.length})';
return data;
}
public static function factory():RoomItemView {
return new RoomItemView();
}
}

View File

@@ -0,0 +1,47 @@
package ru.m.tankz.view.network;
import haxework.view.frame.FrameSwitcher;
import haxework.view.list.VListView;
import haxework.view.VGroupView;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.proto.room.RoomProto;
@:template class RoomListFrame extends VGroupView {
public static inline var ID = "room_list";
@:view var games:VListView<RoomProto>;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;
public function onShow():Void {
network.listRoomSignal.connect(onRoomList);
network.roomSignal.connect(onRoom);
network.listGame(true);
}
public function onHide():Void {
network.listRoomSignal.disconnect(onRoomList);
network.roomSignal.disconnect(onRoom);
network.listGame(false);
}
private function create():Void {
network.createGame("classic", 0);
}
private function onRoomList(data:Array<RoomProto>):Void {
games.data = data;
}
private function onRoom(room:RoomProto):Void {
if (room != null) {
switcher.change(RoomFrame.ID);
}
}
private function selectRoom(room:RoomProto):Void {
network.joinGame(room.game.id, true);
}
}

View File

@@ -16,6 +16,6 @@ views:
- id: games
$type: haxework.view.list.VListView
geometry.size.stretch: true
factory: $code:ru.m.tankz.view.network.GameItemView.factory
factory: $code:ru.m.tankz.view.network.RoomItemView.factory
geometry.margin: 10
+onItemSelect: $code:function(item) selectGame(item.data)
+onItemSelect: $code:function(item) selectRoom(item.data)

View File

@@ -0,0 +1,24 @@
package ru.m.tankz.view.network;
import haxework.view.HGroupView;
import haxework.view.LabelView;
import haxework.view.list.ListView;
import ru.m.tankz.proto.room.RoomSlotProto;
@:template class SlotItemView extends HGroupView implements IListItemView<RoomSlotProto> {
public var item_index(default, default):Int;
public var data(default, set):RoomSlotProto;
@:view var label:LabelView;
private function set_data(value:RoomSlotProto):RoomSlotProto {
data = value;
label.text = '${value.slot.team}-${value.slot.index} ${value.hasUser() ? value.user.name : '(NONE)'}';
return data;
}
public static function factory():SlotItemView {
return new SlotItemView();
}
}

View File

@@ -7,23 +7,9 @@ message UserProto {
string name = 2;
}
enum GameStateProto {
READY = 0;
STARTED = 1;
ENDED = 2;
}
message PlayerProto {
UserProto user = 1;
string team = 2;
int32 index = 3;
}
message GameProto {
int32 id = 1;
string type = 2;
int32 level = 3;
UserProto creator = 4;
repeated PlayerProto players = 5;
GameStateProto state = 6;
bool started = 4;
}

View File

@@ -1,28 +1,3 @@
syntax = "proto3";
package ru.m.tankz.proto.game;
enum GameActionTypeProto {
MOVE = 0;
SHOT = 1;
STOP = 2;
}
enum GameChangeTypeProto {
MOVED = 0;
DESTROED = 1;
MODIFIED = 2;
APPEND = 3;
DIRECTION = 4;
}
message GameChangeProto {
GameChangeTypeProto type = 1;
string entityType = 2;
int32 entityId = 3;
float x = 4;
float y = 5;
int32 directionX = 6;
int32 directionY = 7;
}

View File

@@ -2,16 +2,15 @@ syntax = "proto3";
import "core.proto";
import "game.proto";
import "room.proto";
package ru.m.tankz.proto.pack;
message ErrorResponse {
int32 code = 1;
string message = 2;
}
// Login
message LoginRequest {
string uuid = 1;
string name = 2;
@@ -21,56 +20,10 @@ message LoginResponse {
ru.m.tankz.proto.core.UserProto user = 1;
}
// Logout
message LogoutRequest {}
message LogoutResponse {}
// List Game
message ListGameRequest {}
message ListGameResponse {
repeated ru.m.tankz.proto.core.GameProto games = 1;
}
// Create Game
message CreateGameRequest {
string type = 1;
int32 level = 2;
}
message CreateGameResponse {
ru.m.tankz.proto.core.GameProto game = 1;
}
// Join Game
message JoinGameRequest {
int32 game_id = 1;
bool restore = 2;
}
message JoinGameResponse {
ru.m.tankz.proto.core.GameProto game = 1;
ru.m.tankz.proto.core.UserProto user = 2;
repeated string events = 3;
}
// Leave Game
message LeaveGameRequest {}
message LeaveGameResponse {
ru.m.tankz.proto.core.GameProto game = 1;
ru.m.tankz.proto.core.UserProto user = 2;
}
// Start Game
message StartGameRequest {}
message StartGameResponse {
ru.m.tankz.proto.core.GameProto game = 1;
}
// Game
message GameEventRequest {
int32 time = 1;
string event = 2;
@@ -81,31 +34,23 @@ message GameEventResponse {
string event = 2;
}
// Request
message Request {
oneof content {
LoginRequest login = 1;
LogoutRequest logout = 2;
ListGameRequest listGame = 3;
CreateGameRequest createGame = 4;
JoinGameRequest joinGame = 5;
LeaveGameRequest leaveGame = 6;
StartGameRequest startGame = 7;
GameEventRequest gameEvent = 8;
ru.m.tankz.proto.room.RoomRequest room = 3;
ru.m.tankz.proto.room.RoomListRequest roomList = 4;
GameEventRequest gameEvent = 6;
}
}
// Response
message Response {
oneof content {
LoginResponse login = 1;
LogoutResponse logout = 2;
ListGameResponse listGame = 3;
CreateGameResponse createGame = 4;
JoinGameResponse joinGame = 5;
LeaveGameResponse leaveGame = 6;
StartGameResponse startGame = 7;
GameEventResponse gameEvent = 8;
ru.m.tankz.proto.room.RoomResponse room = 3;
ru.m.tankz.proto.room.RoomListResponse roomList = 4;
GameEventResponse gameEvent = 6;
ErrorResponse error = 999;
}

View File

@@ -0,0 +1,63 @@
syntax = "proto3";
import "core.proto";
package ru.m.tankz.proto.room;
message SlotProto {
string team = 3;
int32 index = 4;
}
message RoomSlotProto {
SlotProto slot = 1;
ru.m.tankz.proto.core.UserProto user = 2;
}
message RoomProto {
ru.m.tankz.proto.core.GameProto game = 1;
ru.m.tankz.proto.core.UserProto creator = 2;
repeated ru.m.tankz.proto.core.UserProto users = 3;
repeated RoomSlotProto slots = 4;
}
message CreateRequest {
string type = 2;
int32 level = 3;
}
message JoinRequest {
int32 gameId = 1;
}
message LeaveRequest {
}
message SlotRequest {
SlotProto slot = 3;
}
message StartRequest {
}
message RoomRequest {
oneof content {
CreateRequest create = 1;
JoinRequest join = 2;
LeaveRequest leave = 3;
SlotRequest slot = 4;
StartRequest start = 5;
}
}
message RoomResponse {
RoomProto room = 1;
}
message RoomListRequest {
bool subscribe = 1;
}
message RoomListResponse {
repeated RoomProto rooms = 1;
}

View File

@@ -1,10 +1,13 @@
package ru.m.tankz.server.game;
import ru.m.tankz.config.Config.PlayerControl;
import ru.m.tankz.proto.room.RoomSlotProto;
import ru.m.tankz.proto.room.SlotProto;
import ru.m.tankz.proto.room.RoomProto;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.IGame.GameListener;
import ru.m.tankz.game.IGame;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.GameStateProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.server.game.IGameManager;
@@ -21,7 +24,7 @@ class _GameListener implements GameListener {
dispatcher.dispatchEvent(game, event);
switch event {
case COMPLETE(_, _):
dispatcher.delete(game.proto.id);
dispatcher.delete(game.id);
dispose();
case _:
}
@@ -52,29 +55,36 @@ class _GameListener implements GameListener {
public function create(user:UserProto, type:String, level:Int):ServerGame {
if (gamesByCreator.exists(user.uuid)) {
delete(gamesByCreator[user.uuid].proto.id);
delete(gamesByCreator[user.uuid].id);
}
var proto = new GameProto()
.setId(++counter)
.setCreator(user)
.setType(type)
.setLevel(level);
var game = new ServerGame(proto);
game.joinUser(user);
var room = new RoomProto()
.setGame(
new GameProto()
.setId(++counter)
.setType(type)
.setLevel(level)
)
.setCreator(user);
var game = new ServerGame(room);
var slots:Array<RoomSlotProto> = [];
for (team in game.state.teams) {
for (player in team.players) {
slots.push(new RoomSlotProto().setSlot(new SlotProto().setTeam(player.id.team).setIndex(player.id.index)));
}
}
game.room.setSlots(slots);
games.push(game);
/*if (gamesByCreator.exists(user.uuid)) {
delete(gamesByCreator[user.uuid].proto.id);
} else*/
gamesById[game.proto.id] = game;
gamesByCreator[game.proto.creator.uuid] = game;
gamesById[game.id] = game;
gamesByCreator[game.room.creator.uuid] = game;
createSignal.emit(game);
join(game.id, user);
return game;
}
public function join(gameId:Int, user:UserProto):Void {
if (gamesById.exists(gameId)) {
var game = gamesById[gameId];
game.joinUser(user);
game.join(user);
gamesByUser[user.uuid] = game;
changeSignal.emit(game, JOIN(user));
}
@@ -84,8 +94,8 @@ class _GameListener implements GameListener {
if (gamesById.exists(gameId)) {
var game = gamesById[gameId];
games.remove(game);
gamesById.remove(game.proto.id);
gamesByCreator.remove(game.proto.creator.uuid);
gamesById.remove(game.id);
gamesByCreator.remove(game.room.creator.uuid);
deleteSignal.emit(game);
}
}
@@ -95,15 +105,24 @@ class _GameListener implements GameListener {
delete(gamesByCreator[user.uuid].proto.id);
} else*/ if (gamesByUser.exists(user.uuid)) {
var game = gamesByUser[user.uuid];
game.leaveUser(user);
gamesByUser.remove(user.uuid);
game.leave(user);
changeSignal.emit(game, LEAVE(user));
}
}
public function slot(user:UserProto, slot:SlotProto):Void {
if (gamesByUser.exists(user.uuid)) {
var game = gamesByUser[user.uuid];
game.slot(user, slot);
changeSignal.emit(game, SLOT(user, slot));
}
}
public function start(gameId:Int):Void {
if (gamesById.exists(gameId)) {
var game:ServerGame = gamesById[gameId];
game.proto.setState(GameStateProto.STARTED);
game.room.game.setStarted(true);
changeSignal.emit(game, START);
game.connect(new _GameListener(game, this));
game.start();

View File

@@ -1,12 +1,14 @@
package ru.m.tankz.server.game;
import ru.m.tankz.game.GameEvent;
import haxework.signal.Signal;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.room.SlotProto;
enum GameChange {
JOIN(user:UserProto);
LEAVE(user:UserProto);
SLOT(user:UserProto, slot:SlotProto);
START();
}
@@ -35,6 +37,7 @@ interface IGameManager {
public function create(user:UserProto, type:String, level:Int):ServerGame;
public function delete(gameId:Int):Void;
public function join(gameId:Int, user:UserProto):Void;
public function slot(user:UserProto, slot:SlotProto):Void;
public function leave(user:UserProto):Void;
public function start(gameId:Int):Void;
}

View File

@@ -1,44 +1,69 @@
package ru.m.tankz.server.game;
import ru.m.tankz.proto.room.RoomSlotProto;
import ru.m.tankz.config.Config;
import ru.m.tankz.core.EntityType;
import ru.m.tankz.game.EventUtil;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameRunner;
import ru.m.tankz.game.GameState;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.core.PlayerProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.room.RoomProto;
import ru.m.tankz.proto.room.SlotProto;
import ru.m.tankz.server.control.ServerControlFactory;
import ru.m.tankz.Type.PlayerId;
class ServerGame extends GameRunner {
public var runner(default, null):GameRunner;
public var proto(default, null):GameProto;
public var room(default, null):RoomProto;
public var id(get, null):Int;
public function new(proto:GameProto) {
super(new GameState(proto.type, 0, proto.level));
public function new(room:RoomProto) {
super(new GameState(room.game.type, 0, room.game.level));
this.controlFactory = new ServerControlFactory();
this.proto = proto;
this.room = room;
}
public function joinUser(user:UserProto, playerId:PlayerId = null):Void {
leaveUser(user);
if (playerId == null) {
playerId = ["human", proto.players.length];
private inline function get_id():Int {
return room.game.id;
}
public function join(user:UserProto):Void {
leave(user);
room.users.push(user);
}
public function slot(user:UserProto, slot:SlotProto):Void {
for (s in room.slots) {
if (s.hasUser() && s.user.uuid == user.uuid) {
s.clearUser();
break;
}
}
for (s in room.slots) {
if (s.slot.team == slot.team && s.slot.index == slot.index) {
s.setUser(user);
break;
}
}
proto.players.push(new PlayerProto().setUser(user).setTeam(playerId.team).setIndex(playerId.index));
}
public function leaveUser(user:UserProto):Void {
proto.setPlayers(proto.players.filter(function(player) return player.user.uuid != user.uuid));
public function leave(user:UserProto):Void {
for (slot in room.slots) {
if (slot.user != null && slot.user.uuid == user.uuid) {
slot.clearUser();
break;
}
}
room.setUsers(room.users.filter(function(u:UserProto) return u.uuid != user.uuid));
}
override public function start():Void {
state.controls = proto.players.map(function(player):PlayerControl return {
playerId: [player.team, player.index],
control: 'human-0'
state.controls = room.slots
.filter(function(slot:RoomSlotProto) return slot.hasUser())
.map(function(slot:RoomSlotProto):PlayerControl return {
playerId: [slot.slot.team, slot.slot.index],
control: "human-0",
});
super.start();
}

View File

@@ -1,24 +1,20 @@
package ru.m.tankz.server.session;
import ru.m.tankz.proto.core.GameStateProto;
import haxe.Unserializer;
import haxe.Serializer;
import ru.m.tankz.proto.pack.GameEventResponse;
import ru.m.tankz.game.GameEvent;
import com.hurlant.crypto.extra.UUID;
import com.hurlant.crypto.prng.Random;
import haxe.Serializer;
import haxe.Unserializer;
import haxework.log.BaseLogger.LoggerUtil;
import ru.m.tankz.game.GameEvent;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.pack.CreateGameResponse;
import ru.m.tankz.proto.pack.ErrorResponse;
import ru.m.tankz.proto.pack.JoinGameResponse;
import ru.m.tankz.proto.pack.LeaveGameResponse;
import ru.m.tankz.proto.pack.ListGameResponse;
import ru.m.tankz.proto.pack.GameEventResponse;
import ru.m.tankz.proto.pack.LoginResponse;
import ru.m.tankz.proto.pack.LogoutResponse;
import ru.m.tankz.proto.pack.Request;
import ru.m.tankz.proto.pack.Response;
import ru.m.tankz.proto.pack.StartGameResponse;
import ru.m.tankz.proto.room.RoomListResponse;
import ru.m.tankz.proto.room.RoomResponse;
import ru.m.tankz.server.game.IGameManager;
import ru.m.tankz.server.game.ServerGame;
import sys.net.Socket;
@@ -31,6 +27,7 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
public var user(default, null):UserProto;
public var gameId(default, null):Int;
private var subscribed:Bool;
private var tag(get, never):String;
private function get_tag():String {
@@ -46,9 +43,9 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message)));
}
private function listGame():ListGameResponse {
private function listGame():RoomListResponse {
var games = gameManager.games;
return new ListGameResponse().setGames([for (game in games) game.proto]);
return new RoomListResponse().setRooms([for (game in games) game.room]);
}
override public function send(packet:Response):Void {
@@ -86,30 +83,28 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
} else if (request.hasLogout()) {
logout();
send(new Response().setLogout(new LogoutResponse()));
// create
} else if (request.hasCreateGame()) {
var game = gameManager.create(user, request.createGame.type, request.createGame.level);
gameId = game.proto.id;
send(new Response().setCreateGame(new CreateGameResponse().setGame(game.proto)));
// list
} else if (request.hasListGame()) {
send(new Response().setListGame(listGame()));
// join
} else if (request.hasJoinGame()) {
gameId = request.joinGame.gameId;
gameManager.join(request.joinGame.gameId, user);
var game = gameManager.gamesById[gameId];
if (request.joinGame.restore && game.proto.state == GameStateProto.STARTED) {
for (event in game.restore()) {
send(new Response().setGameEvent(new GameEventResponse().setTime(0).setEvent(Serializer.run(event))));
}
// room
} else if (request.hasRoom()) {
if (request.room.hasCreate()) {
var game = gameManager.create(user, request.room.create.type, request.room.create.level);
gameId = game.id;
send(new Response().setRoom(new RoomResponse().setRoom(game.room)));
} else if (request.room.hasJoin()) {
gameId = request.room.join.gameId;
gameManager.join(gameId, user);
} else if (request.room.hasLeave()) {
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;
if (subscribed) {
send(new Response().setRoomList(listGame()));
}
// leave
} else if (request.hasLeaveGame()) {
gameManager.leave(user);
// start
} else if (request.hasStartGame()) {
gameManager.start(gameId);
} else if (request.hasGameEvent()) {
if (gameManager.gamesById.exists(gameId)) {
var event:GameEvent = Unserializer.run(request.gameEvent.event);
@@ -129,44 +124,41 @@ class GameSession extends ProtoSession<Response, Request> implements GameManager
}
public function onCreate(game:ServerGame):Void {
if (gameId == -1) {
send(new Response().setListGame(listGame()));
if (subscribed) {
send(new Response().setRoomList(listGame()));
}
}
public function onChange(game:ServerGame, change:GameChange):Void {
if (gameId == game.proto.id) {
if (gameId == game.id) {
switch change {
case JOIN(user):
if (user.uuid == this.user.uuid) {
gameId = game.proto.id;
}
send(new Response().setJoinGame(new JoinGameResponse().setGame(game.proto).setUser(user)));
case LEAVE(user):
if (user.uuid == this.user.uuid) {
gameId = -1;
send(new Response().setRoom(new RoomResponse()));
return;
}
send(new Response().setLeaveGame(new LeaveGameResponse().setGame(game.proto).setUser(user)));
case START:
send(new Response().setStartGame(new StartGameResponse().setGame(game.proto)));
case _:
}
} else {
// ToDo: change game event
send(new Response().setListGame(listGame()));
send(new Response().setRoom(new RoomResponse().setRoom(game.room)));
}
if (subscribed) {
send(new Response().setRoomList(listGame()));
}
}
public function onDelete(game:ServerGame):Void {
if (gameId == -1) {
send(new Response().setListGame(listGame()));
} else if (gameId == game.proto.id) {
if (gameId == game.id) {
gameId = -1;
send(new Response().setLeaveGame(new LeaveGameResponse().setGame(game.proto).setUser(user)));
send(new Response().setRoom(new RoomResponse()));
}
if (subscribed) {
send(new Response().setRoomList(listGame()));
}
}
public function onEvent(game:ServerGame, event:GameEvent):Void {
if (gameId == game.proto.id) {
if (gameId == game.id) {
send(new Response().setGameEvent(new GameEventResponse().setTime(0).setEvent(Serializer.run(event))));
}
}