From b5e8a9b9476eefdc6be86447b265866f59521215 Mon Sep 17 00:00:00 2001 From: Elijah Cohen Date: Wed, 17 Apr 2019 16:32:32 -0500 Subject: [PATCH] preliminary node nonsenses --- .gitignore | 6 ++++ game.py | 33 --------------------- matchmaker.py | 38 ------------------------ connector.py => old/connector.py | 0 old/game.py | 31 +++++++++++++++++--- gamestate.py => old/gamestate.py | 0 main.py => old/main.py | 0 old/matchmaker.py | 50 ++++++++++++++++++-------------- player.py => old/player.py | 0 server/game.js | 25 ++++++++++++++++ server/gamestate.js | 15 ++++++++++ server/matchmaker.js | 30 +++++++++++++++++++ server/package-lock.json | 19 ++++++++++++ server/player.js | 34 ++++++++++++++++++++++ 14 files changed, 185 insertions(+), 96 deletions(-) delete mode 100644 game.py delete mode 100644 matchmaker.py rename connector.py => old/connector.py (100%) rename gamestate.py => old/gamestate.py (100%) rename main.py => old/main.py (100%) rename player.py => old/player.py (100%) create mode 100644 server/game.js create mode 100644 server/gamestate.js create mode 100644 server/matchmaker.js create mode 100644 server/package-lock.json create mode 100644 server/player.js diff --git a/.gitignore b/.gitignore index 75fc14d..9a77fd5 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,9 @@ lib/ /web/socket.js~ /web/test.html~ /web/test.js~ +/server/game.js~ +/server/node_modules/* +server/node_modules/* +/server/gamestate.js~ +/server/matchmaker.js~ +/server/player.js~ diff --git a/game.py b/game.py deleted file mode 100644 index b6aa439..0000000 --- a/game.py +++ /dev/null @@ -1,33 +0,0 @@ - - -SPF = 0.5 # half second for testing purposes -# MS_PER_FRAME = 67 # 15 fps? - - -import threading - -# not a (subclass of) thread, all this has to be is a timer that calls itself or whatever, hope it doesn't take too long to run or whatever - -import gamestate - -class Game(): - def __init__(self, players): - self.players = players - self.game_state = gamestate.GameState() - for player in self.players: # CAUTION HERE, MIGHT NEED TO MODIFY - player.run() - def run(self): - threading.Timer(SPF, self.run).start() - # okay, things to do here: - # check all the inputs in the player classes - # update global game state - # send data to players - inputs = [] - for idx, val in enumerate(self.players): - inputs.append(val.get_status()) - self.game_state.update_state(inputs) - self.game_state.advance_frame() - state = self.game_state.get_state() - for player in self.players: - player.send_data(state) - print(state) diff --git a/matchmaker.py b/matchmaker.py deleted file mode 100644 index 3d56670..0000000 --- a/matchmaker.py +++ /dev/null @@ -1,38 +0,0 @@ - -WS_HOST = 'localhost' -WS_PORT = 6789 -NUM_PLAYERS = 4 - -import asyncio -import websockets -import threading - -import logging - -logger = logging.getLogger('websockets') -logger.setLevel(logging.INFO) -logger.addHandler(logging.StreamHandler()) - -import player -import game - -class Matchmaker(): - def manage_incoming(self,websocket, path): - # init a player, etc etc - new_player = player.Player(websocket) - self.players.append(new_player) - if len(self.players) > (NUM_PLAYERS - 1): # shenanigans to fix potential problem of stranding some (n+1)th player - with self.lock: - new_game = game.Game(self.players[:NUM_PLAYERS]) - new_game.run() - self.players = self.players[NUM_PLAYERS:] - print("did it") - def __init__(self): - # todo: this is where I initialise the listening stuff for websockets, where I pass manage_incoming (or whatev) to the thing - self.players = [] - self.lock = threading.Lock() - async def manager(ws,p): - self.manage_incoming(ws,p) - start_server = websockets.serve(manager,WS_HOST,WS_PORT) - asyncio.get_event_loop().run_until_complete(start_server) - asyncio.get_event_loop().run_forever() diff --git a/connector.py b/old/connector.py similarity index 100% rename from connector.py rename to old/connector.py diff --git a/old/game.py b/old/game.py index 4a2a507..b6aa439 100644 --- a/old/game.py +++ b/old/game.py @@ -1,10 +1,33 @@ -import websockets + +SPF = 0.5 # half second for testing purposes +# MS_PER_FRAME = 67 # 15 fps? + + import threading -class GamePlayer(threading.Thread): +# not a (subclass of) thread, all this has to be is a timer that calls itself or whatever, hope it doesn't take too long to run or whatever + +import gamestate + +class Game(): def __init__(self, players): - threading.Thread.__init__() self.players = players + self.game_state = gamestate.GameState() + for player in self.players: # CAUTION HERE, MIGHT NEED TO MODIFY + player.run() def run(self): - print("starting a thread or whatever: " + name) + threading.Timer(SPF, self.run).start() + # okay, things to do here: + # check all the inputs in the player classes + # update global game state + # send data to players + inputs = [] + for idx, val in enumerate(self.players): + inputs.append(val.get_status()) + self.game_state.update_state(inputs) + self.game_state.advance_frame() + state = self.game_state.get_state() + for player in self.players: + player.send_data(state) + print(state) diff --git a/gamestate.py b/old/gamestate.py similarity index 100% rename from gamestate.py rename to old/gamestate.py diff --git a/main.py b/old/main.py similarity index 100% rename from main.py rename to old/main.py diff --git a/old/matchmaker.py b/old/matchmaker.py index 53cb72a..3d56670 100644 --- a/old/matchmaker.py +++ b/old/matchmaker.py @@ -1,30 +1,38 @@ +WS_HOST = 'localhost' +WS_PORT = 6789 +NUM_PLAYERS = 4 + import asyncio import websockets import threading -import pbr_constants +import logging + +logger = logging.getLogger('websockets') +logger.setLevel(logging.INFO) +logger.addHandler(logging.StreamHandler()) + +import player +import game class Matchmaker(): + def manage_incoming(self,websocket, path): + # init a player, etc etc + new_player = player.Player(websocket) + self.players.append(new_player) + if len(self.players) > (NUM_PLAYERS - 1): # shenanigans to fix potential problem of stranding some (n+1)th player + with self.lock: + new_game = game.Game(self.players[:NUM_PLAYERS]) + new_game.run() + self.players = self.players[NUM_PLAYERS:] + print("did it") def __init__(self): - self.lock = threading.Lock() + # todo: this is where I initialise the listening stuff for websockets, where I pass manage_incoming (or whatev) to the thing self.players = [] - async def get_game(self,p): - with self.lock: - self.players.append(p) - if len(self.players) ==pbr_constants.num_players: - self.new_game() - def new_game(self): - with self.lock: - print(self.players) - - self.players = [] - - - - - - - -if __name__=="__main__": - mm = Matchmaker() + self.lock = threading.Lock() + async def manager(ws,p): + self.manage_incoming(ws,p) + start_server = websockets.serve(manager,WS_HOST,WS_PORT) + asyncio.get_event_loop().run_until_complete(start_server) + asyncio.get_event_loop().run_forever() diff --git a/player.py b/old/player.py similarity index 100% rename from player.py rename to old/player.py diff --git a/server/game.js b/server/game.js new file mode 100644 index 0000000..9241cbe --- /dev/null +++ b/server/game.js @@ -0,0 +1,25 @@ + +const GameState = require('./gamestate.js'); + +function Game(players) { + this.players = players; + this.state = new GameState(); + this.timeout = null; +} + +Game.prototype.start = function(ms) { + this.timeout = setInterval(this.getNextFrame, ms); +} + +Game.prototype.getNextFrame = function() { + // + var inputs = this.players.map(function(p) {return p.get_status();}); + this.state.updateState(inputs); + var state = this.state.getState(); + for(var i=0; i NUM_PLAYERS) { + // is the slicing necessary? I'm not sure I understand js's mechanisms without threads + game = new Game(players.slice(0, NUM_PLAYERS)); + // + game.start(MS_PER_FRAME); + // + players = players.slice(NUM_PLAYERS); + } +} diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 0000000..fb88917 --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,19 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } +} diff --git a/server/player.js b/server/player.js new file mode 100644 index 0000000..0c0767e --- /dev/null +++ b/server/player.js @@ -0,0 +1,34 @@ + + +function Player(ws) { + this.status = 'x'; + this.socket = ws; + this.socket.onmessage = this.listener; +} + +Player.prototype.listener = function(msg) { + var data = msg.data; + if(typeof data == "string" && data.length > 0) { + if(data[0] == 'u') + this.status = 'u'; + else if(data[0] == 'd') + this.status = 'd'; + else + this.status = 'x'; + } +} + +Player.prototype.send_data = function(data) { + if(this.socket.readyState==1) { // TODO: replace the '1' with the proper identifier (the ready state constant) + this.socket.send(data); + } +} + +Player.prototype.get_status = function() { + var stat = this.status; + this.status = 'x'; + return stat; +} + + +module.exports = Player; -- 2.39.2