From b51fe6b55c735277c49448b966730099473983dd Mon Sep 17 00:00:00 2001 From: Olaf Gladis Date: Sat, 29 Nov 2014 15:41:10 +0100 Subject: [PATCH 1/5] WIP --- bomber/engine.py | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/bomber/engine.py b/bomber/engine.py index de3d8cb..3d5d6c4 100644 --- a/bomber/engine.py +++ b/bomber/engine.py @@ -2,6 +2,7 @@ import random import pygameui as ui from itertools import chain +# from decorator import decorator import asyncio TILE_WIDTH = 10 @@ -209,9 +210,20 @@ class IndestructableWall(Wall): COLLIDING_OBJECTS = (IndestructableWall, DestructableWall, Bomb) +# @decorator +def rest_call(fn): + def foo(self, *args, **kw): + ret = fn(*args, **kw) + if ret: + self.client.inform(*ret) + else: + self.client.inform(("ACK", None)) + return foo + + class Player: - def __init__(self, position, client, name="Hans", color=None, password="", id=None, map=None): + def __init__(self, position, client, name="Hans", color=None, password="", id=None, map=None, async=False): x, y = position self.__x = x self.__y = y @@ -220,6 +232,7 @@ def __init__(self, position, client, name="Hans", color=None, password="", id=No hashpassword = lambda x: x self.name = name self.client = client + self.async = async self.color = { "1": (255, 0, 0), # red "2": (0, 0, 255), # blue @@ -309,36 +322,42 @@ def handle_msg(self, msg): handler = getattr(self, "do_{}".format(msg_type)) ret = handler(**msg) if ret: - if isinstance(ret, tuple) and len(ret) == 2: - self.client.inform(* ret) - else: - self.client.inform("ACK", ret) + self.client.inform(* ret) except AttributeError: self.client.inform("ERR", "The function ({}) you are calling is not available".format(msg_type)) - def do_whoami(self, **kwargs): - return ("WHOAMI", self.whoami_data) - - def do_map(self, **kwargs): - return("MAP", "\n".join( - "".join(e.char for e in line) for line in self.map._map),) - def do_move(self, direction, distance=1., **kwargs): assert direction in "wasd" assert isinstance(distance, (int, float)) self.direction = direction self.moving = distance * 10 # TODO, don't use constant + return ("MOVE", self.id, self.position, direction, distance) def do_bomb(self, **kwargs): - self.map.plant_bomb(self, fuse_time=kwargs.get("fuse_time", 5)) + fuse_time = kwargs.get("fuse_time", 5) + self.map.plant_bomb(self, fuse_time=fuse_time) + return ("BOMB", self.id, self.position, fuse_time) + + # REST packets, answer should only go to sender + + @rest_call + def do_whoami(self, **kwargs): + return ("WHOAMI", self.whoami_data) + + @rest_call + def do_map(self, **kwargs): + return("MAP", "\n".join( + "".join(e.char for e in line) for line in self.map._map),) + @rest_call def do_what_bombs(self, **kwargs): return ("WHAT_BOMBS", [ (b.position_int, b.update_timer, b.state,) for b in self.map.items if isinstance(b, Bomb) ]) + @rest_call def do_what_foes(self, **kwargs): return ("WHAT_FOES", [ (p.position_int, p.direction, p.id, p.name) for p in self.map.players @@ -514,7 +533,7 @@ def key_down(self, key, code): elif code.lower() == "b": self.players[0].do_bomb() - def player_register(self, client, username, password="", **kw): + def player_register(self, client, username, password="", async=False, **kw): try: if username in self.users: position = self.users[username] @@ -533,6 +552,7 @@ def player_register(self, client, username, password="", **kw): map=self, name=username, password=password, + async=async, ) if old_player: player.points = old_player.points From 5e3bae79e5e5e39d9eb29789d720700e31e9b9d7 Mon Sep 17 00:00:00 2001 From: Olaf Gladis Date: Sat, 29 Nov 2014 16:32:40 +0100 Subject: [PATCH 2/5] first working solution --- bomber/engine.py | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/bomber/engine.py b/bomber/engine.py index 3d5d6c4..7b78372 100644 --- a/bomber/engine.py +++ b/bomber/engine.py @@ -2,7 +2,6 @@ import random import pygameui as ui from itertools import chain -# from decorator import decorator import asyncio TILE_WIDTH = 10 @@ -210,10 +209,9 @@ class IndestructableWall(Wall): COLLIDING_OBJECTS = (IndestructableWall, DestructableWall, Bomb) -# @decorator def rest_call(fn): def foo(self, *args, **kw): - ret = fn(*args, **kw) + ret = fn(self, *args, **kw) if ret: self.client.inform(*ret) else: @@ -257,6 +255,7 @@ def __init__(self, position, client, name="Hans", color=None, password="", id=No client.on_message.connect(self.handle_msg) self.client.inform("OK", self.whoami_data) + self._setup_async_inform_function() @property def position_int(self): @@ -296,6 +295,20 @@ def get_direction_to_int_position(self): elif yf < yi: return "s" + def inform_async(self, msg_type, data): + self.client.inform(msg_type, data) + + def rest_inform(self, msg_type, data): + accepted_msgtypes = { + "BOMB", "MOVE" + } + if data[0] == self.id and msg_type in accepted_msgtypes: + self.client.inform(msg_type, data) + + def _setup_async_inform_function(self): + if not self.async: + self.inform_async = self.rest_inform + def die(self, hard=False): print("die {}, tonight you dine in hell".format(self.name)) loop = asyncio.get_event_loop() @@ -320,12 +333,16 @@ def handle_msg(self, msg): msg_type = msg.pop("type") try: handler = getattr(self, "do_{}".format(msg_type)) - ret = handler(**msg) - if ret: - self.client.inform(* ret) except AttributeError: self.client.inform("ERR", "The function ({}) you are calling is not available".format(msg_type)) + ret = handler(**msg) + + if ret: + msg_type, *rest = ret + rest.insert(0, self.id) + self.map.inform_all(msg_type, rest) + # self.client.inform(* ret) def do_move(self, direction, distance=1., **kwargs): assert direction in "wasd" @@ -333,12 +350,12 @@ def do_move(self, direction, distance=1., **kwargs): self.direction = direction self.moving = distance * 10 # TODO, don't use constant - return ("MOVE", self.id, self.position, direction, distance) + return ("MOVE", self.id, self.position_int, direction, distance) def do_bomb(self, **kwargs): fuse_time = kwargs.get("fuse_time", 5) self.map.plant_bomb(self, fuse_time=fuse_time) - return ("BOMB", self.id, self.position, fuse_time) + return ("BOMB", self.id, self.position_int, fuse_time) # REST packets, answer should only go to sender @@ -574,6 +591,10 @@ def player_unregister(self, position, password): # self.freespawnpoints.append(position) return old_player + def inform_all(self, msg_type, msg): + for player in self.players: + player.inform_async(msg_type, msg) + def plant_bomb(self, player, fuse_time): bombs = [b for b in self.items if isinstance(b, Bomb) and b.player is player and b.state == "ticking"] if len(bombs) >= player.bombamount: From 4015b82c24be090d97fb28f312f3977ed81d9981 Mon Sep 17 00:00:00 2001 From: Olaf Gladis Date: Sun, 30 Nov 2014 13:18:55 +0100 Subject: [PATCH 3/5] rest call points added --- bomber/engine.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bomber/engine.py b/bomber/engine.py index 7b78372..2d9fe3c 100644 --- a/bomber/engine.py +++ b/bomber/engine.py @@ -380,6 +380,10 @@ def do_what_foes(self, **kwargs): (p.position_int, p.direction, p.id, p.name) for p in self.map.players ]) + @rest_call + def do_points(self, **kwargs): + return ("POINTS", [(p.id, p.name, p.points) for p in self.map.players]) + def update(self, dt): if not self.moving > 0 or not self.alive: return From c9f3dc6a0c90938cb1e697e6a37a1b54c996d905 Mon Sep 17 00:00:00 2001 From: Olaf Gladis Date: Sun, 30 Nov 2014 13:19:39 +0100 Subject: [PATCH 4/5] fix player move async info --- bomber/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bomber/engine.py b/bomber/engine.py index 2d9fe3c..08f640f 100644 --- a/bomber/engine.py +++ b/bomber/engine.py @@ -350,7 +350,7 @@ def do_move(self, direction, distance=1., **kwargs): self.direction = direction self.moving = distance * 10 # TODO, don't use constant - return ("MOVE", self.id, self.position_int, direction, distance) + return ("MOVE", self.position_int, direction, distance) def do_bomb(self, **kwargs): fuse_time = kwargs.get("fuse_time", 5) From 3215891cd8fd74e97dcad7372f552ab6770293e3 Mon Sep 17 00:00:00 2001 From: Olaf Gladis Date: Sun, 30 Nov 2014 13:20:33 +0100 Subject: [PATCH 5/5] bomb info is now state dependend --- bomber/engine.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/bomber/engine.py b/bomber/engine.py index 08f640f..a91cf08 100644 --- a/bomber/engine.py +++ b/bomber/engine.py @@ -55,6 +55,8 @@ def hide(self): class FireTrail(MapObject): def __init__(self, bomb, start, end): + self.start = start + self.end = end x, y = start _x, _y = end @@ -113,11 +115,26 @@ def state(self, value): self._state = value self.on_new_state(value) + def bomb_info(self, bomb): + # for clients it is not a difference if the bomb is exploding or burning + # since the exploding state is just present for 0.2 seconds it will probably produce bugs + # if the client doesn't know or care about it. + + default_info = (b.position_int, b.update_timer, b.state,) + if b.state == "exploding": + return (b.position_int, b.update_timer + 1.5, "burning",) + (self.fire_trails) + elif b.state == "burning": + return default_info + ([f.end for f in self.fire_trails],) + elif b.state == "hiding": + return default_info + ([w.position_int for w in self.destroyed_walls],) + return default_info + (None,) + def on_new_state(self, state): if state == "exploding": self.color = (255, 255, 230) self.update_timer = self.exploding_time self.deploy_fire_trails() + self.player.map.inform_async(self.bomb_info()) elif state == "burning": self.color = (255, 55, 10) self.update_timer = self.burn_time @@ -128,6 +145,7 @@ def on_new_state(self, state): self.player.points += len([w for w in self.destroyed_walls if not w.hidden]) for wall in self.destroyed_walls: wall.hide() + self.player.map.inform_async(self.bomb_info()) def deploy_fire_trails(self): for direction in "wasd": @@ -354,8 +372,8 @@ def do_move(self, direction, distance=1., **kwargs): def do_bomb(self, **kwargs): fuse_time = kwargs.get("fuse_time", 5) - self.map.plant_bomb(self, fuse_time=fuse_time) - return ("BOMB", self.id, self.position_int, fuse_time) + bomb = self.map.plant_bomb(self, fuse_time=fuse_time) + return ("BOMB", self._bomb_info(bomb)) # REST packets, answer should only go to sender @@ -371,7 +389,7 @@ def do_map(self, **kwargs): @rest_call def do_what_bombs(self, **kwargs): return ("WHAT_BOMBS", [ - (b.position_int, b.update_timer, b.state,) for b in self.map.items if isinstance(b, Bomb) + b.bomb_info() for b in self.map.items if isinstance(b, Bomb) ]) @rest_call