[client] add GameListFrame

This commit is contained in:
2019-05-22 17:25:51 +03:00
parent a5722dfa9d
commit 4b426183e8
21 changed files with 135 additions and 412 deletions

View File

@@ -124,7 +124,7 @@ const server = new Project(
config.branch({
name: 'server',
sources: ['src/server/haxe'],
main: 'ru.m.tankz.server.TestServer',
main: 'ru.m.tankz.server.Server',
})
).bind(module, gulp);
@@ -144,5 +144,5 @@ module.exports.default = gulp.series(
module.exports['editor:flash:html'],
module.exports['editor:html5:build'],
//module.exports['server:neko:build'],
module.exports['server:neko:build'],
);

View File

@@ -1,24 +1,21 @@
package ru.m.tankz;
import openfl.display.FPS;
import ru.m.tankz.view.ClientView;
import flash.Lib;
import haxework.animate.Animate;
import haxework.view.Root;
import haxework.log.TraceLogger;
#if flash import haxework.log.JSLogger; #end
#if debug import haxework.log.SocketLogger; #end
import haxework.view.Root;
import ru.m.tankz.view.ClientView;
class Client {
private static inline var TAG = 'Tankz';
private static inline var TAG = "Tankz";
public static function main() {
L.push(new TraceLogger());
#if flash
L.push(new JSLogger());
L.push(new haxework.log.JSLogger());
#end
#if debug
//L.push(new SocketLogger());
//L.push(new haxework.log.SocketLogger());
#end
Const.init();
Init.init();
@@ -35,7 +32,7 @@ class Client {
view.launch();
#if debug
var fps = new FPS(0, 0, 0x00ff00);
var fps = new openfl.display.FPS(0, 0, 0x00ff00);
Lib.current.addChild(fps);
#end
}

View File

@@ -3,7 +3,6 @@ package ru.m.tankz.control;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.control.Control;
class ClientNetworkControl extends HumanControl {
@:provide private var network:NetworkManager;

View File

@@ -3,11 +3,10 @@ package ru.m.tankz.network;
import haxework.signal.Signal;
import ru.m.connect.IConnection;
import ru.m.tankz.control.Control;
import ru.m.tankz.proto.core.GameInfoProto;
import ru.m.tankz.proto.core.GameProto;
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.ListGameRequest;
@@ -33,8 +32,8 @@ class NetworkManager {
public var state(default, null):ConnectionState;
public var stateSignal:Signal<ConnectionState>;
public var listGameSignal:Signal<Array<GameInfoProto>>;
public var gameSignal:Signal<GameInfoProto>;
public var listGameSignal:Signal<Array<GameProto>>;
public var gameSignal:Signal<GameProto>;
public var gameUpdateSignal:Signal<Array<GameChangeProto>>;
@:provide private var connection:ClientConnection;
@@ -98,23 +97,7 @@ class NetworkManager {
}
public function action(action:TankAction):Void {
var update:GameUpdateRequest = switch action {
case TankAction.MOVE(direction):
new GameUpdateRequest()
.setType(GameActionTypeProto.MOVE)
.setDirectionX(direction.x)
.setDirectionY(direction.y);
case TankAction.STOP:
new GameUpdateRequest()
.setType(GameActionTypeProto.STOP);
case TankAction.SHOT:
new GameUpdateRequest()
.setType(GameActionTypeProto.SHOT);
case _: null;
}
if (update != null) {
connection.send(new Request().setUpdateGame(update));
}
// ToDo: network
}
private function onConnectionEvent(event:ConnectionEvent):Void {
@@ -152,10 +135,6 @@ class NetworkManager {
gameSignal.emit(null);
} else if (packet.hasStartGame()) {
gameSignal.emit(packet.startGame.game);
} else if (packet.hasUpdateGame()) {
gameUpdateSignal.emit(packet.updateGame.changes);
} else if (packet.hasGame()) {
//game.load(packet.game.game);
}
}
}

View File

@@ -15,3 +15,5 @@ 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

View File

@@ -1,108 +0,0 @@
package ru.m.tankz.view;
import haxework.view.ButtonView;
import haxework.view.frame.IFrameSwitcher;
import haxework.view.IGroupView;
import haxework.view.InputView;
import haxework.view.LabelView;
import haxework.view.list.ListView;
import haxework.view.VGroupView;
import haxework.provider.Provider;
import ru.m.tankz.game.GameState;
import ru.m.tankz.network.NetworkManager;
import ru.m.tankz.preset.ClassicGame;
import ru.m.tankz.proto.core.GameInfoProto;
import ru.m.tankz.proto.core.GameStateProto;
import ru.m.tankz.proto.core.UserProto;
@:template class NetworkFrame extends VGroupView {
public static var ID(default, never):String = "network";
@:view var frameSwitcher(default, null):IFrameSwitcher;
@:view var loginFrame(default, null):IGroupView;
@:view var stateLabel(default, null):LabelView;
@:view var nameInput(default, null):InputView;
@:view var loginButton(default, null):ButtonView;
@:view var gameListFrame(default, null):IGroupView;
@:view var createGameButton(default, null):ButtonView;
@:view var gameList(default, null):ListView<GameInfoProto>;
@:view var gameFrame(default, null):IGroupView;
@:view var leaveGameButton(default, null):ButtonView;
@:view var startGameButton(default, null):ButtonView;
@:view var userList(default, null):ListView<UserProto>;
@:provide var network:NetworkManager;
@:provide var mainFrameSwitcher:IFrameSwitcher;
public function init():Void {
loginButton.onPress = this;
createGameButton.onPress = this;
leaveGameButton.onPress = this;
startGameButton.onPress = this;
gameList.dispatcher.addListener({
onListItemClick: function(item:IListItemView<GameInfoProto>):Void {
network.joinGame(item.data.id);
}
});
}
public function onShow():Void {
nameInput.text = network.user.name;
onStateChange(network.state);
network.stateSignal.connect(onStateChange);
}
private function onStateChange(state:String):Void {
loginButton.disabled = !(state == "offline" || state == "error");
stateLabel.text = state;
if (state == 'online') {
gameList.data = [];
frameSwitcher.change(gameListFrame.id);
network.listGameSignal.connect(onListGame);
network.gameSignal.connect(onGame);
network.listGame();
} else {
frameSwitcher.change(loginFrame.id);
}
}
private function onListGame(games:Array<GameInfoProto>):Void {
gameList.data = games;
}
private function onGame(game:GameInfoProto):Void {
if (game != null) {
userList.data = game.players;
frameSwitcher.change(gameFrame.id);
if (game.state == GameStateProto.STARTED) {
Provider.set(GameState, new GameState(ClassicGame.TYPE, ClassicGame.PLAYER1));
mainFrameSwitcher.change(GameFrame.ID);
}
} else {
frameSwitcher.change(gameListFrame.id);
}
}
public function onHide():Void {
network.listGameSignal.disconnect(onListGame);
network.gameSignal.disconnect(onGame);
network.stateSignal.disconnect(onStateChange);
}
public function onPress(view:ButtonView):Void {
switch (view.id) {
case 'loginButton':
network.login(nameInput.text);
case 'createGameButton':
network.createGame('classic');
case 'leaveGameButton':
network.leaveGame();
case 'startGameButton':
network.startGame();
}
}
}

View File

@@ -1,90 +0,0 @@
---
pWidth: 100
pHeight: 100
views:
- id: frameSwitcher
$type: haxework.view.frame.FrameSwitcher
pWidth: 100
pHeight: 100
views:
# login
- id: loginFrame
$type: haxework.view.VGroupView
pWidth: 100
pHeight: 100
views:
- id: stateLabel
$type: haxework.view.LabelView
$style: label
text: offline
width: 200
height: 50
- id: nameInput
$type: haxework.view.InputView
$style: label
width: 200
height: 50
text: User
skin:
$type: haxework.view.skin.ColorSkin
color: '#444444'
- id: loginButton
$type: haxework.view.ButtonView
$style: button
text: Login
# game list
- id: gameListFrame
$type: haxework.view.VGroupView
pWidth: 100
pHeight: 100
views:
- id: createGameButton
$type: haxework.view.ButtonView
$style: button
text: Create
- id: gameList
$type: haxework.view.list.VListView<ru.m.tankz.proto.core.GameInfoProto>
factory: "@class:ru.m.tankz.view.network.GameItemView"
pWidth: 100
pHeight: 100
paddings: 10
scroll:
$type: haxework.view.list.VScrollView
width: 10
pHeight: 100
skin:
$type: haxework.view.list.VScrollSkin
skin:
$type: haxework.view.skin.ColorSkin
color: "#000000"
alpha: 0
# game
- id: gameFrame
$type: haxework.view.VGroupView
pWidth: 100
pHeight: 100
views:
- id: startGameButton
$type: haxework.view.ButtonView
$style: button
text: Start
- id: leaveGameButton
$type: haxework.view.ButtonView
$style: button
text: Leave
- id: userList
$type: haxework.view.list.VListView<ru.m.tankz.proto.core.UserProto>
factory: "@class:ru.m.tankz.view.network.UserItemView"
pWidth: 100
pHeight: 100
paddings: 10
scroll:
$type: haxework.view.list.VScrollView
width: 10
pHeight: 100
skin:
$type: haxework.view.list.VScrollSkin
skin:
$type: haxework.view.skin.ColorSkin
color: "#000000"
alpha: 0

View File

@@ -28,7 +28,7 @@ views:
- id: network
$type: haxework.view.ButtonView
skinId: button
# +onPress: $code:switcher.change('record')
+onPress: $code:switcher.change('game_list')
text: Network
disabled: true
- $type: haxework.view.HGroupView

21
src/client/haxe/ru/m/tankz/view/network/GameItemView.hx Executable file → Normal file
View File

@@ -1,21 +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.core.GameInfoProto;
import haxework.view.HGroupView;
import haxework.view.list.ListView.IListItemView;
import ru.m.tankz.proto.core.GameProto;
@:template class GameItemView extends HGroupView implements IListItemView<GameInfoProto> {
@:template class GameItemView extends HGroupView implements IListItemView<GameProto> {
public var item_index(default, default):Int;
public var data(default, set):GameInfoProto;
public var data(default, set):GameProto;
@:view var label(default, null):LabelView;
@:view var label:LabelView;
private function set_data(value:GameInfoProto):GameInfoProto {
private function set_data(value:GameProto):GameProto {
data = value;
label.text = '${data.type}';
label.text = '${value.id}. ${value.type} - ${value.level} (${value.creator.name})';
return data;
}
public static function factory():GameItemView {
return new GameItemView();
}
}

View File

@@ -1,15 +1,8 @@
---
width: 440
height: 44
margins: 5
geometry.size.width: 100%
geometry.size.height: 48
views:
- id: label
$type: haxework.view.LabelView
$style: label
pWidth: 100
pHeight: 100
text: ""
skin:
$type: haxework.view.skin.ColorSkin
color: "#000000"
alpha: 0.2
- id: label
$type: haxework.view.LabelView
geometry.size.stretch: true
skinId: text.box

View File

@@ -0,0 +1,29 @@
package ru.m.tankz.view.network;
import haxework.view.list.VListView;
import ru.m.tankz.proto.core.GameProto;
import ru.m.tankz.network.NetworkManager;
import haxework.view.frame.FrameSwitcher;
import haxework.view.VGroupView;
@: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.listGame();
}
public function onHide():Void {
network.listGameSignal.disconnect(onGameList);
}
private function onGameList(data:Array<GameProto>):Void {
games.data = data;
}
}

View File

@@ -0,0 +1,22 @@
---
views:
- $type: haxework.view.VGroupView
skinId: container
geometry.padding: 20
views:
- id: header
$type: haxework.view.LabelView
skinId: text.header
text: Games List
- id: games
$type: haxework.view.list.VListView
geometry.size.stretch: true
geometry.margin.top: 20
factory: $code:ru.m.tankz.view.network.GameItemView.factory
geometry.margin: 10
- $type: haxework.view.HGroupView
skinId: panel
views:
- $type: haxework.view.ButtonView
skinId: button.close
+onPress: $code:switcher.change('start')

View File

@@ -1,21 +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.UserProto;
@:template class UserItemView extends HGroupView implements IListItemView<UserProto> {
public var item_index(default, default):Int;
public var data(default, set):UserProto;
@:view var label(default, null):LabelView;
private function set_data(value:UserProto):UserProto {
data = value;
label.text = '${data.uuid} -- ${data.name}';
return data;
}
}

View File

@@ -1,15 +0,0 @@
---
width: 440
height: 44
margins: 5
views:
- id: label
$type: haxework.view.LabelView
$style: label
pWidth: 100
pHeight: 100
text: ""
skin:
$type: haxework.view.skin.ColorSkin
color: "#000000"
alpha: 0.2

View File

@@ -3,7 +3,6 @@ package ru.m.tankz.control;
import ru.m.tankz.control.Control;
import ru.m.tankz.Type;
interface IControlFactory {
public function build(id:PlayerId, controller:Controller):Control;
}

View File

@@ -3,7 +3,6 @@ package ru.m.tankz.control;
import ru.m.tankz.control.Control;
import ru.m.tankz.Type;
class NoneControlFactory implements IControlFactory {
public function new() {}

View File

@@ -14,24 +14,11 @@ enum GameStateProto {
ENDED = 2;
}
message BrickProto {
string type = 1;
}
message EntityProto {
string type = 1;
}
message GameInfoProto {
message GameProto {
int32 id = 1;
string type = 2;
UserProto creator = 3;
repeated UserProto players = 4;
GameStateProto state = 5;
int32 level = 3;
UserProto creator = 4;
repeated UserProto players = 5;
GameStateProto state = 6;
}
message GameProto {
GameInfoProto info = 1;
repeated BrickProto map = 2;
repeated EntityProto entities = 3;
}

View File

@@ -30,16 +30,17 @@ message LogoutResponse {}
message ListGameRequest {}
message ListGameResponse {
repeated ru.m.tankz.proto.core.GameInfoProto games = 1;
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.GameInfoProto game = 1;
ru.m.tankz.proto.core.GameProto game = 1;
}
// Join Game
@@ -48,41 +49,23 @@ message JoinGameRequest {
}
message JoinGameResponse {
ru.m.tankz.proto.core.GameInfoProto game = 1;
ru.m.tankz.proto.core.GameProto game = 1;
}
// Leave Game
message LeaveGameRequest {}
message LeaveGameResponse {
ru.m.tankz.proto.core.GameInfoProto game = 1;
ru.m.tankz.proto.core.GameProto game = 1;
}
// Start Game
message StartGameRequest {}
message StartGameResponse {
ru.m.tankz.proto.core.GameInfoProto game = 1;
}
// Game
message GameRequest {}
message GameResponse {
ru.m.tankz.proto.core.GameProto game = 1;
}
// Game Update
message GameUpdateRequest {
ru.m.tankz.proto.game.GameActionTypeProto type = 1;
int32 directionX = 2;
int32 directionY = 3;
}
message GameUpdateResponse {
repeated ru.m.tankz.proto.game.GameChangeProto changes = 1;
}
// Request
message Request {
oneof content {
@@ -93,8 +76,6 @@ message Request {
JoinGameRequest joinGame = 5;
LeaveGameRequest leaveGame = 6;
StartGameRequest startGame = 7;
GameRequest game = 8;
GameUpdateRequest updateGame = 9;
}
}
@@ -108,7 +89,5 @@ message Response {
JoinGameResponse joinGame = 5;
LeaveGameResponse leaveGame = 6;
StartGameResponse startGame = 7;
GameResponse game = 8;
GameUpdateResponse updateGame = 9;
}
}

View File

@@ -1,63 +1,50 @@
package ru.m.tankz.server;
import ru.m.tankz.control.NoneControlFactory;
import ru.m.tankz.control.IControlFactory;
import haxe.io.Bytes;
import haxework.log.TraceLogger;
import haxework.provider.Provider;
import neko.net.ThreadServer;
import ru.m.connect.IConnection.ConnectionEvent;
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.GameSession;
import sys.net.Socket;
#if debug import haxework.log.SocketLogger; #end
class Server extends ThreadServer<_Session, Bytes> {
class Server extends ThreadServer<GameSession, Bytes> {
private static inline var TAG = 'Server';
public function new() {
super();
}
override public function clientConnected(s:Socket):_Session {
var session = new _Session(s);
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.connection.handler.emit(ConnectionEvent.DISCONNECTED);
session.disconnect();
}
override public function readClientMessage(session:_Session, buf:Bytes, pos:Int, len:Int) {
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:_Session, bytes:Bytes) {
try {
session.pushData(bytes);
} catch (error:Dynamic) {
L.e(TAG, 'error', error);
}
override public function clientMessage(session:GameSession, bytes:Bytes) {
session.pushData(bytes);
}
public static function main() {
L.push(new TraceLogger());
#if debug
L.push(new SocketLogger());
L.push(new haxework.log.SocketLogger());
#end
L.d(TAG, 'Running');
L.i(TAG, 'Build: ${CompilationOption.get("build")}');
Provider.setFactory(IConfigBundle, ServerConfigBundle);
Provider.setFactory(ILevelBundle, ServerLevelBundle);
Provider.setFactory(IControlFactory, NoneControlFactory);
//Provider.setFactory(IControlFactory, NoneControlFactory);
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 Server();

View File

@@ -1,46 +0,0 @@
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

@@ -1,12 +1,17 @@
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.GameProto;
import ru.m.tankz.proto.core.UserProto;
import ru.m.tankz.proto.pack.CreateGameRequest;
import ru.m.tankz.proto.pack.CreateGameResponse;
import ru.m.tankz.proto.pack.ListGameRequest;
import ru.m.tankz.proto.pack.ListGameResponse;
import ru.m.tankz.proto.pack.LoginRequest;
import ru.m.tankz.proto.pack.LoginResponse;
import ru.m.tankz.proto.pack.LogoutRequest;
import ru.m.tankz.proto.pack.LogoutResponse;
import ru.m.tankz.proto.pack.Request;
import ru.m.tankz.proto.pack.Response;
import sys.net.Socket;
@@ -31,12 +36,35 @@ class GameSession extends ProtoSession<Response, Request> {
return new LogoutResponse();
}
private function onCreateGame(request:CreateGameRequest):CreateGameResponse {
var game = new GameProto()
.setId(1)
.setCreator(user)
.setType(request.type)
.setLevel(request.level);
return new CreateGameResponse().setGame(game);
}
private function onListGame(request:ListGameRequest):ListGameResponse {
// ToDo: test games
var games = [for (i in 0...5) new GameProto()
.setId(i)
.setCreator(user)
.setType("classic")
.setLevel(i)];
return new ListGameResponse().setGames(games);
}
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)));
} else if (request.hasCreateGame()) {
send(new Response().setCreateGame(onCreateGame(request.createGame)));
} else if (request.hasListGame()) {
send(new Response().setListGame(onListGame(request.listGame)));
}
}
}