[server] add session
This commit is contained in:
11
gulpfile.js
11
gulpfile.js
@@ -23,6 +23,14 @@ exports.clean = function clean() {
|
||||
return gulp.src('target/*', {read: false}).pipe(gulpClean());
|
||||
};
|
||||
|
||||
exports.generate = function generate() {
|
||||
return new Haxe().haxelib(['run', 'protohx', 'generate', 'protohx.json']).then(({stdout}) => {
|
||||
if (stdout.indexOf('FAIL') > -1) {
|
||||
throw stdout;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const config = new Project.Config({
|
||||
meta: {
|
||||
title: 'Puzzle\'z',
|
||||
@@ -52,6 +60,7 @@ const app = new Project(
|
||||
config.branch({
|
||||
name: 'app',
|
||||
sources: [
|
||||
'src-gen/haxe',
|
||||
'src/common/haxe',
|
||||
'src/app/haxe',
|
||||
],
|
||||
@@ -79,6 +88,7 @@ const server = new Project(
|
||||
config.branch({
|
||||
name: 'server',
|
||||
sources: [
|
||||
'src-gen/haxe',
|
||||
'src/common/haxe',
|
||||
'src/server/haxe',
|
||||
],
|
||||
@@ -90,6 +100,7 @@ module.exports.publish = publish(packageInfo.name, packageInfo.version, Config.P
|
||||
|
||||
const defaultSeries = [
|
||||
exports.clean,
|
||||
exports.generate,
|
||||
module.exports['app:flash:build'],
|
||||
module.exports['app:flash:html'],
|
||||
module.exports['app:html5:build'],
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
"lime": "7.7.0",
|
||||
"openfl": "8.9.6",
|
||||
"hxcpp": "4.0.52",
|
||||
"svg": "1.1.3"
|
||||
"svg": "1.1.3",
|
||||
"haxe-crypto": "0.0.7"
|
||||
},
|
||||
"haxe": "4.0.5",
|
||||
"dependencies": {}
|
||||
|
||||
12
protohx.json
Executable file
12
protohx.json
Executable file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"protoPath": "src/common/proto",
|
||||
"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
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
package ru.m.puzzlez;
|
||||
|
||||
import hw.connect.ConnectionFactory;
|
||||
import ru.m.puzzlez.proto.pack.Request;
|
||||
import ru.m.puzzlez.proto.pack.Response;
|
||||
import hw.connect.IConnection;
|
||||
import hw.log.TraceLogger;
|
||||
import hw.app.App;
|
||||
import hw.app.Const;
|
||||
@@ -12,6 +16,7 @@ import ru.m.update.Updater;
|
||||
class PuzzlezApp {
|
||||
|
||||
@:provide static var updater:Updater;
|
||||
@:provide static var connection:IConnection<Response, Request>;
|
||||
|
||||
public static function main() {
|
||||
// ToDo: fix @:provide macro
|
||||
@@ -19,6 +24,8 @@ class PuzzlezApp {
|
||||
ImageStorage;
|
||||
SettingsStorage;
|
||||
L.push(new TraceLogger());
|
||||
connection = ConnectionFactory.buildClientConnection("127.0.0.1", 6000, Request);
|
||||
connection.connect().then(_ -> L.i("connect", "success")).catchError(error -> L.e("connect", "", error));
|
||||
updater = new Updater(Const.instance.VERSION, "https://shmyga.ru/repo/puzzlez/packages.json");
|
||||
var app = new App();
|
||||
app.theme = new PuzzlezTheme();
|
||||
|
||||
@@ -186,7 +186,7 @@ class Render extends SpriteView implements IRender {
|
||||
}
|
||||
activePart = pointPart;
|
||||
tableView.setChildIndex(activePart, tableView.numChildren - 1);
|
||||
activePoint = tableView.globalToLocal(point);
|
||||
activePoint = RenderUtil.convertPoint(tableView.globalToLocal(point));
|
||||
tableView.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||
tableView.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
|
||||
signal.emit(ACTION(PART_TAKE(activePart.id)));
|
||||
@@ -194,14 +194,14 @@ class Render extends SpriteView implements IRender {
|
||||
}
|
||||
|
||||
private function onMouseMove(event:MouseEvent):Void {
|
||||
var newPoint:Point = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY));
|
||||
var newPoint:Point = RenderUtil.convertPoint(tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)));
|
||||
var partPosition = activePart.position.add(newPoint).subtract(activePoint);
|
||||
signal.emit(ACTION(PART_MOVE(activePart.id, partPosition.clone())));
|
||||
activePoint = newPoint;
|
||||
}
|
||||
|
||||
private function onMouseUp(event:MouseEvent):Void {
|
||||
var newPoint:Point = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY));
|
||||
var newPoint:Point = RenderUtil.convertPoint(tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)));
|
||||
var partPosition = activePart.position.add(newPoint).subtract(activePoint);
|
||||
signal.emit(ACTION(PART_PUT(activePart.id, partPosition.clone())));
|
||||
tableView.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||
|
||||
@@ -116,4 +116,8 @@ class RenderUtil {
|
||||
var height = source.height * s;
|
||||
return new Rectangle((target.width - width) / 2, (target.height - height) / 2, width, height);
|
||||
}
|
||||
|
||||
public static function convertPoint(point:flash.geom.Point):Point {
|
||||
return new Point(point.x, point.y);
|
||||
}
|
||||
}
|
||||
|
||||
12
src/common/proto/core.proto
Normal file
12
src/common/proto/core.proto
Normal file
@@ -0,0 +1,12 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ru.m.puzzlez.proto.core;
|
||||
|
||||
message UserProto {
|
||||
string uuid = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message GameProto {
|
||||
int32 id = 1;
|
||||
}
|
||||
8
src/common/proto/game.proto
Normal file
8
src/common/proto/game.proto
Normal file
@@ -0,0 +1,8 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ru.m.puzzlez.proto.game;
|
||||
|
||||
message GameEventProto {
|
||||
int32 time = 1;
|
||||
string event = 2;
|
||||
}
|
||||
55
src/common/proto/pack.proto
Normal file
55
src/common/proto/pack.proto
Normal file
@@ -0,0 +1,55 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "core.proto";
|
||||
import "game.proto";
|
||||
import "room.proto";
|
||||
|
||||
package ru.m.puzzlez.proto.pack;
|
||||
|
||||
message ErrorResponse {
|
||||
int32 code = 1;
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
message LoginRequest {
|
||||
string uuid = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message LoginResponse {
|
||||
ru.m.puzzlez.proto.core.UserProto user = 1;
|
||||
}
|
||||
|
||||
message LogoutRequest {}
|
||||
|
||||
message LogoutResponse {}
|
||||
|
||||
message GameEventRequest {
|
||||
ru.m.puzzlez.proto.game.GameEventProto event = 1;
|
||||
}
|
||||
|
||||
message GameEventResponse {
|
||||
ru.m.puzzlez.proto.game.GameEventProto event = 1;
|
||||
}
|
||||
|
||||
message Request {
|
||||
oneof content {
|
||||
LoginRequest login = 1;
|
||||
LogoutRequest logout = 2;
|
||||
ru.m.puzzlez.proto.room.RoomRequest room = 3;
|
||||
ru.m.puzzlez.proto.room.RoomListRequest roomList = 4;
|
||||
GameEventRequest gameEvent = 6;
|
||||
}
|
||||
}
|
||||
|
||||
message Response {
|
||||
oneof content {
|
||||
LoginResponse login = 1;
|
||||
LogoutResponse logout = 2;
|
||||
ru.m.puzzlez.proto.room.RoomResponse room = 3;
|
||||
ru.m.puzzlez.proto.room.RoomListResponse roomList = 4;
|
||||
GameEventResponse gameEvent = 6;
|
||||
|
||||
ErrorResponse error = 999;
|
||||
}
|
||||
}
|
||||
64
src/common/proto/room.proto
Normal file
64
src/common/proto/room.proto
Normal file
@@ -0,0 +1,64 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "core.proto";
|
||||
|
||||
package ru.m.puzzlez.proto.room;
|
||||
|
||||
message SlotProto {
|
||||
string team = 3;
|
||||
int32 index = 4;
|
||||
}
|
||||
|
||||
message RoomSlotProto {
|
||||
SlotProto slot = 1;
|
||||
ru.m.puzzlez.proto.core.UserProto user = 2;
|
||||
}
|
||||
|
||||
message RoomProto {
|
||||
ru.m.puzzlez.proto.core.GameProto game = 1;
|
||||
ru.m.puzzlez.proto.core.UserProto creator = 2;
|
||||
repeated ru.m.puzzlez.proto.core.UserProto users = 3;
|
||||
repeated RoomSlotProto slots = 4;
|
||||
}
|
||||
|
||||
message CreateRequest {
|
||||
string type = 2;
|
||||
int32 level = 3;
|
||||
}
|
||||
|
||||
message JoinRequest {
|
||||
int32 gameId = 1;
|
||||
bool restore = 2;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
179
src/server/haxe/ru/m/puzzlez/GameSession.hx
Normal file
179
src/server/haxe/ru/m/puzzlez/GameSession.hx
Normal file
@@ -0,0 +1,179 @@
|
||||
package ru.m.puzzlez;
|
||||
|
||||
import com.hurlant.crypto.extra.UUID;
|
||||
import com.hurlant.crypto.prng.Random;
|
||||
import haxe.Serializer;
|
||||
import haxe.Unserializer;
|
||||
import hw.connect.session.ProtoSession;
|
||||
import hw.log.BaseLogger.LoggerUtil;
|
||||
import ru.m.puzzlez.core.GameEvent;
|
||||
import ru.m.puzzlez.game.IGameManager;
|
||||
import ru.m.puzzlez.game.ServerGame;
|
||||
import ru.m.puzzlez.proto.core.UserProto;
|
||||
import ru.m.puzzlez.proto.game.GameEventProto;
|
||||
import ru.m.puzzlez.proto.pack.ErrorResponse;
|
||||
import ru.m.puzzlez.proto.pack.GameEventResponse;
|
||||
import ru.m.puzzlez.proto.pack.LoginResponse;
|
||||
import ru.m.puzzlez.proto.pack.LogoutResponse;
|
||||
import ru.m.puzzlez.proto.pack.Request;
|
||||
import ru.m.puzzlez.proto.pack.Response;
|
||||
import ru.m.puzzlez.proto.room.RoomListResponse;
|
||||
import ru.m.puzzlez.proto.room.RoomResponse;
|
||||
import sys.net.Socket;
|
||||
|
||||
class GameSession extends ProtoSession<Response, Request> implements GameManagerListener {
|
||||
private static inline var TAG = "Session";
|
||||
|
||||
@:provide static var gameManager:IGameManager;
|
||||
|
||||
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 {
|
||||
return '[${id}|${user == null ? '-' : user.name}|${gameId == -1 ? '-' : Std.string(gameId)}]';
|
||||
}
|
||||
|
||||
public function new(socket:Socket) {
|
||||
super(socket, Request);
|
||||
gameId = -1;
|
||||
}
|
||||
|
||||
private function sendError(code:Int, message:String):Void {
|
||||
send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message)));
|
||||
}
|
||||
|
||||
private function listGame():RoomListResponse {
|
||||
var games = gameManager.games;
|
||||
return new RoomListResponse().setRooms([for (game in games) game.room]);
|
||||
}
|
||||
|
||||
override public function send(packet:Response):Void {
|
||||
#if proto_debug L.d(TAG, '$tag send: ${packet}'); #end
|
||||
try {
|
||||
super.send(packet);
|
||||
} catch (error:Dynamic) {
|
||||
L.e(TAG, '$tag send ', error);
|
||||
}
|
||||
}
|
||||
|
||||
private function logout(leave:Bool = true):Void {
|
||||
gameId = -1;
|
||||
gameManager.disconnect(this);
|
||||
if (user != null && leave) {
|
||||
gameManager.leave(user);
|
||||
user = null;
|
||||
}
|
||||
}
|
||||
|
||||
private function join(gameId:Int, restore:Bool):Void {
|
||||
this.gameId = gameId;
|
||||
gameManager.join(gameId, user);
|
||||
var game = gameManager.gamesById[gameId];
|
||||
if (restore) {
|
||||
// ToDo: restore
|
||||
}
|
||||
}
|
||||
|
||||
override private function onRequest(request:Request):Void {
|
||||
#if proto_debug L.d(TAG, '$tag onRequest: ${request}'); #end
|
||||
try {
|
||||
if (!request.hasLogin() && user == null) {
|
||||
throw "Not Authorized";
|
||||
}
|
||||
// login
|
||||
if (request.hasLogin()) {
|
||||
user = new UserProto()
|
||||
.setUuid(request.login.uuid != null ? request.login.uuid : UUID.generateRandom(new Random()).toString())
|
||||
.setName(request.login.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);
|
||||
}
|
||||
// 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);
|
||||
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()) {
|
||||
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()));
|
||||
}
|
||||
} else if (request.hasGameEvent()) {
|
||||
if (gameManager.gamesById.exists(gameId)) {
|
||||
var event:GameEvent = Unserializer.run(request.gameEvent.event.event);
|
||||
// ToDo: emit event
|
||||
///gameManager.gamesById[gameId].gameEventSignal.emit(event);
|
||||
}
|
||||
}
|
||||
} catch (error:Dynamic) {
|
||||
L.e(TAG, '$tag onRequest ', error);
|
||||
sendError(500, LoggerUtil.printError(error));
|
||||
}
|
||||
}
|
||||
|
||||
override public function disconnect():Void {
|
||||
L.d(TAG, '$tag disconnect');
|
||||
logout(false);
|
||||
super.disconnect();
|
||||
}
|
||||
|
||||
public function onCreate(game:ServerGame):Void {
|
||||
if (subscribed) {
|
||||
send(new Response().setRoomList(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 = -1;
|
||||
send(new Response().setRoom(new RoomResponse()));
|
||||
return;
|
||||
}
|
||||
case _:
|
||||
}
|
||||
send(new Response().setRoom(new RoomResponse().setRoom(game.room)));
|
||||
}
|
||||
if (subscribed) {
|
||||
send(new Response().setRoomList(listGame()));
|
||||
}
|
||||
}
|
||||
|
||||
public function onDelete(game:ServerGame):Void {
|
||||
if (gameId == game.id) {
|
||||
gameId = -1;
|
||||
send(new Response().setRoom(new RoomResponse()));
|
||||
}
|
||||
if (subscribed) {
|
||||
send(new Response().setRoomList(listGame()));
|
||||
}
|
||||
}
|
||||
|
||||
public function onEvent(game:ServerGame, event:GameEvent):Void {
|
||||
if (gameId == game.id) {
|
||||
send(new Response().setGameEvent(new GameEventResponse().setEvent(new GameEventProto().setTime(0).setEvent(Serializer.run(event)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,34 +5,34 @@ import cpp.net.ThreadServer;
|
||||
import sys.net.Socket;
|
||||
import haxe.io.Bytes;
|
||||
|
||||
typedef Session = Dynamic;
|
||||
typedef Message = Bytes;
|
||||
|
||||
typedef ClientMessage<M> = {
|
||||
var msg:M;
|
||||
var bytes:Int;
|
||||
}
|
||||
|
||||
class PuzzlezServer extends ThreadServer<Session, Message> {
|
||||
class PuzzlezServer extends ThreadServer<GameSession, Message> {
|
||||
|
||||
private static inline var TAG = 'Server';
|
||||
|
||||
override public function clientConnected(socket:Socket):Session {
|
||||
var session = null; // new Session(socket);
|
||||
override public function clientConnected(socket:Socket):GameSession {
|
||||
var session = new GameSession(socket);
|
||||
L.d(TAG, 'Client connected');
|
||||
return session;
|
||||
}
|
||||
|
||||
override public function clientDisconnected(session:Session) {
|
||||
override public function clientDisconnected(session:GameSession) {
|
||||
L.d(TAG, 'Client disconnected');
|
||||
//session.disconnect();
|
||||
}
|
||||
|
||||
override public function readClientMessage(session:Session, buf:Bytes, pos:Int, len:Int): ClientMessage<Message> {
|
||||
override public function readClientMessage(session:GameSession, buf:Bytes, pos:Int, len:Int): ClientMessage<Message> {
|
||||
//L.d(TAG, 'Client message: ${buf}');
|
||||
return {msg: buf.sub(pos, len), bytes: len};
|
||||
}
|
||||
|
||||
override public function clientMessage(session:Session, message:Message) {
|
||||
override public function clientMessage(session:GameSession, message:Message) {
|
||||
//session.pushData(bytes);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class PuzzlezServer extends ThreadServer<Session, Message> {
|
||||
L.d(TAG, 'Running');
|
||||
L.i(TAG, 'Build: ${CompilationOption.get("build")}');
|
||||
var host:String = Sys.args().length > 0 ? Sys.args()[0] : "0.0.0.0";
|
||||
var port:Int = Sys.args().length > 1 ? Std.parseInt(Sys.args()[1]) : 5000;
|
||||
var port:Int = Sys.args().length > 1 ? Std.parseInt(Sys.args()[1]) : 6000;
|
||||
var wserver = new PuzzlezServer();
|
||||
L.i(TAG, 'Start on ${host}:${port}');
|
||||
wserver.run(host, port);
|
||||
|
||||
4
src/server/haxe/ru/m/puzzlez/game/GameListener.hx
Normal file
4
src/server/haxe/ru/m/puzzlez/game/GameListener.hx
Normal file
@@ -0,0 +1,4 @@
|
||||
package ru.m.puzzlez.game;
|
||||
|
||||
interface GameListener {
|
||||
}
|
||||
124
src/server/haxe/ru/m/puzzlez/game/GameManager.hx
Normal file
124
src/server/haxe/ru/m/puzzlez/game/GameManager.hx
Normal file
@@ -0,0 +1,124 @@
|
||||
package ru.m.puzzlez.game;
|
||||
|
||||
import ru.m.puzzlez.core.GameEvent;
|
||||
import ru.m.puzzlez.game.IGameManager;
|
||||
import ru.m.puzzlez.proto.room.SlotProto;
|
||||
import ru.m.puzzlez.proto.room.RoomSlotProto;
|
||||
import ru.m.puzzlez.proto.core.GameProto;
|
||||
import ru.m.puzzlez.proto.room.RoomProto;
|
||||
import ru.m.puzzlez.proto.core.UserProto;
|
||||
|
||||
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);
|
||||
switch event {
|
||||
case COMPLETE:
|
||||
dispatcher.delete(game.id);
|
||||
dispose();
|
||||
case _:
|
||||
}
|
||||
}
|
||||
|
||||
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<Int, ServerGame>;
|
||||
public var gamesByCreator(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();
|
||||
gamesByCreator = new Map();
|
||||
gamesByUser = new Map();
|
||||
}
|
||||
|
||||
public function create(user:UserProto):ServerGame {
|
||||
if (gamesByCreator.exists(user.uuid)) {
|
||||
delete(gamesByCreator[user.uuid].id);
|
||||
}
|
||||
var room = new RoomProto()
|
||||
.setGame(
|
||||
new GameProto()
|
||||
.setId(++counter)
|
||||
)
|
||||
.setCreator(user);
|
||||
var game = new ServerGame(room);
|
||||
var slots:Array<RoomSlotProto> = [];
|
||||
game.room.setSlots(slots);
|
||||
games.push(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.join(user);
|
||||
gamesByUser[user.uuid] = game;
|
||||
changeSignal.emit(game, JOIN(user));
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(gameId:Int):Void {
|
||||
if (gamesById.exists(gameId)) {
|
||||
var game = gamesById[gameId];
|
||||
games.remove(game);
|
||||
gamesById.remove(game.id);
|
||||
gamesByCreator.remove(game.room.creator.uuid);
|
||||
deleteSignal.emit(game);
|
||||
}
|
||||
}
|
||||
|
||||
public function leave(user:UserProto):Void {
|
||||
/*if (gamesByCreator.exists(user.uuid)) {
|
||||
delete(gamesByCreator[user.uuid].proto.id);
|
||||
} else*/ if (gamesByUser.exists(user.uuid)) {
|
||||
var game = gamesByUser[user.uuid];
|
||||
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];
|
||||
changeSignal.emit(game, START);
|
||||
game.connect(new _GameListener(game, this));
|
||||
game.start();
|
||||
}
|
||||
}
|
||||
|
||||
public function dispatchEvent(game:ServerGame, event:GameEvent):Void {
|
||||
eventSignal.emit(game, event);
|
||||
}
|
||||
}
|
||||
44
src/server/haxe/ru/m/puzzlez/game/IGameManager.hx
Normal file
44
src/server/haxe/ru/m/puzzlez/game/IGameManager.hx
Normal file
@@ -0,0 +1,44 @@
|
||||
package ru.m.puzzlez.game;
|
||||
|
||||
import hw.signal.Signal;
|
||||
import ru.m.puzzlez.core.GameEvent;
|
||||
import ru.m.puzzlez.proto.core.UserProto;
|
||||
import ru.m.puzzlez.proto.room.SlotProto;
|
||||
|
||||
enum GameChange {
|
||||
JOIN(user:UserProto);
|
||||
LEAVE(user:UserProto);
|
||||
SLOT(user:UserProto, slot:SlotProto);
|
||||
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<Int, ServerGame>;
|
||||
public var gamesByCreator(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:UserProto):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;
|
||||
}
|
||||
72
src/server/haxe/ru/m/puzzlez/game/ServerGame.hx
Normal file
72
src/server/haxe/ru/m/puzzlez/game/ServerGame.hx
Normal file
@@ -0,0 +1,72 @@
|
||||
package ru.m.puzzlez.game;
|
||||
|
||||
import haxe.Timer;
|
||||
import ru.m.puzzlez.core.GameEvent;
|
||||
import ru.m.puzzlez.proto.core.UserProto;
|
||||
import ru.m.puzzlez.proto.room.RoomProto;
|
||||
import ru.m.puzzlez.proto.room.SlotProto;
|
||||
|
||||
@:dispatcher(GameListener) class ServerGame {
|
||||
|
||||
public var room(default, null):RoomProto;
|
||||
public var id(get, null):Int;
|
||||
|
||||
private var timer:Timer;
|
||||
|
||||
public function new(room:RoomProto) {
|
||||
this.room = room;
|
||||
}
|
||||
|
||||
private inline function get_id():Int {
|
||||
return room.game.id;
|
||||
}
|
||||
|
||||
public function contains(user:UserProto):Bool {
|
||||
for (slot in room.slots) {
|
||||
if (slot.hasUser() && slot.user.uuid == user.uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function join(user:UserProto):Void {
|
||||
if (!contains(user)) {
|
||||
room.users.push(user);
|
||||
}
|
||||
}
|
||||
|
||||
public function slot(user:UserProto, slot:SlotProto):Void {
|
||||
join(user);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public function start():Void {
|
||||
|
||||
}
|
||||
|
||||
public function restore():Array<GameEvent> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user