Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PROPOSAL] thread_idx "lock" for communications #9

Open
wants to merge 1 commit into
base: intent_log
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion diplomacy/client/notification_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ def on_game_message_received(game, notification):
:type game: diplomacy.client.network_game.NetworkGame
:type notification: diplomacy.communication.notifications.GameMessageReceived
"""
Game.add_message(game, notification.message)
if notification.message.time_sent != 0:
Game.add_message(game, notification.message)

def on_game_processed(game, notification):
""" Manage notification GamePhaseUpdate (for omniscient and observer games).
Expand Down
5 changes: 4 additions & 1 deletion diplomacy/client/response_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,10 @@ def on_send_game_message(context, response):
request = context.request # type: requests.SendGameMessage
message = request.message
message.time_sent = response.data
Game.add_message(context.game, message)
if message.time_sent == 0:
return 0

return Game.add_message(context.game, message)

def on_set_game_state(context, response):
""" Manage response for request SetGameState.
Expand Down
20 changes: 18 additions & 2 deletions diplomacy/engine/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ def new_log_data(self, body, recipient="OMNISCIENT"):
assert self.is_player_game()
return Log(phase=self.current_short_phase, sender=self.role, recipient=recipient, message=body)

def new_power_message(self, recipient, body):
def new_power_message(self, recipient, body, thread_idx=None):
""" Create a undated (without timestamp) power message to be sent from a power to another via server.
Server will answer with timestamp, and message will be updated
and added to local game messages.
Expand All @@ -893,7 +893,7 @@ def new_power_message(self, recipient, body):
assert self.is_player_game()
if not self.has_power(recipient):
raise exceptions.MapPowerException(recipient)
return Message(phase=self.current_short_phase, sender=self.role, recipient=recipient, message=body)
return Message(phase=self.current_short_phase, sender=self.role, recipient=recipient, message=body, thread_idx=thread_idx)
Copy link

@mjspeck mjspeck Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkj could you add the thread_idx param to the docstring? Otherwise, the only explanation for it would be in this PR.


def new_global_message(self, body):
""" Create an undated (without timestamp) global message to be sent from a power via server.
Expand Down Expand Up @@ -932,6 +932,7 @@ def add_log(self, log):

self.logs.put(log.time_sent, log)
return log.time_sent

def add_message(self, message):
""" Add message to current game data.
Only a server game can add a message with no timestamp:
Expand All @@ -957,6 +958,21 @@ def add_message(self, message):
time.sleep(1e-6)
message.time_sent = common.timestamp_microseconds()

if (message.thread_idx is not None) and (not self.is_player_game()):
def _is_current_thread(a, b):
if (a.phase != b.phase): return False
if (a.sender == b.sender) and (a.recipient == b.recipient): return True
if (a.sender == b.recipient) and (a.recipient == b.sender): return True
return False

expected_thread_idx = len([msg for msg in self.messages.values() if _is_current_thread(msg, message)])
if message.thread_idx != expected_thread_idx:
print('rejected', self.role, message)
return 0

if not self.is_player_game():
print('accepted', self.role, message)

self.messages.put(message.time_sent, message)
return message.time_sent

Expand Down
6 changes: 4 additions & 2 deletions diplomacy/engine/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,14 @@ class Message(Jsonable):
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']
__slots__ = ['sender', 'recipient', 'time_sent', 'phase', 'message', 'thread_idx']
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 (e.g. 'S1901M' or 'COMPLETED')
strings.MESSAGE: str,
strings.THREAD_IDX: parsing.OptionalValueType(int),
}

def __init__(self, **kwargs):
Expand All @@ -80,10 +81,11 @@ def __init__(self, **kwargs):
self.time_sent = None # type: int
self.phase = None # type: str
self.message = None # type: str
self.thread_idx = None # type: int
super(Message, self).__init__(**kwargs)

def __str__(self):
return '[%d/%s/%s->%s](%s)' % (self.time_sent or 0, self.phase, self.sender, self.recipient, self.message)
return '[%d/%s/%s->%s/tid=%d](%s)' % (self.time_sent or 0, self.phase, self.sender, self.recipient, self.thread_idx if self.thread_idx is not None else -1, self.message)

def __hash__(self):
return hash(self.time_sent)
Expand Down
1 change: 1 addition & 0 deletions diplomacy/utils/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
STATES = 'states'
STATUS = 'status'
SUPPLY_CENTERS = 'supply_centers'
THREAD_IDX = 'thread_idx'
TIME_SENT = 'time_sent'
TIMESTAMP = 'timestamp'
TIMESTAMP_CREATED = 'timestamp_created'
Expand Down