From 6187faf20384b0c5a4966343b2d4ca47f8b11e45 Mon Sep 17 00:00:00 2001 From: Philip Paquette Date: Wed, 26 Sep 2018 07:48:55 -0400 Subject: Release v1.0.0 - Diplomacy Game Engine - AGPL v3+ License --- diplomacy/engine/message.py | 115 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 diplomacy/engine/message.py (limited to 'diplomacy/engine/message.py') diff --git a/diplomacy/engine/message.py b/diplomacy/engine/message.py new file mode 100644 index 0000000..2d6d644 --- /dev/null +++ b/diplomacy/engine/message.py @@ -0,0 +1,115 @@ +# ============================================================================== +# Copyright (C) 2019 - Philip Paquette +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see . +# ============================================================================== +""" Game message. Represent a message exchanged inside a game. + + Possible messages exchanges: + - power 1 -> power 2 + - power -> all game + - system -> power + - system -> all game + - system -> observers + - system -> omniscient observers + + Sender `system` is identified with constant SYSTEM defined below. + Recipients `all game`, `observers` and `omniscient observers` are identified respectively with constants + GLOBAL, OBSERVER and OMNISCIENT defined below. + + Consider using Game methods to generate appropriate messages instead of this class directly: + - Game.new_power_message() to send a message from a power to another. + - Game.new_global_message() to send a message from a power to all game. + - ServerGame.new_system_message() to send a server system message. + Use constant names defined below to specify recipient for system message when it's not a power name + (GLOBAL, OBSERVER or OMNISCIENT). +""" +from diplomacy.utils import parsing, strings +from diplomacy.utils.jsonable import Jsonable + +SYSTEM = 'SYSTEM' # sender +GLOBAL = 'GLOBAL' # recipient (all powers) +OBSERVER = 'OBSERVER' # recipient (all observer tokens) +OMNISCIENT = 'OMNISCIENT' # recipient (all omniscient tokens) + +class Message(Jsonable): + """ GameMessage class. Properties: + - sender: message sender name: either SYSTEM or a power name. + - recipient: message recipient name: either GLOBAL, OBSERVER, OMNISCIENT or a power name. + - time_sent: message timestamp in microseconds. + - phase: short name of game phase when message is sent. + - message: message body. + + Note about timestamp management: + We assume a message has an unique timestamp inside one game. To respect this rule, the server is the only one + responsible for generating message timestamps. This allow to generate timestamp or only 1 same machine (server) + instead of managing timestamps from many user machines, to prevent timestamp inconsistency when messages + are stored on server. Therefore, message timestamp is the time when server stores the message, not the time + when message was sent by any client. + """ + __slots__ = ['sender', 'recipient', 'time_sent', 'phase', 'message'] + model = { + strings.SENDER: str, # either SYSTEM or a power name. + strings.RECIPIENT: str, # either GLOBAL, OBSERVER, OMNISCIENT or a power name. + strings.TIME_SENT: parsing.OptionalValueType(int), # given by server. + strings.PHASE: str, # phase short name. + strings.MESSAGE: str, + } + + def __init__(self, **kwargs): + self.sender = None # type: str + self.recipient = None # type: str + self.time_sent = None # type: int + self.phase = None # type: str + self.message = None # type: str + super(Message, self).__init__(**kwargs) + + def __str__(self): + return '[%d/%s/%s->%s](%s)' % ( + self.time_sent, self.phase, self.sender, self.recipient, self.message) + + def __hash__(self): + return hash(self.time_sent) + + def __eq__(self, other): + assert isinstance(other, Message) + return self.time_sent == other.time_sent + + def __ne__(self, other): + assert isinstance(other, Message) + return self.time_sent != other.time_sent + + def __lt__(self, other): + assert isinstance(other, Message) + return self.time_sent < other.time_sent + + def __gt__(self, other): + assert isinstance(other, Message) + return self.time_sent > other.time_sent + + def __le__(self, other): + assert isinstance(other, Message) + return self.time_sent <= other.time_sent + + def __ge__(self, other): + assert isinstance(other, Message) + return self.time_sent >= other.time_sent + + def is_global(self): + """ Return True if this message is global. """ + return self.recipient == GLOBAL + + def for_observer(self): + """ Return True if this message is sent to observers. """ + return self.recipient == OBSERVER -- cgit v1.2.3