update
This commit is contained in:
@@ -26,3 +26,6 @@ CREATE TABLE IF NOT EXISTS armageddon.person (
|
||||
INSERT INTO armageddon.account (id,login,password) VALUES(1,'shmyga', 'd48cc4eb42c058869ae90daef9606e43');
|
||||
INSERT INTO armageddon.person (id,account_id,name) VALUES(1,1,'-=Shmyga=-');
|
||||
|
||||
INSERT INTO armageddon.account (id,login,password) VALUES(2,'a', md5('a'));
|
||||
INSERT INTO armageddon.person (id,account_id,name) VALUES(2,2,'a');
|
||||
|
||||
|
||||
@@ -49,7 +49,11 @@ class PlayerTank extends Tank {
|
||||
|
||||
private function updateMove():Void {
|
||||
if (moveQueue.length == 0) {
|
||||
stop();
|
||||
//stop();
|
||||
Provider.get(IConnection).send(
|
||||
new GameActionRequest()
|
||||
.setType(GameActionType.STOP)
|
||||
);
|
||||
} else {
|
||||
switch (keyBinding.get(moveQueue[0])) {
|
||||
case TankAction.MOVE(direction):
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package ru.m.tankz.view.frames;
|
||||
|
||||
import ru.m.tankz.core.MobileEntity;
|
||||
import ru.m.tankz.core.Direction;
|
||||
import ru.m.tankz.proto.GameObjectType;
|
||||
import ru.m.tankz.proto.GameChangeType;
|
||||
import ru.m.tankz.game.ClientTankz;
|
||||
import protohx.Message;
|
||||
import ru.m.tankz.proto.GameUpdateResponse;
|
||||
@@ -32,6 +36,7 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
|
||||
game.init(persons, DEFAULT.CONFIG);
|
||||
content.addEventListener(Event.ENTER_FRAME, updateGame);
|
||||
Provider.get(IConnection).packetHandler.addListener(this);
|
||||
render.draw(game);
|
||||
}
|
||||
|
||||
public function onHide():Void {
|
||||
@@ -41,12 +46,47 @@ class GameFrame extends VGroupView implements ViewBuilder implements IPacketHand
|
||||
}
|
||||
|
||||
private function updateGame(_):Void {
|
||||
game.update();
|
||||
render.draw(game);
|
||||
//game.update();
|
||||
//render.draw(game);
|
||||
}
|
||||
|
||||
public function onGameUpdateResponse(packet:GameUpdateResponse):Void {
|
||||
|
||||
for (change in packet.changes) {
|
||||
switch (change.type) {
|
||||
case GameChangeType.DIRECTION:
|
||||
switch (change.objectType) {
|
||||
case GameObjectType.TANK:
|
||||
for (tank in game.tanks) {
|
||||
if (tank.id == change.objectId) {
|
||||
tank.direction = new Direction(change.directionX, change.directionY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case GameChangeType.MOVED:
|
||||
switch (change.objectType) {
|
||||
case GameObjectType.TANK:
|
||||
for (tank in game.tanks) {
|
||||
if (tank.id == change.objectId) {
|
||||
tank.x = change.x;
|
||||
tank.y = change.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case GameChangeType.APPEND:
|
||||
switch (change.objectType) {
|
||||
case GameObjectType.BULLET:
|
||||
for (tank in game.tanks) {
|
||||
if (tank.id == change.parentObjectId) {
|
||||
tank.bullets.push(new MobileEntity(0, change.x, change.y, 0, new Direction(change.directionX, change.directionY)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
render.draw(game);
|
||||
}
|
||||
|
||||
public function onPacket(packet:Message):Void {}
|
||||
|
||||
@@ -42,11 +42,11 @@ class BaseConnection implements IConnection {
|
||||
}
|
||||
}
|
||||
public function send(packet:Message):Void {
|
||||
L.d("Send", Type.getClassName(Type.getClass(packet)).split(".").pop());
|
||||
//L.d("Send", Type.getClassName(Type.getClass(packet)).split(".").pop());
|
||||
}
|
||||
|
||||
public function receive(packet:Message):Void {
|
||||
L.d("Receive", Type.getClassName(Type.getClass(packet)).split(".").pop());
|
||||
//L.d("Receive", Type.getClassName(Type.getClass(packet)).split(".").pop());
|
||||
var name = "on" + Type.getClassName(Type.getClass(packet)).split(".").pop();
|
||||
packetHandler.dispatch(function(h) {
|
||||
var method = Reflect.field(h, name);
|
||||
|
||||
@@ -17,7 +17,7 @@ class NekoWebConnection extends NekoConnection {
|
||||
}
|
||||
|
||||
override public function send(packet:Message):Void {
|
||||
L.d("Send", Type.getClassName(Type.getClass(packet)).split(".").pop());
|
||||
//L.d("Send", Type.getClassName(Type.getClass(packet)).split(".").pop());
|
||||
try {
|
||||
var data = WebSocketTools.packet2string(packet, builder);
|
||||
writeData(data, socket);
|
||||
|
||||
@@ -2,8 +2,8 @@ package ru.m.tankz.core;
|
||||
|
||||
class Entity implements IEntity {
|
||||
|
||||
public var x(default, default):Float;
|
||||
public var y(default, default):Float;
|
||||
public var x(default, default):Float = 0;
|
||||
public var y(default, default):Float = 0;
|
||||
|
||||
public var width(default, default):Float;
|
||||
public var height(default, default):Float;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ru.m.tankz.core;
|
||||
|
||||
interface IMobileEntity extends IEntity {
|
||||
public var id(default, null):Int;
|
||||
|
||||
public var mx(default, default):Float;
|
||||
public var my(default, default):Float;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package ru.m.tankz.core;
|
||||
|
||||
interface ITank extends IMobileEntity {
|
||||
public var id(default, null):Int;
|
||||
public var bullets:Array<IMobileEntity>;
|
||||
|
||||
public function shot():Void;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package ru.m.tankz.core;
|
||||
|
||||
class MobileEntity extends Entity implements IMobileEntity {
|
||||
public var id(default, null):Int;
|
||||
|
||||
public var mx(default, default):Float;
|
||||
public var my(default, default):Float;
|
||||
public var mx(default, default):Float = 0;
|
||||
public var my(default, default):Float = 0;
|
||||
|
||||
public var speed(default, null):Float;
|
||||
public var speed(default, null):Float = 0;
|
||||
public var direction(default, default):Direction;
|
||||
|
||||
public function new(x:Float, y:Float, speed:Float, direction:Direction = null) {
|
||||
public function new(id:Int, x:Float, y:Float, speed:Float, direction:Direction = null) {
|
||||
super(x, y);
|
||||
this.id = id;
|
||||
this.speed = speed;
|
||||
this.direction = direction == null ? Direction.BOTTOM : direction;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@ enum TankAction {
|
||||
|
||||
class Tank extends MobileEntity implements ITank {
|
||||
|
||||
public var id(default, null):Int;
|
||||
public var bullets:Array<IMobileEntity>;
|
||||
|
||||
public function new(id:Int, x:Float, y:Float) {
|
||||
super(x, y, 4);
|
||||
super(id, x, y, 4);
|
||||
this.id = id;
|
||||
bullets = new Array<IMobileEntity>();
|
||||
width = 34;
|
||||
@@ -20,7 +19,7 @@ class Tank extends MobileEntity implements ITank {
|
||||
|
||||
public function shot():Void {
|
||||
if (bullets.length >= 5) return;
|
||||
var bullet = new MobileEntity(x + width / 2 - 5, y + height / 2 - 5, 6, direction);
|
||||
var bullet = new MobileEntity(0, x + width / 2 - 5, y + height / 2 - 5, 6, direction);
|
||||
bullet.width = 10;
|
||||
bullet.height = 10;
|
||||
bullet.move(direction);
|
||||
|
||||
@@ -93,6 +93,7 @@ message ExitGameResponse {
|
||||
enum GameActionType {
|
||||
MOVE = 1;
|
||||
SHOT = 2;
|
||||
STOP = 3;
|
||||
}
|
||||
|
||||
message GameActionRequest {
|
||||
@@ -103,6 +104,7 @@ message GameActionRequest {
|
||||
|
||||
enum GameObjectType {
|
||||
TANK = 1;
|
||||
BULLET = 2;
|
||||
}
|
||||
|
||||
enum GameChangeType {
|
||||
@@ -110,14 +112,18 @@ enum GameChangeType {
|
||||
DESTROED = 2;
|
||||
MODIFIED = 3;
|
||||
APPEND = 4;
|
||||
DIRECTION = 5;
|
||||
}
|
||||
|
||||
message GameChange {
|
||||
required GameChangeType type = 1;
|
||||
required GameObjectType objectType = 2;
|
||||
required int32 objectId = 3;
|
||||
optional int32 newX = 4;
|
||||
optional int32 newY = 5;
|
||||
optional int32 parentObjectId = 4;
|
||||
optional float x = 5;
|
||||
optional float y = 6;
|
||||
optional int32 directionX = 7;
|
||||
optional int32 directionY = 8;
|
||||
}
|
||||
|
||||
message GameUpdateResponse {
|
||||
|
||||
12
src/server/haxe/ru/m/tankz/server/game/Game.hx
Normal file
12
src/server/haxe/ru/m/tankz/server/game/Game.hx
Normal file
@@ -0,0 +1,12 @@
|
||||
package ru.m.tankz.server.game;
|
||||
|
||||
import ru.m.tankz.game.ITankz;
|
||||
|
||||
class Game {
|
||||
|
||||
private var tankz:ITankz;
|
||||
|
||||
public function new() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
package ru.m.tankz.server.session;
|
||||
|
||||
import ru.m.tankz.proto.GameObjectType;
|
||||
import ru.m.tankz.proto.GameChangeType;
|
||||
import ru.m.tankz.proto.GameChange;
|
||||
import ru.m.tankz.config.TankzConfig.DEFAULT;
|
||||
import ru.m.tankz.proto.GameUpdateResponse;
|
||||
import haxe.Timer;
|
||||
import ru.m.tankz.core.Direction;
|
||||
import ru.m.tankz.game.Tankz;
|
||||
import ru.m.tankz.game.ITankz;
|
||||
import ru.m.tankz.proto.GameActionType;
|
||||
@@ -31,6 +38,39 @@ import protohx.Message;
|
||||
import ru.m.core.connect.IConnection;
|
||||
import sys.net.Socket;
|
||||
|
||||
class NekoTimer {
|
||||
|
||||
private var sleep:Float;
|
||||
private var stopped:Bool;
|
||||
|
||||
public function new(time_ms:Int) {
|
||||
this.sleep = time_ms / 1000.0;
|
||||
this.stopped = false;
|
||||
Thread.create(function() {
|
||||
while (!stopped) {
|
||||
Sys.sleep(sleep);
|
||||
try {
|
||||
run();
|
||||
} catch (error:Dynamic) {
|
||||
trace(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dynamic function run() {}
|
||||
|
||||
public function stop() {
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef ObjectState = {
|
||||
var x:Float;
|
||||
var y:Float;
|
||||
var d:Direction;
|
||||
}
|
||||
|
||||
class GameCenter {
|
||||
|
||||
@@ -39,21 +79,27 @@ class GameCenter {
|
||||
private var created:Map<Int, Int>;
|
||||
private var persons:Map<Int, Int>;
|
||||
|
||||
private var running:Map<Int, ITankz>;
|
||||
public var running:Map<Int, ITankz>;
|
||||
private var timers:Map<Int, NekoTimer>;
|
||||
|
||||
public function new() {
|
||||
games = new Map<Int, Game>();
|
||||
created = new Map<Int, Int>();
|
||||
persons = new Map<Int, Int>();
|
||||
running = new Map<Int, ITankz>();
|
||||
timers = new Map<Int, NekoTimer>();
|
||||
}
|
||||
|
||||
public function getReadyGames():Array<Game> {
|
||||
return Lambda.array(games).filter(function(g) return g.state == GameState.READY);
|
||||
}
|
||||
|
||||
public function getCreatedGame(person_id:Int):Game {
|
||||
return games.get(created.get(person_id));
|
||||
public function getCreatedGame(peronsId:Int):Game {
|
||||
return games.get(created.get(peronsId));
|
||||
}
|
||||
|
||||
public function getPersonGameId(personId:Int):Int {
|
||||
return persons.get(personId);
|
||||
}
|
||||
|
||||
public function createGame(person:Person):Game {
|
||||
@@ -82,6 +128,10 @@ class GameCenter {
|
||||
game.persons.remove(person);
|
||||
if (game.persons.length == 0) {
|
||||
games.remove(game.id);
|
||||
if (timers.exists(game.id)) {
|
||||
timers.get(game.id).stop();
|
||||
timers.remove(game.id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -91,9 +141,57 @@ class GameCenter {
|
||||
|
||||
public function start(gameId:Int):Void {
|
||||
if (games.exists(gameId)) {
|
||||
games.get(gameId).setState(GameState.STARTED);
|
||||
var game:Game = games.get(gameId);
|
||||
game.setState(GameState.STARTED);
|
||||
var tankz = new Tankz();
|
||||
tankz.init(game.persons, DEFAULT.CONFIG);
|
||||
running.set(gameId, tankz);
|
||||
var timer = new NekoTimer(30);
|
||||
timer.run = buildUpdater(gameId, tankz);
|
||||
timers.set(gameId, timer);
|
||||
broadcast(gameId, new StartGameResponse().setGame(game));
|
||||
}
|
||||
}
|
||||
|
||||
private function buildUpdater(gameId:Int, tankz:ITankz):Void->Void {
|
||||
return function() {
|
||||
var states = new Map<Int, ObjectState>();
|
||||
for (tank in tankz.tanks) {
|
||||
states.set(tank.id, {
|
||||
x: tank.x,
|
||||
y: tank.y,
|
||||
d: tank.direction
|
||||
});
|
||||
}
|
||||
tankz.update();
|
||||
var changes = new Array<GameChange>();
|
||||
for (tank in tankz.tanks) {
|
||||
if (states.exists(tank.id)) {
|
||||
var state = states.get(tank.id);
|
||||
if (state.d != tank.direction) {
|
||||
trace("DDD");
|
||||
changes.push(new GameChange()
|
||||
.setType(GameChangeType.DIRECTION)
|
||||
.setObjectType(GameObjectType.TANK)
|
||||
.setObjectId(tank.id)
|
||||
.setDirectionX(tank.direction.x)
|
||||
.setDirectionY(tank.direction.y)
|
||||
);
|
||||
}
|
||||
if (state.x != tank.x || state.y != tank.y) {
|
||||
changes.push(new GameChange()
|
||||
.setType(GameChangeType.MOVED)
|
||||
.setObjectType(GameObjectType.TANK)
|
||||
.setObjectId(tank.id)
|
||||
.setX(tank.x)
|
||||
.setY(tank.y)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changes.length > 0) {
|
||||
broadcast(gameId, new GameUpdateResponse().setChanges(changes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,8 +307,7 @@ class Session implements IConnectionHandler implements IPacketHandler {
|
||||
|
||||
public function onStartGameRequest(packet:StartGameRequest):Void {
|
||||
var game:Game = games.getCreatedGame(person.id);
|
||||
game.setState(GameState.STARTED);
|
||||
games.broadcast(game.id, new StartGameResponse().setGame(game));
|
||||
games.start(game.id);
|
||||
}
|
||||
|
||||
public function onExitGameRequest(packet:ExitGameRequest):Void {
|
||||
@@ -219,11 +316,18 @@ class Session implements IConnectionHandler implements IPacketHandler {
|
||||
}
|
||||
|
||||
public function onGameActionRequest(packet:GameActionRequest):Void {
|
||||
switch (packet.type) {
|
||||
case GameActionType.SHOT:
|
||||
|
||||
case GameActionType.MOVE:
|
||||
|
||||
var game:ITankz = games.running.get(games.getPersonGameId(person.id));
|
||||
for (tank in game.tanks) {
|
||||
if (tank.id == person.id) {
|
||||
switch (packet.type) {
|
||||
case GameActionType.SHOT:
|
||||
tank.shot();
|
||||
case GameActionType.MOVE:
|
||||
tank.move(new Direction(packet.directionX, packet.directionY));
|
||||
case GameActionType.STOP:
|
||||
tank.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
113
src/server/haxe/ru/m/tankz/server/session/Thread.hx
Normal file
113
src/server/haxe/ru/m/tankz/server/session/Thread.hx
Normal file
@@ -0,0 +1,113 @@
|
||||
package ru.m.tankz.server.session;
|
||||
|
||||
enum ThreadHandle {
|
||||
}
|
||||
|
||||
class Thread {
|
||||
|
||||
var handle : ThreadHandle;
|
||||
|
||||
function new(h) {
|
||||
handle = h;
|
||||
}
|
||||
|
||||
/**
|
||||
Send a message to the thread queue. This message can be readed by using [readMessage].
|
||||
**/
|
||||
public function sendMessage( msg : Dynamic ) {
|
||||
thread_send(handle,msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns the current thread.
|
||||
**/
|
||||
public static function current() {
|
||||
return new Thread(thread_current());
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new thread that will execute the [callb] function, then exit.
|
||||
**/
|
||||
public static function create( callb : Void -> Void ) {
|
||||
return new Thread(thread_create(function(_) { return callb(); },null));
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a message from the thread queue. If [block] is true, the function
|
||||
blocks until a message is available. If [block] is false, the function
|
||||
returns [null] if no message is available.
|
||||
**/
|
||||
public static function readMessage( block : Bool ) : Dynamic {
|
||||
return thread_read_message(block);
|
||||
}
|
||||
|
||||
@:keep function __compare(t) {
|
||||
return untyped __dollar__compare(handle,t.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
Starts an OS message loop after [osInitialize] has been done.
|
||||
In that state, the UI handled by this thread will be updated and
|
||||
[sync] calls can be performed. The loop returns when [exitLoop] is
|
||||
called for this thread.
|
||||
**
|
||||
public static function osLoop() {
|
||||
if( os_loop == null ) throw "Please call osInitialize() first";
|
||||
os_loop();
|
||||
}
|
||||
|
||||
/**
|
||||
The function [f] will be called by this thread if it's in [osLoop].
|
||||
[sync] returns immediatly. See [osInitialize] remarks.
|
||||
**
|
||||
public function sync( f : Void -> Void ) {
|
||||
os_sync(handle,f);
|
||||
}
|
||||
|
||||
/**
|
||||
The function [f] will be called by this thread and the calling thread
|
||||
will wait until the result is available then return its value.
|
||||
**
|
||||
public function syncResult<T>( f : Void -> T ) : T {
|
||||
if( this == current() )
|
||||
return f();
|
||||
var v = new neko.vm.Lock();
|
||||
var r = null;
|
||||
sync(function() {
|
||||
r = f();
|
||||
v.release();
|
||||
});
|
||||
v.wait();
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
Exit from [osLoop].
|
||||
**
|
||||
public function exitLoop() {
|
||||
os_loop_stop(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
If you want to use the [osLoop], [sync] and [syncResult] methods, you
|
||||
need to call [osInitialize] before creating any thread or calling [current].
|
||||
This will load [os.ndll] library and initialize UI methods for each thread.
|
||||
**
|
||||
public static function osInitialize() {
|
||||
os_loop = neko.Lib.load("os","os_loop",0);
|
||||
os_loop_stop = neko.Lib.load("os","os_loop_stop",1);
|
||||
os_sync = neko.Lib.load("os","os_sync",2);
|
||||
}
|
||||
|
||||
static var os_loop = null;
|
||||
static var os_loop_stop = null;
|
||||
static var os_sync = null;
|
||||
*/
|
||||
|
||||
static var thread_create = neko.Lib.load("std","thread_create",2);
|
||||
static var thread_current = neko.Lib.load("std","thread_current",0);
|
||||
static var thread_send = neko.Lib.load("std","thread_send",2);
|
||||
static var thread_read_message = neko.Lib.load("std","thread_read_message",1);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user