From: Elijah Cohen Date: Fri, 12 Apr 2019 23:11:04 +0000 (-0500) Subject: lots of restructuring, many things are good X-Git-Url: https://git.eli173.com/?a=commitdiff_plain;h=34e4cf81ed99fb62250fc51df4fbe0cf0a994aca;p=pong_br lots of restructuring, many things are good ~player~ doesn't work, so I'm committing before rewriting it, to be very async --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..75fc14d --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +/NOTES.org~ +__pycache__/ +bin/ +/connector.py~ +env/ +/game.py~ +/gamestate.py~ +include/ +lib/ +/main.py~ +/matchmaker.py~ +/player.py~ +/player_manager.py~ +/web/drawing.js~ +/web/index.html~ +/web/socket.js~ +/web/test.html~ +/web/test.js~ diff --git a/NOTES.org b/NOTES.org new file mode 100644 index 0000000..d9acd67 --- /dev/null +++ b/NOTES.org @@ -0,0 +1,23 @@ + + +Basic infrastructure for web work: +have a player manager class thread which checks main game state and sends it out every so often (1/15 seconds?) (can also form ground work for computer players +have a single game creator class which waits until there are ten connections, then spawns a new game thread +game thread which manages game state and reads player logic + +sososo + +The general outline of the game is that we have some large number of players $n$, arranged in a $2n$-sided regular polygon, where the player has their pong-space, and is surrounded by two walls. The walls primarily serve the purpose of having the game end nicely when there are two players left: it becomes a regular game of pong. + +I'm going to limit the number of players to 10 for the time being, I think anything with more than 20 sides might be a bit too much. 20 might be pushing it actually. + + +At the moment I think I've figured out basic matchmaking (the br format pretty much lets me ignore skill levels so I can just throw anyone with anyone), so the main concern is the actual pong gameplay. My biggest challenge is how to shrink the circle when someone dies. +There's gotta be a decent transformation I can come up with? Probably mostly trig. I've gotta work it so multiple things can go away at the same time. + + + +Okay MM doesn't actually work yet: new strat tho. +Have the recieving thingy (the start_server bit, where we recieve the new ws connections) pass along some info to an asynchronous matchmaking service. That recieving thingy will just wait until the match is made, at which point it'll recieve some game-interaction object, and will send and recieve updates from the game started in some separate thread. + +As far as dev, I think I'll try to do the networking then actually do game logic diff --git a/connector.py b/connector.py new file mode 100644 index 0000000..a3caa64 --- /dev/null +++ b/connector.py @@ -0,0 +1,10 @@ + + +import asyncio +import websockets +import threading + + +async def getconnection(websocket, path): + + diff --git a/game.py b/game.py new file mode 100644 index 0000000..1634a67 --- /dev/null +++ b/game.py @@ -0,0 +1,33 @@ + + +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: + 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/gamestate.py b/gamestate.py new file mode 100644 index 0000000..f20f2b8 --- /dev/null +++ b/gamestate.py @@ -0,0 +1,12 @@ + + +class GameState(): + def __init__(self): + self.inputs = [] + def update_state(self, inputs): + self.inputs = inputs + def get_state(self): + return ''.join(self.inputs) + def advance_frame(self): + pass + diff --git a/main.py b/main.py new file mode 100644 index 0000000..c146580 --- /dev/null +++ b/main.py @@ -0,0 +1,9 @@ + + + +import matchmaker + + + +if __name__ == "__main__": + mm = matchmaker.Matchmaker() diff --git a/matchmaker.py b/matchmaker.py new file mode 100644 index 0000000..3d56670 --- /dev/null +++ b/matchmaker.py @@ -0,0 +1,38 @@ + +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/old/demo.py b/old/demo.py new file mode 100644 index 0000000..f969653 --- /dev/null +++ b/old/demo.py @@ -0,0 +1,39 @@ + + +import asyncio +import websockets +import threading + + +class Matcher(): + def __init__(self): + self.lock = threading.Lock() + self.players = [] + def add_player(self,ws): + with self.lock: + self.players.append(ws) + if len(self.players) == 4: + self.new_game() + def new_game(self): + print(self.players) + self.players = [] + +async def hello(ws, path, matcher): + txt = await ws.recv() + + matcher.add_player(ws) + + print(txt) + rep = "hey you" + + await ws.send(rep) + + +if __name__ == "__main__": + matcher = Matcher() + async def hi(ws,path): + await hello(ws,path,matcher) + start_server = websockets.serve(hi, 'localhost', 6789) + + asyncio.get_event_loop().run_until_complete(start_server) + asyncio.get_event_loop().run_forever() diff --git a/old/game.py b/old/game.py new file mode 100644 index 0000000..4a2a507 --- /dev/null +++ b/old/game.py @@ -0,0 +1,10 @@ + +import websockets +import threading + +class GamePlayer(threading.Thread): + def __init__(self, players): + threading.Thread.__init__() + self.players = players + def run(self): + print("starting a thread or whatever: " + name) diff --git a/old/matchmaker.py b/old/matchmaker.py new file mode 100644 index 0000000..53cb72a --- /dev/null +++ b/old/matchmaker.py @@ -0,0 +1,30 @@ + +import asyncio +import websockets +import threading + +import pbr_constants + +class Matchmaker(): + def __init__(self): + self.lock = threading.Lock() + 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() diff --git a/old/pbr_constants.py b/old/pbr_constants.py new file mode 100644 index 0000000..a8d4b0d --- /dev/null +++ b/old/pbr_constants.py @@ -0,0 +1,6 @@ + +fps = 30 + +num_players = 5 + +max_games = 100 diff --git a/old/playfield.py b/old/playfield.py new file mode 100644 index 0000000..3edee85 --- /dev/null +++ b/old/playfield.py @@ -0,0 +1,5 @@ + +class PlayField(): + + def __init__(self, players): + self.players = players diff --git a/old/socket.py b/old/socket.py new file mode 100644 index 0000000..8c340a4 --- /dev/null +++ b/old/socket.py @@ -0,0 +1,20 @@ + +import asyncio +import websockets +import threading + +import pbr_constants + + +class SocketHandler(): + def __init__(self): + + + + + + + + + +def listener(ws, path): diff --git a/player.py b/player.py new file mode 100644 index 0000000..e10dfd4 --- /dev/null +++ b/player.py @@ -0,0 +1,33 @@ + + +import asyncio +import websockets +import threading + + +class Player(threading.Thread): + def __init__(self, socket): + super().__init__() + self.game = None + self.socket = socket + self.status = 'x' + self.status_lock = threading.Lock() + async def run(self): + print('fired') + msg = await self.socket.recv() + print('recv') + # should be 'u' or 'd', if neither + with self.status_lock: + if len(msg) > 0: + self.status = msg[0] + else: + self.status = 'x' + # needs to be re-ran at this point? probably + def send_data(self, data): + # to be used by the game thread thingy + self.socket.send(data) + def get_status(self): + with self.status_lock: + stat = self.status + self.status = 'x' + return stat diff --git a/web/drawing.js b/web/drawing.js new file mode 100644 index 0000000..7af6248 --- /dev/null +++ b/web/drawing.js @@ -0,0 +1,27 @@ + + +function drawngon(n,r) { + var cvs = document.getElementById('game'); + var ctx = cvs.getContext('2d'); + var angleper = 2*Math.PI/n; + var center = {x:cvs.width/2, y:cvs.height/2}; + + ctx.beginPath(); + ctx.moveTo(center.x+r, center.y); + var start = {x: center.x+r, y:center.y}; + for(var i=1; i + + + Pong Battle Royale + + + + + + + + + diff --git a/web/socket.js b/web/socket.js new file mode 100644 index 0000000..c55b0ac --- /dev/null +++ b/web/socket.js @@ -0,0 +1,63 @@ + +var prefixurl = "ws://localhost:6789" + +var keystate = ""; + +function doIt() { + console.log("aaa") + var ws = new WebSocket(prefixurl); + ws.onopen = function(event) { + ws.send("Hello World!"); + }; + ws.onmessage = function(event) { + console.log(event.data); + } +} + +function onload() { + var timer = 0; + document.getElementById("play").addEventListener('click',e=>doIt()); + document.getElementById("stop").addEventListener('click',e=>clearInterval(timer)); + console.log("ssss"); + + var ws = new WebSocket(prefixurl); + ws.onmessage = function(event) { + console.log("event.data") + } + timer = window.setInterval(function(){sendInput(ws);},1000); + window.onkeydown = (e=>keypressHandler(e,true)); + window.onkeyup = (e=>keypressHandler(e,false)); +} + +window.addEventListener("DOMContentLoaded",e=> onload()); + + +function sendInput(ws) { + if(keystate != '') { + ws.send(keystate); + } +} + +function keypressHandler(evt,isdn) { + if(evt.keyCode == '38') { + if(isdn) { + keystate = 'u'; + } + else if(keystate=='u') { + keystate = ''; + } + } + else if(evt.keyCode == '40') { + if(isdn) { + keystate = 'd'; + } + else if(keystate=='d') { + keystate = ''; + } + } +} + +function recievemessage(evt) { + + +} diff --git a/web/test.html b/web/test.html new file mode 100644 index 0000000..0198bad --- /dev/null +++ b/web/test.html @@ -0,0 +1,24 @@ + + + + Pong Battle Royale + + + + Testing page for the websocket infrastructure I've drummed up +
+ + + +
+ response from server: +
+
+ + diff --git a/web/test.js b/web/test.js new file mode 100644 index 0000000..aabbe0e --- /dev/null +++ b/web/test.js @@ -0,0 +1,30 @@ + +var prefixurl = "ws://localhost:6789" + +theSocket = null; + + +function send(k, s) { + // sends key k thru socket s + console.log(k); + theSocket.send(k); +} + +function start() { + // opens up a nice websocket + theSocket = new WebSocket(prefixurl); + theSocket.onmessage = function (e) { + newdiv = document.createElement('div') + newdiv.innerText = "data:" + e.data; + document.getElementById('content').appendChild(newdiv); + } +} + + + +function onload() { + document.getElementById("connect").addEventListener('click', e=> start()); + document.getElementById("up").addEventListener('click', e=> send('u',theSocket)); + document.getElementById("dn").addEventListener('click', e=> send('d',theSocket)); +} +window.addEventListener("DOMContentLoaded", e => onload());