1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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 <https://www.gnu.org/licenses/>.
# ==============================================================================
""" 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
|