diff src/plugins/plugin_misc_room_game.py @ 828:8f335c03eebb

plugins room_games, radiocol, libervia: small changes like refactorization to ease the maintenance
author souliane <souliane@mailoo.org>
date Fri, 17 Jan 2014 15:02:46 +0100
parents e3f4d80f987d
children f3513c8cc2e6
line wrap: on
line diff
--- a/src/plugins/plugin_misc_room_game.py	Thu Jan 16 11:44:14 2014 +0100
+++ b/src/plugins/plugin_misc_room_game.py	Fri Jan 17 15:02:46 2014 +0100
@@ -108,14 +108,19 @@
         self.join_mode = self.INVITED
         self.ready_mode = self.FORCE  # TODO: asking for confirmation is not implemented
 
+        # this has been added for testing purpose. It is sometimes needed to remove a dependence
+        # while building the synchronization data, for example to replace a call to time.time()
+        # by an arbitrary value. If needed, this attribute would be set to True from the testcase.
+        self.testing = False
+
         host.trigger.add("MUC user joined", self.userJoinedTrigger)
         host.trigger.add("MUC user left", self.userLeftTrigger)
 
     def _createOrInvite(self, room, other_players, profile):
         """
         This is called only when someone explicitly wants to play.
-        The game must not be created if one already exists in the room,
-        and its creation could be postponed until all the expected players
+        The game will not be created if one already exists in the room,
+        also its creation could be postponed until all the expected players
         join the room (in that case it will be created from userJoinedTrigger).
         @param room: instance of wokkel.muc.Room
         @param other_players: list for other players JID userhosts
@@ -128,7 +133,7 @@
             if not self._checkJoinAuth(room_jid_s, user_jid.userhost(), nick):
                 return
             nicks.extend(self._invitePlayers(room, other_players, nick, profile))
-            self._updatePlayers(room_jid_s, nicks, profile)
+            self._updatePlayers(room_jid_s, nicks, True, profile)
         else:
             self._initGame(room_jid_s, nick)
             (auth, waiting, missing) = self._checkWaitAuth(room, other_players)
@@ -137,7 +142,7 @@
             if auth:
                 self.createGame(room_jid_s, nicks, profile)
             else:
-                self._updatePlayers(room_jid_s, nicks, profile)
+                self._updatePlayers(room_jid_s, nicks, False, profile)
 
     def _initGame(self, room_jid_s, referee_nick):
         """Important: do not add the referee to 'players' yet. For a
@@ -191,11 +196,14 @@
             debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s))
         return auth
 
-    def _updatePlayers(self, room_jid_s, nicks, profile):
+    def _updatePlayers(self, room_jid_s, nicks, sync, profile):
         """Update the list of players and signal to the room that some players joined the game.
+        If sync is True, the news players are synchronized with the game data they have missed.
         Remark: self.games[room_jid_s]['players'] should not be modified outside this method.
         @param room_jid_s: room userhost
         @param nicks: list of players nicks in the room (referee included, in first position)
+        @param sync: set to True to send synchronization data to the new players
+        @param profile
         """
         if nicks == []:
             return
@@ -203,12 +211,12 @@
         new_nicks = [nick for nick in nicks if nick not in self.games[room_jid_s]['players']]
         if len(new_nicks) == 0:
             return
-        sync = self._gameExists(room_jid_s, True) and len(self.games[room_jid_s]['players']) > 0
 
         def setStatus(status):
             for nick in new_nicks:
                 self.games[room_jid_s]['status'][nick] = status
 
+        sync = sync and self._gameExists(room_jid_s, True) and len(self.games[room_jid_s]['players']) > 0
         setStatus('desync' if sync else 'init')
         self.games[room_jid_s]['players'].extend(new_nicks)
         self._synchronizeRoom(room_jid_s, [JID(room_jid_s)], profile)
@@ -231,7 +239,7 @@
         elements = [(element, None, None)]
 
         sync_args = []
-        sync_data = self.getSyncData(room_jid_s)
+        sync_data = self._getSyncData(room_jid_s)
         for nick in sync_data:
             user_jid = JID(room_jid_s + '/' + nick)
             if user_jid in recipients:
@@ -248,16 +256,35 @@
         for args, kwargs in sync_args:
             self._sendElements(*args, **kwargs)
 
-    def getSyncData(self, room_jid_s, force_nicks=[]):
-        """This method may (and should probably) be overwritten by a child class.
-        The synchronization data are returned for each player who has the state
-        'desync' or if he's been contained by force_nicks.
+    def _getSyncData(self, room_jid_s, force_nicks=[]):
+        """The synchronization data are returned for each player who
+        has the state 'desync' or if he's been contained by force_nicks.
         @param room_jid_s: room userhost
         @param force_nicks: force the synchronization for this list of the nicks
-        @return: a mapping between player nicks and a list of child elements
-        to be sent by self._synchronizeRoom for the game to be synchronized.
+        @return: a mapping between player nicks and a list of elements to
+        be sent by self._synchronizeRoom for the game to be synchronized.
         """
-        return {}
+        if not self._gameExists(room_jid_s):
+            return {}
+        data = {}
+        status = self.games[room_jid_s]['status']
+        nicks = [nick for nick in status if status[nick] == 'desync']
+        for nick in force_nicks:
+            if nick not in nicks:
+                nicks.append(nick)
+        for nick in nicks:
+            elements = self.getSyncDataForPlayer(room_jid_s, nick)
+            if elements:
+                data[nick] = elements
+        return data
+
+    def getSyncDataForPlayer(self, room_jid_s, nick):
+        """This method may (and should probably) be overwritten by a child class.
+        @param room_jid_s: room userhost
+        @param nick: the nick of the player to be synchronized
+        @return: a list of elements to synchronize this player with the game.
+        """
+        return []
 
     def _invitePlayers(self, room, other_players, nick, profile):
         """Invite players to a room, associated game may exist or not.
@@ -424,7 +451,7 @@
                 self.createGame(room_jid_s, nicks, profile_key=profile)
                 return True
         # let the room know that a new player joined
-        self._updatePlayers(room_jid_s, [user.nick], profile)
+        self._updatePlayers(room_jid_s, [user.nick], True, profile)
         return True
 
     def userLeftTrigger(self, room, user, profile):
@@ -442,6 +469,9 @@
                 self.games[room_jid_s]['players'].remove(user.nick)
             except ValueError:
                 pass
+            if len(self.games[room_jid_s]['players']) == 0:
+                del self.games[room_jid_s]  # finish the game
+                return True
             if self.wait_mode == self.FOR_ALL:
                 # allow this user to join the game again
                 user_jid_s = user.entity.userhost()
@@ -493,11 +523,10 @@
         (create, sync) = self._checkCreateGameAndInit(room_jid_s, profile)
         if not create:
             if sync:
-                debug(_('Synchronize game %s in %s for %s') % (self.name, room_jid_s, ', '.join(nicks)))
-                self._updatePlayers(room_jid_s, nicks, profile)
+                self._updatePlayers(room_jid_s, nicks, True, profile)
             return
         self.games[room_jid_s]['started'] = True
-        self._updatePlayers(room_jid_s, nicks, profile)
+        self._updatePlayers(room_jid_s, nicks, False, profile)
         if self.player_init:
             # specific data to each player (score, private data)
             self.games[room_jid_s].setdefault('players_data', {})