Skip to content

Commit

Permalink
Merge branch 'release/1.3'
Browse files Browse the repository at this point in the history
features:
* Dissolve callback functions into abstract methods in client-layer.
** This is more intuitive and simpler to use then callbacks.

fixed:
* Fixed player is not alive during spawn and before very first move.
* Fixed behavior for bots which sends no steer command.

other:
* Merged topic and adapter.
* Simply set logging level everywhere.
  • Loading branch information
Danny Lade committed Feb 9, 2019
2 parents 79653f3 + 7a0ea7c commit 005e8c5
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 136 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ __pycache__
.ipynb_checkpoints/
.vscode/
.spyproject/
.idea/

*.egg-info/
11 changes: 9 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __readme__():

setup(
name='traze-client',
version='1.2',
version='1.3',
author="Danny Lade",
author_email="[email protected]",
description=("A client for the simple tron-like multi client online game called 'Traze' which is using MQTT for communication."), # noqa
Expand All @@ -44,7 +44,14 @@ def __readme__():
],

classifiers=[
"Development Status :: 5 - Production/Stable",
# Development Status :: 1 - Planning
# Development Status :: 2 - Pre-Alpha
# Development Status :: 3 - Alpha
# Development Status :: 4 - Beta
# Development Status :: 5 - Production/Stable
# Development Status :: 6 - Mature
# Development Status :: 7 - Inactive
"Development Status :: 1 - Planning",
"Topic :: Games/Entertainment :: Simulation",
"Programming Language :: Python :: 3.5",
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", # noqa
Expand Down
59 changes: 48 additions & 11 deletions traze/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,51 @@
@author: Danny Lade
"""
import uuid
import json
import functools

import paho.mqtt.client as mqtt

from .log import setup_custom_logger
from .topic import MqttTopic

__all__ = [
"TrazeMqttAdapter"
]


class _MqttTopic:

def __init__(self, client, name, *args):
def topic_name(topicName, *args):
if not args:
return topicName
return topicName.replace('+', '%s') % (args)

self._client = client
self._name = topic_name(name, *args)
self.functions = set()

def subscribe(self, on_payload_func):
def on_message(client, userdata, message):
payload = json.loads(str(message.payload, 'utf-8'))
for on_payload in self.functions:
on_payload(payload)

if not self.functions:
self._client.subscribe(self._name)
self._client.message_callback_add(self._name, on_message)

if on_payload_func not in self.functions:
self.functions.add(on_payload_func)

def publish(self, obj=None):
self._client.publish(self._name, json.dumps(obj))


class TrazeMqttAdapter:

def __init__(self, host='traze.iteratec.de', port=8883, transport='tcp'):
self.logger = setup_custom_logger(name=type(self).__name__)
self.logger = setup_custom_logger(self)

def _on_connect(client, userdata, flags, rc):
self.logger.info("Connected the MQTT broker.")
Expand All @@ -50,16 +79,17 @@ def _on_disconnect(client, userdata, rc):
self._client.connect(host, port)
self._client.loop_start()

def on_heartbeat(self, game_name, on_heartbeat):
# there is no heartbeat from server but the grid-event is a good base
self.__get_topic__('traze/+/grid', game_name).subscribe(on_heartbeat)

#
# world based topic(s)
# - parameters: None
#
def on_game_info(self, on_game_info):
self.__get_topic__('traze/games').subscribe(on_game_info)

def on_player_info(self, game_name, on_player_info):
self.__get_topic__('traze/+/player/+', game_name, self.__client_id__).subscribe(on_player_info) # noqa

#
# game based topic(s)
# - parameters: game_name
#
def on_grid(self, game_name, on_grid):
self.__get_topic__('traze/+/grid', game_name).subscribe(on_grid)

Expand All @@ -69,6 +99,13 @@ def on_players(self, game_name, on_players):
def on_ticker(self, game_name, on_ticker):
self.__get_topic__('traze/+/ticker', game_name).subscribe(on_ticker)

def on_player_info(self, game_name, on_player_info):
self.__get_topic__('traze/+/player/+', game_name, self.__client_id__).subscribe(on_player_info) # noqa

#
# player based topic(s)
# - parameters: game_name, player_id/player_name
#
def publish_join(self, game_name, player_name):
self.__get_topic__('traze/+/join', game_name).publish({'name': player_name, 'mqttClientName': self.__client_id__}) # noqa

Expand All @@ -81,6 +118,6 @@ def publish_bail(self, game_name, player_id, player_token):
def disconnect(self):
self._client.disconnect()

@functools.lru_cache()
@functools.lru_cache() # singleton by parameter (for same arguments always return the same object)
def __get_topic__(self, topic_name, *args):
return MqttTopic(self._client, topic_name, *args)
return _MqttTopic(self._client, topic_name, *args)
31 changes: 18 additions & 13 deletions traze/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,13 @@ def __repr__(self):

@classmethod
def from_name(cls, name):
for action in Action:
if action.name == name:
return action
raise ValueError('{} is not a valid action name'.format(name))
return cls.__members__[name]


class BotBase(Player, metaclass=ABCMeta):
def __init__(self, game, name=None):
def on_update():
next_action = None
actions = self.actions
if actions:
next_action = self.next_action(actions)
if next_action:
self.steer(next_action)

super().__init__(game, name, on_update)
def __init__(self, game, name=None):
super().__init__(game, name)

def play(self, count=1, suppress_server_timeout=False):
for i in range(1, count + 1):
Expand All @@ -76,13 +66,28 @@ def play(self, count=1, suppress_server_timeout=False):

self.destroy()

def on_update(self):
self.logger.debug("on_update: {}".format((self.x, self.y)))

next_action = None
actions = self.actions
if actions:
next_action = self.next_action(actions)
self.steer(next_action)

def on_dead(self):
self.logger.debug("on_dead: {}".format((self.x, self.y)))

return

@property
def actions(self):
valid_actions = set()
for action in list(Action):
if self.valid(self.x + action.dX, self.y + action.dY):
valid_actions.add(action)

self.logger.debug("valid_actions: {}".format(valid_actions))
return tuple(valid_actions)

@abstractmethod
Expand Down
Loading

0 comments on commit 005e8c5

Please sign in to comment.