[network] added NetworkFrame

This commit is contained in:
2018-02-21 17:46:52 +03:00
parent db2339ab3a
commit dd447656f8
17 changed files with 377 additions and 202 deletions

View File

@@ -105,7 +105,7 @@ exports['client'] = gulp.series(
const testFlash = function() {
const argv = yargs.argv;
return build('flash')()
return build('flash', {proto_debug: true})()
.pipe(new FlashPlayer().run(argv.dev))
.pipe(debug());
};

View File

@@ -8,6 +8,12 @@ const prepare = require('./prepare');
const debug = require('../tasks/debug');
const generate = () => function generate() {
return new Haxe().haxelib([
'run', 'protohx', 'generate', 'protohx.json'
]);
};
const build = () => function build() {
const argv = yargs.argv;
return gulp.src('.')
@@ -18,6 +24,7 @@ const build = () => function build() {
'protohx',
'orm',
'haxework:git',
'haxe-crypto'
],
cp: [
'src/common/haxe',
@@ -27,6 +34,9 @@ const build = () => function build() {
main: 'ru.m.tankz.server.Server',
outputFile: 'tankz.n',
debug: argv.dev,
values: {
proto_debug: true
}
}))
.pipe(gulp.dest('target'));
};
@@ -39,5 +49,5 @@ const test = (build) => function test() {
};
exports['server'] = gulp.series(prepare(Haxe.ID), build());
exports['server:test'] = gulp.series(prepare(Haxe.ID, FlashPlayer.ID), test(build()));
exports['server'] = gulp.series(prepare(Haxe.ID), generate(), build());
exports['server:test'] = gulp.series(prepare(Haxe.ID, FlashPlayer.ID), generate(), test(build()));

View File

@@ -38,6 +38,7 @@
"yaml": "1.3.0",
"haxework": "git@bitbucket.org:shmyga/haxework.git",
"orm": "2.1.0",
"yield": "1.1.2"
"yield": "1.1.2",
"haxe-crypto": "0.0.7"
}
}

View File

@@ -1,5 +1,6 @@
package ru.m.tankz;
import ru.m.tankz.storage.UserStorage;
import openfl.Assets;
import ru.m.tankz.sound.SoundManager;
import flash.events.KeyboardEvent;
@@ -70,14 +71,16 @@ class Client implements IConnectionHandler {
Provider.set(IConnection, new ru.m.connect.flash.FlashConnection('localhost', 5001));
#elseif html5
Provider.set(IConnection, new ru.m.connect.js.JsConnection('localhost', 5001));
#else
Provider.set(IConnection, new ru.m.connect.fake.FakeConnection());
#end
//Provider.get(IConnection).handler.addListener(this);
Provider.get(IConnection).handler.addListener(this);
view = new ClientView();
Provider.set(IFrameSwitcher, view.switcher);
Root.bind(view);
view.content.stage.stageFocusRect = false;
//view.logout.onPress = this;
view.content.stage.addEventListener(KeyboardEvent.KEY_UP, function(event:KeyboardEvent):Void {
if (event.keyCode == Keyboard.ESCAPE) {
@@ -88,6 +91,7 @@ class Client implements IConnectionHandler {
Provider.setFactory(IConfigBundle, ConfigBundle);
Provider.setFactory(ILevelBundle, LevelBundle);
Provider.setFactory(SaveStorage, SaveStorage);
Provider.setFactory(UserStorage, UserStorage);
Provider.setFactory(SoundManager, SoundManager);
Provider.setFactory(Game, ClassicGame, ClassicGame.TYPE);
Provider.setFactory(Game, DotaGame, DotaGame.TYPE);
@@ -110,11 +114,11 @@ class Client implements IConnectionHandler {
public function onConnected():Void {}
public function onDisconnected():Void {
//view.switcher.change(AuthFrame.ID);
view.switcher.change(StartFrame.ID);
}
public function onError(error:Dynamic):Void {
L.e(TAG, '', error);
//view.switcher.change(AuthFrame.ID);
view.switcher.change(StartFrame.ID);
}
}

View File

@@ -18,6 +18,8 @@ views:
$type: ru.m.tankz.frame.LevelFrame
- id: game
$type: ru.m.tankz.frame.GameFrame
- id: network
$type: ru.m.tankz.frame.NetworkFrame
- $type: haxework.gui.LabelView
$style: label
inLayout: false

View File

@@ -0,0 +1,88 @@
package ru.m.tankz.frame;
import haxework.gui.ButtonView;
import haxework.gui.InputView;
import haxework.gui.LabelView;
import haxework.gui.VGroupView;
import haxework.gui.ViewBuilder;
import haxework.provider.Provider;
import protohx.Message;
import ru.m.connect.IConnection;
import ru.m.tankz.proto.pack.LoginRequest;
import ru.m.tankz.proto.pack.LoginResponse;
import ru.m.tankz.storage.UserStorage;
interface NetworkFrameLayout {
var stateLabel(default, null):LabelView;
var nameInput(default, null):InputView;
var loginButton(default, null):ButtonView;
}
@:template("ru/m/tankz/frame/NetworkFrame.yaml", "ru/m/tankz/Style.yaml")
class NetworkFrame extends VGroupView implements ViewBuilder implements NetworkFrameLayout implements IPacketHandler implements IConnectionHandler {
public static var ID(default, never):String = "network";
private var state(null, set):String;
private function set_state(value:String):String {
stateLabel.text = value;
loginButton.disabled = value != 'online';
return value;
}
public function init():Void {
loginButton.onPress = this;
}
public function onShow():Void {
var user:User = Provider.get(UserStorage).read();
nameInput.text = user.name;
var connection:IConnection = Provider.get(IConnection);
connection.packetHandler.addListener(this);
connection.handler.addListener(this);
state = connection.connected ? 'online' : 'offline';
if (!connection.connected) {
connection.connect();
}
}
public function onHide():Void {
Provider.get(IConnection).packetHandler.removeListener(this);
Provider.get(IConnection).handler.removeListener(this);
}
public function onPress(view:ButtonView):Void {
var user:User = Provider.get(UserStorage).read();
user.name = nameInput.text;
Provider.get(IConnection).send(
new LoginRequest()
.setUuid(user.uuid)
.setName(user.name)
);
}
public function onLoginResponse(packet:LoginResponse):Void {
var user:User = {
uuid: packet.user.uuid,
name: packet.user.name,
};
Provider.get(UserStorage).write(user);
//Provider.set(User, user);
state = 'logined';
}
public function onPacket(packet:Message):Void {}
public function onConnected():Void {
state = 'online';
}
public function onDisconnected():Void {
state = 'offline';
}
public function onError(error:Dynamic):Void {
state = 'offline';
}
}

View File

@@ -0,0 +1,23 @@
---
pWidth: 100
pHeight: 100
views:
- id: stateLabel
$type: haxework.gui.LabelView
$style: label
text: offline
width: 200
height: 50
- id: nameInput
$type: haxework.gui.InputView
$style: label
width: 200
height: 50
text: User
skin:
$type: haxework.gui.skin.ColorSkin
color: '#444444'
- id: loginButton
$type: haxework.gui.ButtonView
$style: button
text: Login

View File

@@ -19,12 +19,13 @@ interface StartFrameLayout {
var dota_1p(default, null):ButtonView;
var dota_2p_coop(default, null):ButtonView;
var dota_2p_vs(default, null):ButtonView;
var network(default, null):ButtonView;
}
@:template("ru/m/tankz/frame/StartFrame.yaml", "ru/m/tankz/Style.yaml")
class StartFrame extends VGroupView implements ViewBuilder implements StartFrameLayout {
public static inline var ID = "start";
public static var ID(default, never):String = "start";
public function init():Void {
classic_1p.onPress = this;
@@ -33,6 +34,7 @@ class StartFrame extends VGroupView implements ViewBuilder implements StartFrame
dota_1p.onPress = this;
dota_2p_coop.onPress = this;
dota_2p_vs.onPress = this;
network.onPress = this;
}
public function onShow():Void {
@@ -59,6 +61,8 @@ class StartFrame extends VGroupView implements ViewBuilder implements StartFrame
startGame(DotaGame.TYPE, DotaGame.PLAYER2_COOP);
case 'dota_2p_vs':
startGame(DotaGame.TYPE, DotaGame.PLAYER2_VS);
case 'network':
Provider.get(IFrameSwitcher).change(NetworkFrame.ID);
}
}

View File

@@ -2,43 +2,66 @@
pWidth: 100
pHeight: 100
views:
# logo
- $type: haxework.gui.ImageView
image: "@asset:image:resources/image/ui/logo.png"
contentSize: true
bottomMargin: 15
- $type: haxework.gui.HGroupView
contentSize: true
views:
- $type: haxework.gui.VGroupView
contentSize: true
views:
# classic
- $type: haxework.gui.LabelView
$style: label
fontSize: 20
topMargin: 15
contentSize: true
text: Classic
- id: classic_1p
$type: haxework.gui.ButtonView
text: 1 Player
$style: button
- id: classic_2p
$type: haxework.gui.ButtonView
text: 2 Player
$style: button
- id: classic_load
$type: haxework.gui.ButtonView
text: Load
$style: button
- $type: haxework.gui.VGroupView
contentSize: true
views:
# dota
- $type: haxework.gui.LabelView
$style: label
fontSize: 20
topMargin: 15
contentSize: true
text: DotA
- id: dota_1p
$type: haxework.gui.ButtonView
text: 1 Player
$style: button
- id: dota_2p_coop
$type: haxework.gui.ButtonView
text: 2 COOP
$style: button
- id: dota_2p_vs
$type: haxework.gui.ButtonView
text: 2 VS
$style: button
# network
- $type: haxework.gui.LabelView
$style: label
fontSize: 20
topMargin: 15
contentSize: true
text: Classic
- id: classic_1p
text: Network
- id: network
$type: haxework.gui.ButtonView
text: 1 Player
$style: button
- id: classic_2p
$type: haxework.gui.ButtonView
text: 2 Player
$style: button
- id: classic_load
$type: haxework.gui.ButtonView
text: Load
$style: button
- $type: haxework.gui.LabelView
$style: label
fontSize: 20
topMargin: 15
contentSize: true
text: DotA
- id: dota_1p
$type: haxework.gui.ButtonView
text: 1 Player
$style: button
- id: dota_2p_coop
$type: haxework.gui.ButtonView
text: 2 COOP
$style: button
- id: dota_2p_vs
$type: haxework.gui.ButtonView
text: 2 VS
$style: button
text: Network
$style: button

View File

@@ -0,0 +1,27 @@
package ru.m.tankz.storage;
import flash.net.SharedObject;
class UserStorage {
private static var TAG(default, never):String = 'UserStorage';
private var so:SharedObject;
public function new() {
so = SharedObject.getLocal('user');
}
public function read():Null<User> {
var user:User = Reflect.getProperty(so.data, 'user');
L.d(TAG, 'read: ${user}');
return user != null ? user : {name: 'User', uuid: null};
}
public function write(user:User):Void {
L.d(TAG, 'write: ${user}');
so.setProperty('user', user);
so.flush();
}
}

View File

@@ -0,0 +1,6 @@
package ru.m;
typedef User = {
var uuid:String;
var name:String;
}

View File

@@ -0,0 +1,7 @@
package ru.m.connect.fake;
class FakeConnection extends BaseConnection {
override public function connect():Void {}
override public function disconnect():Void {}
}

View File

@@ -2,19 +2,7 @@ package ru.m.tankz;
import protohx.Message;
import ru.m.connect.IConnection;
import ru.m.tankz.proto.pack.CreateGameRequest;
import ru.m.tankz.proto.pack.CreateGameResponse;
import ru.m.tankz.proto.pack.ErrorResponse;
import ru.m.tankz.proto.pack.GameActionRequest;
import ru.m.tankz.proto.pack.GameListRequest;
import ru.m.tankz.proto.pack.GameListResponse;
import ru.m.tankz.proto.pack.GameUpdateResponse;
import ru.m.tankz.proto.pack.JoinGameRequest;
import ru.m.tankz.proto.pack.JoinGameResponse;
import ru.m.tankz.proto.pack.LeaveGameRequest;
import ru.m.tankz.proto.pack.LeaveGameResponse;
import ru.m.tankz.proto.pack.StartGameRequest;
import ru.m.tankz.proto.pack.StartGameResponse;
import ru.m.tankz.proto.pack.*;
import Type;
@@ -24,9 +12,10 @@ class PacketBuilder implements IPacketBuilder {
0x00 => [
0x0001 => ErrorResponse
],
/*0x01 => [
],*/
0x01 => [
0x0001 => LoginRequest,
0x0002 => LoginResponse,
],
0x02 => [
0x0001 => GameListRequest,
0x0002 => GameListResponse,

View File

@@ -3,15 +3,11 @@ syntax = "proto3";
package ru.m.tankz.proto.core;
message Player {
int32 id = 1;
message User {
string uuid = 1;
string name = 2;
}
enum GameType {
CLASSIC = 0;
}
enum GameState {
READY = 0;
STARTED = 1;
@@ -20,8 +16,8 @@ enum GameState {
message Game {
int32 id = 1;
GameType type = 2;
Player creator = 3;
repeated Player players = 4;
string type = 2;
User creator = 3;
repeated User players = 4;
GameState state = 5;
}

View File

@@ -11,6 +11,17 @@ message ErrorResponse {
string message = 2;
}
// Login
message LoginRequest {
string uuid = 1;
string name = 2;
}
message LoginResponse {
ru.m.tankz.proto.core.User user = 1;
}
message GameListRequest {}
message GameListResponse {
@@ -18,7 +29,7 @@ message GameListResponse {
}
message CreateGameRequest {
ru.m.tankz.proto.core.GameType type = 1;
string type = 1;
}
message CreateGameResponse {

View File

@@ -11,40 +11,40 @@ import neko.net.ThreadServer;
class Server extends ThreadServer<Session, Bytes> {
private static inline var TAG = "Server";
private static inline var TAG = "Server";
public function new() {
super();
}
public function new() {
super();
}
override public function clientConnected(s:Socket):Session {
var session = new Session(s);
L.d(TAG, "Client connected");
return session;
}
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) {
L.d(TAG, "Client disconnected");
session.onDisconnected();
}
override public function clientDisconnected(session:Session) {
L.d(TAG, "Client disconnected");
session.onDisconnected();
}
override public function readClientMessage(session:Session, buf:Bytes, pos:Int, len:Int) {
return {msg: buf.sub(pos, len), bytes: len};
}
override public function readClientMessage(session:Session, buf:Bytes, pos:Int, len:Int) {
return {msg: buf.sub(pos, len), bytes: len};
}
override public function clientMessage(session:Session, bytes:Bytes) {
session.pushData(bytes);
}
override public function clientMessage(session:Session, bytes:Bytes) {
session.pushData(bytes);
}
public static function main() {
L.push(new TraceLogger());
#if debug
L.push(new SocketLogger());
#end
L.d(TAG, "Running");
L.i(TAG, "Build: " + CompilationOption.get("build"));
Provider.set(IPacketBuilder, new PacketBuilder());
var wserver = new Server();
wserver.run("localhost", 5001);
}
public static function main() {
L.push(new TraceLogger());
#if debug
L.push(new SocketLogger());
#end
L.d(TAG, "Running");
L.i(TAG, "Build: " + CompilationOption.get("build"));
Provider.set(IPacketBuilder, new PacketBuilder());
var wserver = new Server();
wserver.run("localhost", 5001);
}
}

View File

@@ -1,142 +1,126 @@
package ru.m.tankz.server.session;
import ru.m.tankz.proto.GamesUnSubscribeRequest;
import ru.m.tankz.proto.GamesSubscribeRequest;
import ru.m.tankz.proto.LeaveGameRequest;
import ru.m.tankz.server.game.GameManager;
import ru.m.tankz.proto.GameActionRequest;
import ru.m.tankz.proto.StartGameRequest;
import ru.m.tankz.proto.Person;
import ru.m.tankz.proto.JoinGameRequest;
import ru.m.tankz.proto.CreateGameRequest;
import ru.m.connect.neko.NekoWebConnection;
import haxe.io.Bytes;
import ru.m.tankz.proto.PersonSelectResponse;
import ru.m.tankz.proto.PersonSelectRequest;
import ru.m.tankz.proto.Account;
import ru.m.connect.neko.NekoConnection;
import ru.m.tankz.proto.ErrorResponse;
import ru.m.tankz.server.db.DbProvider;
import ru.m.tankz.proto.LoginResponse;
import ru.m.tankz.proto.LoginRequest;
import ru.m.tankz.proto.GamesResponse;
import protohx.Message;
import ru.m.connect.IConnection;
import ru.m.connect.neko.NekoConnection;
import ru.m.connect.neko.NekoWebConnection;
import ru.m.tankz.proto.core.User;
import ru.m.tankz.proto.pack.LoginRequest;
import ru.m.tankz.proto.pack.LoginResponse;
import sys.net.Socket;
import Type;
class Session implements IConnectionHandler implements IPacketHandler {
public static var sessions:Map<Int, Session> = new Map<Int, Session>();
public static var sessions:Map<Int, Session> = new Map<Int, Session>();
public var account(default, null):Account;
public var person(default, null):Person;
public var gameId(default, null):Int = -1;
public var user(default, null):User;
public var gameId(default, null):Int = -1;
private var connection(default, null):IConnection;
private var socket:Socket;
private var connection(default, null):IConnection;
private var socket:Socket;
public function new(socket:Socket) {
this.socket = socket;
}
public function send(packet:Message):Void {
connection.send(packet);
}
public function pushData(bytes:Bytes):Void {
if (connection != null) {
connection.pushData(bytes);
} else {
var str:String = bytes.getString(0, bytes.length);
if (StringTools.startsWith(str, "GET")) {
connection = new NekoWebConnection(socket);
} else {
connection = new NekoConnection(socket);
}
connection.handler.addListener(this);
connection.packetHandler.addListener(this);
connection.pushData(bytes);
public function new(socket:Socket) {
this.socket = socket;
}
}
/**
public function send(packet:Message):Void {
connection.send(packet);
}
public function pushData(bytes:Bytes):Void {
if (connection != null) {
connection.pushData(bytes);
} else {
var str:String = bytes.getString(0, bytes.length);
if (StringTools.startsWith(str, "GET")) {
connection = new NekoWebConnection(socket);
} else {
connection = new NekoConnection(socket);
}
connection.handler.addListener(this);
connection.packetHandler.addListener(this);
connection.pushData(bytes);
}
}
/**
* Connection handlers
**/
public function onConnected():Void {
public function onConnected():Void {
}
public function onDisconnected():Void {
if (person != null) {
var game = GameManager.byPersonId.get(person.id);
if (game != null) game.leave(person);
}
}
public function onError(error:Dynamic):Void {
connection.send(
new ErrorResponse()
.setCode(0)
.setMessage(Std.string(error))
);
}
public function onDisconnected():Void {
/*if (person != null) {
var game = GameManager.byPersonId.get(person.id);
if (game != null) game.leave(person);
}*/
}
/**
public function onError(error:Dynamic):Void {
/*connection.send(
new ErrorResponse()
.setCode(0)
.setMessage(Std.string(error))
);*/
}
/**
* Packets handlers
**/
public function onLoginRequest(packet:LoginRequest):Void {
var db = new DbProvider();
account = db.getAccount(packet.login, packet.password);
if (account != null) {
connection.send(new LoginResponse().setAccount(account));
} else {
connection.send(new ErrorResponse().setCode(404).setMessage("Account not found"));
public function onLoginRequest(packet:LoginRequest):Void {
connection.send(new LoginResponse().setUser(
new User()
.setUuid(packet.uuid != null ? packet.uuid : 'xxx')
.setName(packet.name)
));
}
}
public function onPersonSelectRequest(packet:PersonSelectRequest):Void {
var db = new DbProvider();
var person = db.getPerson(packet.personId);
if (person != null) {
this.person = person;
sessions.set(person.id, this);
connection.send(new PersonSelectResponse().setPerson(person));
} else {
connection.send(new ErrorResponse().setCode(404).setMessage("Person not found"));
/*public function onPersonSelectRequest(packet:PersonSelectRequest):Void {
var db = new DbProvider();
var person = db.getPerson(packet.personId);
if (person != null) {
this.person = person;
sessions.set(person.id, this);
connection.send(new PersonSelectResponse().setPerson(person));
} else {
connection.send(new ErrorResponse().setCode(404).setMessage("Person not found"));
}
}
}
public function onGamesSubscribeRequest(packet:GamesSubscribeRequest):Void {
GameManager.subscribers.set(person.id, true);
connection.send(new GamesResponse().setGames(GameManager.getReadyGames()));
}
public function onGamesSubscribeRequest(packet:GamesSubscribeRequest):Void {
GameManager.subscribers.set(person.id, true);
connection.send(new GamesResponse().setGames(GameManager.getReadyGames()));
}
public function onGamesUnSubscribeRequest(packet:GamesUnSubscribeRequest):Void {
GameManager.subscribers.remove(person.id);
}
public function onGamesUnSubscribeRequest(packet:GamesUnSubscribeRequest):Void {
GameManager.subscribers.remove(person.id);
}
public function onCreateGameRequest(packet:CreateGameRequest):Void {
new GameManager(person);
}
public function onCreateGameRequest(packet:CreateGameRequest):Void {
new GameManager(person);
}
public function onJoinGameRequest(packet:JoinGameRequest):Void {
GameManager.byGameId.get(packet.gameId).join(person);
}
public function onJoinGameRequest(packet:JoinGameRequest):Void {
GameManager.byGameId.get(packet.gameId).join(person);
}
public function onLeaveGameRequest(packet:LeaveGameRequest):Void {
GameManager.byPersonId.get(person.id).leave(person);
}
public function onLeaveGameRequest(packet:LeaveGameRequest):Void {
GameManager.byPersonId.get(person.id).leave(person);
}
public function onStartGameRequest(packet:StartGameRequest):Void {
GameManager.byPersonId.get(person.id).start();
}
public function onStartGameRequest(packet:StartGameRequest):Void {
GameManager.byPersonId.get(person.id).start();
}
public function onGameActionRequest(packet:GameActionRequest):Void {
GameManager.byPersonId.get(person.id).action(person, packet);
}
public function onGameActionRequest(packet:GameActionRequest):Void {
GameManager.byPersonId.get(person.id).action(person, packet);
}*/
public function onPacket(packet:Message):Void {
trace("Unknown packet: " + Type.getClassName(Type.getClass(packet)).split(".").pop());
}
public function onPacket(packet:Message):Void {
trace("Unknown packet: " + Type.getClassName(Type.getClass(packet)).split(".").pop());
}
}