[common] add DesktopConnection

This commit is contained in:
2019-05-21 17:44:48 +03:00
parent 7984d8282c
commit a5722dfa9d
29 changed files with 646 additions and 217 deletions

9
.editorconfig Normal file
View File

@@ -0,0 +1,9 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

View File

@@ -124,7 +124,7 @@ const server = new Project(
config.branch({
name: 'server',
sources: ['src/server/haxe'],
main: 'ru.m.tankz.server.Server',
main: 'ru.m.tankz.server.TestServer',
})
).bind(module, gulp);

View File

@@ -79,7 +79,7 @@ class Init {
#elseif html5
connection = new ru.m.connect.js.JsConnection<Request, Response>(host, 5000, Response);
#else
connection = new ru.m.connect.fake.FakeConnection<Request, Response>(Response);
connection = new ru.m.connect.desktop.DesktopConnection<Request, Response>(host, 5000, Response);
#end
networkManager = new NetworkManager();
}

View File

@@ -146,5 +146,7 @@ class Style {
registerButton("close", "times-circle-solid.svg");
registerButton("next", "arrow-alt-circle-right-solid.svg");
registerButton("start", "play-circle-solid.svg");
registerButton("login", "sign-in-solid.svg");
registerButton("logout", "sign-out-solid.svg");
}
}

View File

@@ -1,70 +1,80 @@
package ru.m.tankz.network;
import ru.m.tankz.storage.MultiplayerStorage;
import haxework.storage.IStorage;
import haxework.signal.Signal;
import ru.m.tankz.proto.pack.GameRequest;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.proto.pack.StartGameRequest;
import ru.m.tankz.proto.game.GameChangeProto;
import ru.m.tankz.proto.game.GameActionTypeProto;
import ru.m.tankz.proto.pack.GameUpdateRequest;
import ru.m.connect.IConnection;
import ru.m.tankz.control.Control;
import ru.m.tankz.proto.core.GameInfoProto;
import ru.m.tankz.proto.game.GameActionTypeProto;
import ru.m.tankz.proto.game.GameChangeProto;
import ru.m.tankz.proto.pack.CreateGameRequest;
import ru.m.tankz.proto.pack.GameUpdateRequest;
import ru.m.tankz.proto.pack.JoinGameRequest;
import ru.m.tankz.proto.pack.LeaveGameRequest;
import ru.m.tankz.proto.pack.CreateGameRequest;
import ru.m.connect.IConnection;
import ru.m.tankz.proto.core.GameInfoProto;
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.storage.MultiplayerStorage;
typedef ClientConnection = IConnection<Request, Response>;
enum ConnectionState {
OFFLINE;
CONNECT;
CONNECTED;
LOGIN;
ONLINE(user:User);
ERROR(error:Dynamic);
}
class NetworkManager {
public var state(default, null):String;
public var stateSignal:Signal<String>;
public var state(default, null):ConnectionState;
public var stateSignal:Signal<ConnectionState>;
public var listGameSignal:Signal<Array<GameInfoProto>>;
public var gameSignal:Signal<GameInfoProto>;
public var gameUpdateSignal:Signal<Array<GameChangeProto>>;
public var user(default, null):User;
public var game(default, set):NetworkGame;
@:provide private var connection:ClientConnection;
@:provide private var storage:MultiplayerStorage;
public function new() {
stateSignal = new Signal<String>();
listGameSignal = new Signal<Array<GameInfoProto>>();
gameSignal = new Signal<GameInfoProto>();
gameUpdateSignal = new Signal<Array<GameChangeProto>>();
updateState('offline');
stateSignal = new Signal();
listGameSignal = new Signal();
gameSignal = new Signal();
gameUpdateSignal = new Signal();
updateState(OFFLINE);
connection.handler.connect(onConnectionEvent);
connection.receiveHandler.connect(onResponse);
user = storage.user;
if (user == null) {
user = {name: 'User', uuid: null};
var user = storage.user;
if (user != null) {
login(user.name, user.uuid);
}
}
private function updateState(value:String):Void {
private function updateState(value:ConnectionState):Void {
state = value;
stateSignal.emit(value);
}
public function login(name:String):Void {
user.name = name;
updateState('connect...');
public function login(name:String, uuid:String = null):Void {
updateState(CONNECT);
connection.connect().then(function(c:ClientConnection) {
updateState('login...');
updateState(LOGIN);
c.send(new Request().setLogin(
new LoginRequest()
.setUuid(user.uuid)
.setName(user.name)
.setUuid(uuid)
.setName(name)
));
}).catchError(function(_) {});
}).catchError(function(error) {
updateState(ERROR(error));
});
}
public function logout():Void {
connection.send(new Request().setLogout(new LogoutRequest()));
}
public function listGame():Void {
@@ -108,30 +118,30 @@ class NetworkManager {
}
private function onConnectionEvent(event:ConnectionEvent):Void {
updateState(switch (event) {
case ConnectionEvent.CONNECTED:
updateState(switch event {
case CONNECTED:
L.d('Network', '$event');
'connected';
case ConnectionEvent.DISCONNECTED:
CONNECTED;
case DISCONNECTED:
L.d('Network', '$event');
'offline';
case ConnectionEvent.ERROR(error):
OFFLINE;
case ERROR(error):
L.e('Network', '$error', error);
'error';
ERROR(error);
});
}
private function onResponse(packet:Response):Void {
if (packet.hasLogin()) {
user = {
var user = {
uuid: packet.login.user.uuid,
name: packet.login.user.name,
};
storage.user = user;
updateState('online');
updateState(ONLINE(user));
} else if (packet.hasLogout()) {
user = null;
updateState('connected');
storage.user = null;
updateState(CONNECTED);
} else if (packet.hasListGame()) {
listGameSignal.emit(packet.listGame.games);
} else if (packet.hasCreateGame()) {
@@ -145,13 +155,7 @@ class NetworkManager {
} else if (packet.hasUpdateGame()) {
gameUpdateSignal.emit(packet.updateGame.changes);
} else if (packet.hasGame()) {
game.load(packet.game.game);
//game.load(packet.game.game);
}
}
private function set_game(value:NetworkGame):NetworkGame {
this.game = value;
connection.send(new Request().setGame(new GameRequest()));
return this.game;
}
}

View File

@@ -1,25 +1,69 @@
package ru.m.tankz.view;
import haxework.view.ButtonView;
import haxework.view.LabelView;
import haxework.view.frame.FrameSwitcher;
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.popup.FontPopup;
import ru.m.tankz.view.popup.LoginPopup;
@:template class StartFrame extends VGroupView {
public static var ID(default, never):String = "start";
@:view var username:LabelView;
@:view("login") var loginButton:ButtonView;
@:view("logout") var logoutButton:ButtonView;
@:view("network") var networkButton:ButtonView;
@:provide var state:GameState;
@:provide var switcher:FrameSwitcher;
@:provide var network:NetworkManager;
private var fontPopup:FontPopup;
public function onShow():Void {
onConnectionState(network.state);
network.stateSignal.connect(onConnectionState);
}
public function onHide():Void {
network.stateSignal.disconnect(onConnectionState);
}
private function onConnectionState(state:ConnectionState):Void {
trace("state", state);
setUser(switch state {
case ONLINE(user): user;
case _: null;
});
}
private function setUser(value:User):Void {
username.text = value == null ? "" : value.name;
loginButton.visible = value == null;
logoutButton.visible = value != null;
networkButton.disabled = value == null;
}
private function startGame(type:GameType):Void {
state = new GameState(type);
switcher.change(LevelFrame.ID);
}
private function login():Void {
LoginPopup.instance.show().then(function(user:User):Void {
L.d("Login", 'user: $user');
});
}
private function logout():Void {
network.logout();
}
private function choiceFont():Void {
if (fontPopup == null) {
fontPopup = new FontPopup();

View File

@@ -25,6 +25,12 @@ views:
skinId: button
+onPress: $code:switcher.change('record')
text: Records
- id: network
$type: haxework.view.ButtonView
skinId: button
# +onPress: $code:switcher.change('record')
text: Network
disabled: true
- $type: haxework.view.HGroupView
skinId: panel
views:
@@ -34,7 +40,24 @@ views:
+onPress: $code:switcher.change('settings')
- $type: haxework.view.SpriteView
geometry.size.width: 100%
- id: username
$type: haxework.view.LabelView
skinId: text
geometry.margin.right: 10
- id: login
$type: haxework.view.ButtonView
skinId: button.login
+onPress: $code:login()
- id: logout
$type: haxework.view.ButtonView
skinId: button.logout
+onPress: $code:logout()
visible: false
- $type: haxework.view.LabelView
geometry.hAlign: right
geometry.vAlign: top
geometry.padding: [20, 5]
geometry.position: absolute
geometry.margin: [0, 20, 20, 0]
skinId: text.box
text: $r:text:version

View File

@@ -0,0 +1,47 @@
package ru.m.tankz.view.popup;
import haxework.log.BaseLogger.LoggerUtil;
import haxework.view.InputView;
import haxework.view.popup.PopupView;
import haxework.view.TextView;
import ru.m.tankz.network.NetworkManager;
@:template class LoginPopup extends PopupView<User> {
@:view var username:InputView;
@:view var password:InputView;
@:view var error:TextView;
@:provide static var network:NetworkManager;
override private function onShow():Void {
super.onShow();
network.stateSignal.connect(onStateChange);
}
override private function onClose():Void {
super.onClose();
network.stateSignal.disconnect(onStateChange);
}
private function onStateChange(state:ConnectionState):Void {
switch state {
case ONLINE(user): close(user);
case ERROR(error): this.error.text = LoggerUtil.printError(error);
case _: this.error.text = null;
}
}
private function submit():Void {
network.login(username.text);
}
public static var instance(get, null):LoginPopup;
private static function get_instance():LoginPopup {
if (instance == null) {
instance = new LoginPopup();
}
return instance;
}
}

View File

@@ -0,0 +1,64 @@
---
layout.hAlign: center
layout.vAlign: middle
view:
$type: haxework.view.VGroupView
layout.hAlign: center
geometry.size.width: 400
# geometry.size.height: 400
skinId: window
views:
- $type: haxework.view.HGroupView
geometry.size.width: 100%
geometry.padding: 10
layout.vAlign: middle
views:
- id: name
$type: haxework.view.LabelView
geometry.size.width: 100%
geometry.margin.left: 10
layout.hAlign: left
skinId: text
text: Login
- $type: haxework.view.ButtonView
skinId: window.close
+onPress: $code:reject('close')
- $type: haxework.view.VGroupView
geometry.size.width: 100%
# geometry.size.stretch: true
geometry.padding: 20
layout.margin: 5
views:
- $type: haxework.view.LabelView
geometry.size.width: 100%
skinId: text
text: Username
- id: username
$type: haxework.view.InputView
geometry.size.width: 100%
geometry.size.height: 28
skinId: text.box
- $type: haxework.view.LabelView
geometry.size.width: 100%
skinId: text
text: Password
- id: password
$type: haxework.view.InputView
textField.displayAsPassword: true
geometry.size.width: 100%
geometry.size.height: 28
skinId: text.box
- id: error
$type: haxework.view.TextView
geometry.size.width: 100%
skinId: text
fill: false
- $type: haxework.view.HGroupView
layout.hAlign: center
layout.margin: 5
skinId: panel
views:
- $type: haxework.view.ButtonView
skinId: button.simple
text: Submit
+onPress: $code:submit()

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sign-in" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-sign-in fa-w-16 fa-2x"><path fill="currentColor" d="M137.2 110.3l21.9-21.9c9.3-9.3 24.5-9.4 33.9-.1L344.9 239c9.5 9.4 9.5 24.7 0 34.1L193 423.7c-9.4 9.3-24.5 9.3-33.9-.1l-21.9-21.9c-9.7-9.7-9.3-25.4.8-34.7l77.6-71.1H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h191.5l-77.6-71.1c-10-9.1-10.4-24.9-.7-34.5zM512 352V160c0-53-43-96-96-96h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h84c17.7 0 32 14.3 32 32v192c0 17.7-14.3 32-32 32h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h84c53 0 96-43 96-96z" class=""></path></svg>

After

Width:  |  Height:  |  Size: 698 B

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sign-out" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-sign-out fa-w-16 fa-2x"><path fill="currentColor" d="M180 448H96c-53 0-96-43-96-96V160c0-53 43-96 96-96h84c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H96c-17.7 0-32 14.3-32 32v192c0 17.7 14.3 32 32 32h84c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm117.9-303.1l77.6 71.1H184c-13.3 0-24 10.7-24 24v32c0 13.3 10.7 24 24 24h191.5l-77.6 71.1c-10.1 9.2-10.4 25-.8 34.7l21.9 21.9c9.3 9.3 24.5 9.4 33.9.1l152-150.8c9.5-9.4 9.5-24.7 0-34.1L353 88.3c-9.4-9.3-24.5-9.3-33.9.1l-21.9 21.9c-9.7 9.6-9.3 25.4.7 34.6z" class=""></path></svg>

After

Width:  |  Height:  |  Size: 695 B

View File

@@ -7,7 +7,6 @@ import promhx.Promise;
import protohx.Message;
import ru.m.connect.IConnection;
class BaseConnection<O:Message, I:Message> implements IConnection<O, I> {
public var handler(default, null):Signal<ConnectionEvent>;
public var sendHandler(default, null):Signal<O>;
@@ -17,12 +16,11 @@ class BaseConnection<O:Message, I:Message> implements IConnection<O, I> {
private var connectDeferred:Deferred<IConnection<O, I>>;
public function new(i:Class<I>) {
queue = new PacketQueue<I>(i);
public function new(inputFactory:Class<I>) {
queue = new PacketQueue<I>(inputFactory);
handler = new Signal<ConnectionEvent>();
sendHandler = new Signal<O>();
receiveHandler = new Signal<I>();
connectDeferred = new Deferred();
}
public function connect():Promise<IConnection<O, I>> {

View File

@@ -5,7 +5,6 @@ import haxe.io.Bytes;
import promhx.Promise;
import protohx.Message;
enum ConnectionEvent {
CONNECTED;
DISCONNECTED;

View File

@@ -0,0 +1,78 @@
package ru.m.connect.desktop;
import cpp.vm.Thread;
import haxe.io.BytesOutput;
import haxe.Timer;
import promhx.Deferred;
import promhx.Promise;
import protohx.Message;
import ru.m.connect.IConnection;
import sys.net.Host;
import sys.net.Socket;
class DesktopConnection<O:Message, I:Message> extends BaseConnection<O, I> {
private var host:String;
private var port:Int;
private var socket:Socket;
private var reader:Thread;
public function new(host:String, port:Int, inputFactory:Class<I>) {
super(inputFactory);
this.host = host;
this.port = port;
connected = false;
socket = new Socket();
socket.setFastSend(true);
socket.output.bigEndian = false;
socket.input.bigEndian = false;
sendHandler.connect(_send);
}
override public function connect():Promise<IConnection<O, I>> {
connectDeferred = new Deferred();
try {
if (connected) {
connectDeferred.resolve(this);
} else {
socket.connect(new Host(host), port);
connected = true;
reader = Thread.create(_read);
connectDeferred.resolve(this);
}
} catch (error:Dynamic) {
Timer.delay(function() connectDeferred.throwError(error), 1);
}
return connectDeferred.promise();
}
override public function disconnect():Void {
socket.close();
connected = false;
handler.emit(DISCONNECTED);
}
private function _read():Void {
try {
while (connected) {
socket.waitForRead();
var size = socket.input.readUInt16();
var data = socket.input.read(size);
var packet:I = Type.createInstance(queue.packetClass, []);
packet.mergeFrom(data);
receiveHandler.emit(packet);
}
} catch (error:Dynamic) {
handler.emit(ERROR(error));
}
}
private function _send(packet:O):Void {
var out = new BytesOutput();
packet.writeTo(out);
var bytes = out.getBytes();
socket.output.writeUInt16(bytes.length);
socket.output.write(bytes);
socket.output.flush();
}
}

View File

@@ -1,18 +1,18 @@
package ru.m.connect.flash;
import ru.m.connect.IConnection.ConnectionEvent;
import promhx.Promise;
import flash.utils.Endian;
import haxe.io.BytesOutput;
import protohx.Message;
import haxe.io.Bytes;
import flash.events.ErrorEvent;
import flash.events.ProgressEvent;
import flash.events.Event;
import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.Endian;
import haxe.io.Bytes;
import haxe.io.BytesOutput;
import promhx.Deferred;
import promhx.Promise;
import protohx.Message;
import ru.m.connect.IConnection;
class FlashConnection<O:Message, I:Message> extends BaseConnection<O, I> {
@@ -20,8 +20,8 @@ class FlashConnection<O:Message, I:Message> extends BaseConnection<O, I> {
private var port:Int;
private var socket:Socket;
public function new(host:String, port:Int, i:Class<I>) {
super(i);
public function new(host:String, port:Int, inputFactory:Class<I>) {
super(inputFactory);
this.host = host;
this.port = port;
connected = false;
@@ -37,14 +37,15 @@ class FlashConnection<O:Message, I:Message> extends BaseConnection<O, I> {
override public function connect():Promise<IConnection<O, I>> {
socket.connect(host, port);
connectDeferred = new Deferred();
return connectDeferred.promise();
}
override public function disconnect():Void {
if (socket.connected) {
socket.close();
//connected = false;
//handler.emit(ConnectionEvent.DISCONNECTED);
connected = false;
handler.emit(ConnectionEvent.DISCONNECTED);
}
}
@@ -52,13 +53,19 @@ class FlashConnection<O:Message, I:Message> extends BaseConnection<O, I> {
socket.close();
connected = false;
handler.emit(ConnectionEvent.ERROR(event));
if (connectDeferred != null) {
connectDeferred.throwError(event);
connectDeferred = null;
}
}
private function onConnect(_):Void {
connected = true;
handler.emit(ConnectionEvent.CONNECTED);
if (connectDeferred != null) {
connectDeferred.resolve(this);
connectDeferred = null;
}
}
private function onClose(_):Void {

View File

@@ -2,11 +2,11 @@ package ru.m.connect.js;
import js.Browser;
import js.html.WebSocket;
import promhx.Deferred;
import promhx.Promise;
import protohx.Message;
import ru.m.Base64;
import ru.m.connect.IConnection.ConnectionEvent;
import ru.m.connect.IConnection;
class JsConnection<O:Message, I:Message> extends BaseConnection<O, I> {
@@ -14,8 +14,8 @@ class JsConnection<O:Message, I:Message> extends BaseConnection<O, I> {
private var port:Int;
private var socket:WebSocket;
public function new(host:String, port:Int, i:Class<I>) {
super(i);
public function new(host:String, port:Int, inputFactory:Class<I>) {
super(inputFactory);
this.host = host;
this.port = port;
connected = false;
@@ -38,11 +38,12 @@ class JsConnection<O:Message, I:Message> extends BaseConnection<O, I> {
socket.onclose = this.onClose;
socket.onerror = this.onError;
socket.onmessage = this.onSocketData;
connectDeferred = new Deferred();
return connectDeferred.promise();
}
override public function disconnect():Void {
socket.close();
socket.close(1000);
connected = false;
}

View File

@@ -4,7 +4,6 @@ import haxe.io.BytesOutput;
import protohx.Message;
import sys.net.Socket;
class NekoConnection<O:Message, I:Message> extends BaseConnection<O, I> {
public var socket(default, null):Socket;

View File

@@ -2,11 +2,10 @@ package ru.m.connect.neko;
import haxe.crypto.BaseCode;
import haxe.crypto.Sha1;
import protohx.Message;
import haxe.io.Bytes;
import protohx.Message;
import sys.net.Socket;
class NekoWebConnection<O:Message, I:Message> extends NekoConnection<O, I> {
private var opened:Bool;

View File

@@ -1,18 +0,0 @@
package ru.m.tankz.network;
import ru.m.tankz.game.Game;
import ru.m.tankz.proto.core.GameProto;
class NetworkGame extends Game {
private static var TAG(default, never):String = 'NetworkGame';
public function load(proto:GameProto):Void {
L.w(TAG, 'load: ${proto}');
// ToDo:
}
public function export():GameProto {
return new GameProto();
}
}

View File

@@ -11,12 +11,12 @@ import ru.m.tankz.bundle.IConfigBundle;
import ru.m.tankz.bundle.ILevelBundle;
import ru.m.tankz.server.bundle.ServerConfigBundle;
import ru.m.tankz.server.bundle.ServerLevelBundle;
import ru.m.tankz.server.session.Session;
import ru.m.tankz.server.session._Session;
import sys.net.Socket;
#if debug import haxework.log.SocketLogger; #end
class Server extends ThreadServer<Session, Bytes> {
class Server extends ThreadServer<_Session, Bytes> {
private static inline var TAG = 'Server';
@@ -24,23 +24,23 @@ class Server extends ThreadServer<Session, Bytes> {
super();
}
override public function clientConnected(s:Socket):Session {
var session = new Session(s);
override public function clientConnected(s:Socket):_Session {
var session = new _Session(s);
L.d(TAG, 'Client connected');
return session;
}
override public function clientDisconnected(session:Session) {
override public function clientDisconnected(session:_Session) {
L.d(TAG, 'Client disconnected');
session.connection.handler.emit(ConnectionEvent.DISCONNECTED);
}
override public function readClientMessage(session:Session, buf:Bytes, pos:Int, len:Int) {
override public function readClientMessage(session:_Session, buf:Bytes, pos:Int, len:Int) {
//L.d(TAG, 'Client message: ${buf}');
return {msg: buf.sub(pos, len), bytes: len};
}
override public function clientMessage(session:Session, bytes:Bytes) {
override public function clientMessage(session:_Session, bytes:Bytes) {
try {
session.pushData(bytes);
} catch (error:Dynamic) {

View File

@@ -0,0 +1,46 @@
package ru.m.tankz.server;
import haxe.io.Bytes;
import haxework.log.TraceLogger;
import neko.net.ThreadServer;
import ru.m.tankz.server.session.GameSession;
import sys.net.Socket;
class TestServer extends ThreadServer<GameSession, Bytes> {
private static inline var TAG = 'Server';
public function new() {
super();
}
override public function clientConnected(socket:Socket):GameSession {
var session = new GameSession(socket);
L.d(TAG, 'Client connected');
return session;
}
override public function clientDisconnected(session:GameSession) {
L.d(TAG, 'Client disconnected');
session.disconnect();
}
override public function readClientMessage(session:GameSession, buf:Bytes, pos:Int, len:Int) {
//L.d(TAG, 'Client message: ${buf}');
return {msg: buf.sub(pos, len), bytes: len};
}
override public function clientMessage(session:GameSession, bytes:Bytes) {
session.pushData(bytes);
}
public static function main() {
L.push(new TraceLogger());
L.d(TAG, 'Running');
var host:String = Sys.args().length > 0 ? Sys.args()[0] : "localhost";
var port:Int = Sys.args().length > 1 ? Std.parseInt(Sys.args()[1]) : 5000;
var wserver = new TestServer();
L.i(TAG, 'Start on ${host}:${port}');
wserver.run(host, port);
}
}

View File

@@ -8,7 +8,6 @@ import sys.io.File;
import yaml.Parser;
import yaml.Yaml;
class ServerConfigBundle implements IConfigBundle {
public function new() {}

View File

@@ -1,7 +1,8 @@
package ru.m.tankz.server.game;
import ru.m.tankz.game.Game;
import ru.m.tankz.game.IGame;
import ru.m.tankz.game.GameState;
import ru.m.tankz.network.NetworkGame;
import ru.m.tankz.preset.ClassicGame;
import ru.m.tankz.proto.pack.StartGameResponse;
import ru.m.tankz.proto.pack.LeaveGameResponse;
@@ -13,7 +14,7 @@ import ru.m.tankz.proto.core.GameStateProto;
import ru.m.tankz.proto.core.GameInfoProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.server.session.Thread;
import ru.m.tankz.server.session.Session;
import ru.m.tankz.server.session._Session;
/**
@@ -58,7 +59,7 @@ class GameManager {
private static var idCounter:Int = 0;
public var gameInfo(default, null):GameInfoProto;
public var game(default, null):NetworkGame;
public var game(default, null):IGame;
private var timer:NekoTimer;
@@ -83,14 +84,14 @@ class GameManager {
public function broadcastGames() {
var packet = new Response().setListGame(new ListGameResponse().setGames(getReadyGames()));
for (personId in subscribers.keys()) {
var session:Session = Session.sessions.get(personId);
var session:_Session = _Session.sessions.get(personId);
session.send(packet);
}
}
public function broadcast(packet:Response) {
for (player in gameInfo.players) {
var session:Session = Session.sessions.get(player.uuid);
var session:_Session = _Session.sessions.get(player.uuid);
session.send(packet);
}
}
@@ -105,7 +106,7 @@ class GameManager {
gameInfo.setPlayers(gameInfo.players.filter(function(p:UserProto) return p.uuid != user.uuid));
byPersonId.remove(user.uuid);
var packet = new Response().setLeaveGame(new LeaveGameResponse().setGame(gameInfo));
Session.sessions.get(user.uuid).send(packet);
_Session.sessions.get(user.uuid).send(packet);
if (gameInfo.players.length == 0/* || person.id == game.creator.id*/) {
stop();
} else {
@@ -115,8 +116,9 @@ class GameManager {
public function start() {
gameInfo.setState(GameStateProto.STARTED);
game = new NetworkGame(ClassicGame.TYPE);
game.start(new GameState(ClassicGame.TYPE,ClassicGame.PLAYER1));
var state = new GameState(ClassicGame.TYPE);
game = new Game(state);
//game.start(new GameState(ClassicGame.TYPE,ClassicGame.PLAYER1));
timer = new NekoTimer(30);
timer.run = update;
broadcast(new Response().setStartGame(new StartGameResponse().setGame(gameInfo)));
@@ -136,7 +138,7 @@ class GameManager {
}
private function update() {
game.engine.update();
//game.engine.update();
/*var changes = engine.update();
changes = this.changes.concat(changes);
this.changes = [];

View File

@@ -0,0 +1,42 @@
package ru.m.tankz.server.session;
import ru.m.tankz.proto.pack.LogoutResponse;
import ru.m.tankz.proto.pack.LogoutRequest;
import com.hurlant.crypto.extra.UUID;
import com.hurlant.crypto.prng.Random;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.pack.LoginRequest;
import ru.m.tankz.proto.pack.LoginResponse;
import ru.m.tankz.proto.pack.Request;
import ru.m.tankz.proto.pack.Response;
import sys.net.Socket;
class GameSession extends ProtoSession<Response, Request> {
private static inline var TAG = "Session";
public var user(default, null):UserProto;
public function new(socket:Socket) {
super(socket, Request);
}
private function onLogin(request:LoginRequest):LoginResponse {
user = new UserProto()
.setUuid(request.uuid != null ? request.uuid : UUID.generateRandom(new Random()).toString())
.setName(request.name);
return new LoginResponse().setUser(user);
}
private function onLogout(request:LogoutRequest):LogoutResponse {
return new LogoutResponse();
}
override private function onRequest(request:Request):Void {
L.d(TAG, 'onRequest: ${request}');
if (request.hasLogin()) {
send(new Response().setLogin(onLogin(request.login)));
} else if (request.hasLogout()) {
send(new Response().setLogout(onLogout(request.logout)));
}
}
}

View File

@@ -0,0 +1,8 @@
package ru.m.tankz.server.session;
import haxe.io.Bytes;
interface ISession {
public function pushData(bytes:Bytes):Void;
public function disconnect():Void;
}

View File

@@ -0,0 +1,73 @@
package ru.m.tankz.server.session;
import ru.m.connect.neko.NekoWebConnection;
import haxe.io.Bytes;
import protohx.Message;
import ru.m.connect.IConnection;
import ru.m.connect.neko.NekoConnection;
import sys.net.Socket;
class ProtoSession<O:Message, I:Message> implements ISession {
private static inline var TAG = "Session";
private static var POLICY_FILE:String = [
"<?xml version=\"1.0\"?>",
"<!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">",
"<cross-domain-policy>",
"<site-control permitted-cross-domain-policies=\"master-only\"/>",
"<allow-access-from domain=\"*\" to-ports=\"*\"/>",
"</cross-domain-policy>"
].join("\n");
public var connection(default, null):IConnection<O, I>;
private var socket:Socket;
private var request:Class<I>;
public function new(socket:Socket, request:Class<I>) {
this.socket = socket;
this.request = request;
}
private function buildConnection(bytes:Bytes):IConnection<O, I> {
var str:String = bytes.getString(0, bytes.length);
if (str == "<policy-file-request/>" + String.fromCharCode(0)) {
L.d(TAG, "policy-file-request");
socket.output.writeString(POLICY_FILE + String.fromCharCode(0));
socket.output.flush();
return null;
}
if (StringTools.startsWith(str, "GET")) {
connection = new NekoWebConnection<O, I>(socket, request);
} else {
connection = new NekoConnection<O, I>(socket, request);
}
connection.handler.connect(onConnectionEvent);
connection.receiveHandler.connect(onRequest);
return connection;
}
public function send(packet:O):Void {
connection.send(packet);
}
public function pushData(bytes:Bytes):Void {
if (connection == null) {
connection = buildConnection(bytes);
}
if (connection != null) {
connection.pushData(bytes);
}
}
public function disconnect():Void {
connection.handler.emit(ConnectionEvent.DISCONNECTED);
}
private function onConnectionEvent(event:ConnectionEvent):Void {
L.d(TAG, 'onConnectionEvent: ${event}');
}
private function onRequest(request:I):Void {
L.d(TAG, 'onRequest: ${request}');
}
}

View File

@@ -31,7 +31,7 @@ import sys.net.Socket;
typedef ServerConnection = IConnection<Response, Request>;
class Session {
class _Session {
private static inline var TAG = 'Session';
private static var POLICY_FILE:String = [
@@ -43,7 +43,7 @@ class Session {
'</cross-domain-policy>'
].join('\n');
public static var sessions:Map<String, Session> = new Map<String, Session>();
public static var sessions:Map<String, _Session> = new Map<String, _Session>();
public var user(default, null):UserProto;
public var gameId(default, null):Int = -1;
@@ -150,6 +150,7 @@ class Session {
private function game(request:GameRequest):GameResponse {
var gameManager:GameManager = GameManager.byPersonId.get(user.uuid);
return new GameResponse().setGame(gameManager.game.export());
return new GameResponse();
//return new GameResponse().setGame(gameManager.game.export());
}
}