Mercurial > libervia-backend
comparison 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 |
comparison
equal
deleted
inserted
replaced
827:215a2cb15e2d | 828:8f335c03eebb |
---|---|
106 self.invite_mode = self.FROM_PLAYERS if self.player_init == {} else self.FROM_NONE | 106 self.invite_mode = self.FROM_PLAYERS if self.player_init == {} else self.FROM_NONE |
107 self.wait_mode = self.FOR_NONE if self.player_init == {} else self.FOR_ALL | 107 self.wait_mode = self.FOR_NONE if self.player_init == {} else self.FOR_ALL |
108 self.join_mode = self.INVITED | 108 self.join_mode = self.INVITED |
109 self.ready_mode = self.FORCE # TODO: asking for confirmation is not implemented | 109 self.ready_mode = self.FORCE # TODO: asking for confirmation is not implemented |
110 | 110 |
111 # this has been added for testing purpose. It is sometimes needed to remove a dependence | |
112 # while building the synchronization data, for example to replace a call to time.time() | |
113 # by an arbitrary value. If needed, this attribute would be set to True from the testcase. | |
114 self.testing = False | |
115 | |
111 host.trigger.add("MUC user joined", self.userJoinedTrigger) | 116 host.trigger.add("MUC user joined", self.userJoinedTrigger) |
112 host.trigger.add("MUC user left", self.userLeftTrigger) | 117 host.trigger.add("MUC user left", self.userLeftTrigger) |
113 | 118 |
114 def _createOrInvite(self, room, other_players, profile): | 119 def _createOrInvite(self, room, other_players, profile): |
115 """ | 120 """ |
116 This is called only when someone explicitly wants to play. | 121 This is called only when someone explicitly wants to play. |
117 The game must not be created if one already exists in the room, | 122 The game will not be created if one already exists in the room, |
118 and its creation could be postponed until all the expected players | 123 also its creation could be postponed until all the expected players |
119 join the room (in that case it will be created from userJoinedTrigger). | 124 join the room (in that case it will be created from userJoinedTrigger). |
120 @param room: instance of wokkel.muc.Room | 125 @param room: instance of wokkel.muc.Room |
121 @param other_players: list for other players JID userhosts | 126 @param other_players: list for other players JID userhosts |
122 """ | 127 """ |
123 user_jid = self.host.getJidNStream(profile)[0] | 128 user_jid = self.host.getJidNStream(profile)[0] |
126 nicks = [nick] | 131 nicks = [nick] |
127 if self._gameExists(room_jid_s): | 132 if self._gameExists(room_jid_s): |
128 if not self._checkJoinAuth(room_jid_s, user_jid.userhost(), nick): | 133 if not self._checkJoinAuth(room_jid_s, user_jid.userhost(), nick): |
129 return | 134 return |
130 nicks.extend(self._invitePlayers(room, other_players, nick, profile)) | 135 nicks.extend(self._invitePlayers(room, other_players, nick, profile)) |
131 self._updatePlayers(room_jid_s, nicks, profile) | 136 self._updatePlayers(room_jid_s, nicks, True, profile) |
132 else: | 137 else: |
133 self._initGame(room_jid_s, nick) | 138 self._initGame(room_jid_s, nick) |
134 (auth, waiting, missing) = self._checkWaitAuth(room, other_players) | 139 (auth, waiting, missing) = self._checkWaitAuth(room, other_players) |
135 nicks.extend(waiting) | 140 nicks.extend(waiting) |
136 nicks.extend(self._invitePlayers(room, missing, nick, profile)) | 141 nicks.extend(self._invitePlayers(room, missing, nick, profile)) |
137 if auth: | 142 if auth: |
138 self.createGame(room_jid_s, nicks, profile) | 143 self.createGame(room_jid_s, nicks, profile) |
139 else: | 144 else: |
140 self._updatePlayers(room_jid_s, nicks, profile) | 145 self._updatePlayers(room_jid_s, nicks, False, profile) |
141 | 146 |
142 def _initGame(self, room_jid_s, referee_nick): | 147 def _initGame(self, room_jid_s, referee_nick): |
143 """Important: do not add the referee to 'players' yet. For a | 148 """Important: do not add the referee to 'players' yet. For a |
144 <players /> message to be emitted whenever a new player is joining, | 149 <players /> message to be emitted whenever a new player is joining, |
145 it is necessary to not modify 'players' outside of _updatePlayers. | 150 it is necessary to not modify 'players' outside of _updatePlayers. |
189 | 194 |
190 if not auth and (verbose or _DEBUG): | 195 if not auth and (verbose or _DEBUG): |
191 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) | 196 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) |
192 return auth | 197 return auth |
193 | 198 |
194 def _updatePlayers(self, room_jid_s, nicks, profile): | 199 def _updatePlayers(self, room_jid_s, nicks, sync, profile): |
195 """Update the list of players and signal to the room that some players joined the game. | 200 """Update the list of players and signal to the room that some players joined the game. |
201 If sync is True, the news players are synchronized with the game data they have missed. | |
196 Remark: self.games[room_jid_s]['players'] should not be modified outside this method. | 202 Remark: self.games[room_jid_s]['players'] should not be modified outside this method. |
197 @param room_jid_s: room userhost | 203 @param room_jid_s: room userhost |
198 @param nicks: list of players nicks in the room (referee included, in first position) | 204 @param nicks: list of players nicks in the room (referee included, in first position) |
205 @param sync: set to True to send synchronization data to the new players | |
206 @param profile | |
199 """ | 207 """ |
200 if nicks == []: | 208 if nicks == []: |
201 return | 209 return |
202 # this is better than set(nicks).difference(...) as it keeps the order | 210 # this is better than set(nicks).difference(...) as it keeps the order |
203 new_nicks = [nick for nick in nicks if nick not in self.games[room_jid_s]['players']] | 211 new_nicks = [nick for nick in nicks if nick not in self.games[room_jid_s]['players']] |
204 if len(new_nicks) == 0: | 212 if len(new_nicks) == 0: |
205 return | 213 return |
206 sync = self._gameExists(room_jid_s, True) and len(self.games[room_jid_s]['players']) > 0 | |
207 | 214 |
208 def setStatus(status): | 215 def setStatus(status): |
209 for nick in new_nicks: | 216 for nick in new_nicks: |
210 self.games[room_jid_s]['status'][nick] = status | 217 self.games[room_jid_s]['status'][nick] = status |
211 | 218 |
219 sync = sync and self._gameExists(room_jid_s, True) and len(self.games[room_jid_s]['players']) > 0 | |
212 setStatus('desync' if sync else 'init') | 220 setStatus('desync' if sync else 'init') |
213 self.games[room_jid_s]['players'].extend(new_nicks) | 221 self.games[room_jid_s]['players'].extend(new_nicks) |
214 self._synchronizeRoom(room_jid_s, [JID(room_jid_s)], profile) | 222 self._synchronizeRoom(room_jid_s, [JID(room_jid_s)], profile) |
215 if sync: | 223 if sync: |
216 setStatus('init') | 224 setStatus('init') |
229 else: | 237 else: |
230 element = self._createStartElement(self.games[room_jid_s]['players'], name="players") | 238 element = self._createStartElement(self.games[room_jid_s]['players'], name="players") |
231 elements = [(element, None, None)] | 239 elements = [(element, None, None)] |
232 | 240 |
233 sync_args = [] | 241 sync_args = [] |
234 sync_data = self.getSyncData(room_jid_s) | 242 sync_data = self._getSyncData(room_jid_s) |
235 for nick in sync_data: | 243 for nick in sync_data: |
236 user_jid = JID(room_jid_s + '/' + nick) | 244 user_jid = JID(room_jid_s + '/' + nick) |
237 if user_jid in recipients: | 245 if user_jid in recipients: |
238 user_elements = copy.deepcopy(elements) | 246 user_elements = copy.deepcopy(elements) |
239 for child in sync_data[nick]: | 247 for child in sync_data[nick]: |
246 for recipient in recipients: | 254 for recipient in recipients: |
247 self._sendElements(recipient, elements, profile=profile) | 255 self._sendElements(recipient, elements, profile=profile) |
248 for args, kwargs in sync_args: | 256 for args, kwargs in sync_args: |
249 self._sendElements(*args, **kwargs) | 257 self._sendElements(*args, **kwargs) |
250 | 258 |
251 def getSyncData(self, room_jid_s, force_nicks=[]): | 259 def _getSyncData(self, room_jid_s, force_nicks=[]): |
260 """The synchronization data are returned for each player who | |
261 has the state 'desync' or if he's been contained by force_nicks. | |
262 @param room_jid_s: room userhost | |
263 @param force_nicks: force the synchronization for this list of the nicks | |
264 @return: a mapping between player nicks and a list of elements to | |
265 be sent by self._synchronizeRoom for the game to be synchronized. | |
266 """ | |
267 if not self._gameExists(room_jid_s): | |
268 return {} | |
269 data = {} | |
270 status = self.games[room_jid_s]['status'] | |
271 nicks = [nick for nick in status if status[nick] == 'desync'] | |
272 for nick in force_nicks: | |
273 if nick not in nicks: | |
274 nicks.append(nick) | |
275 for nick in nicks: | |
276 elements = self.getSyncDataForPlayer(room_jid_s, nick) | |
277 if elements: | |
278 data[nick] = elements | |
279 return data | |
280 | |
281 def getSyncDataForPlayer(self, room_jid_s, nick): | |
252 """This method may (and should probably) be overwritten by a child class. | 282 """This method may (and should probably) be overwritten by a child class. |
253 The synchronization data are returned for each player who has the state | 283 @param room_jid_s: room userhost |
254 'desync' or if he's been contained by force_nicks. | 284 @param nick: the nick of the player to be synchronized |
255 @param room_jid_s: room userhost | 285 @return: a list of elements to synchronize this player with the game. |
256 @param force_nicks: force the synchronization for this list of the nicks | 286 """ |
257 @return: a mapping between player nicks and a list of child elements | 287 return [] |
258 to be sent by self._synchronizeRoom for the game to be synchronized. | |
259 """ | |
260 return {} | |
261 | 288 |
262 def _invitePlayers(self, room, other_players, nick, profile): | 289 def _invitePlayers(self, room, other_players, nick, profile): |
263 """Invite players to a room, associated game may exist or not. | 290 """Invite players to a room, associated game may exist or not. |
264 @param room: wokkel.muc.Room instance | 291 @param room: wokkel.muc.Room instance |
265 @param other_players: list of JID userhosts to invite | 292 @param other_players: list of JID userhosts to invite |
422 del self.invitations[room_jid_s][batch] | 449 del self.invitations[room_jid_s][batch] |
423 nicks.insert(0, profile_nick) # add the referee | 450 nicks.insert(0, profile_nick) # add the referee |
424 self.createGame(room_jid_s, nicks, profile_key=profile) | 451 self.createGame(room_jid_s, nicks, profile_key=profile) |
425 return True | 452 return True |
426 # let the room know that a new player joined | 453 # let the room know that a new player joined |
427 self._updatePlayers(room_jid_s, [user.nick], profile) | 454 self._updatePlayers(room_jid_s, [user.nick], True, profile) |
428 return True | 455 return True |
429 | 456 |
430 def userLeftTrigger(self, room, user, profile): | 457 def userLeftTrigger(self, room, user, profile): |
431 """This trigger is used to update or stop the game when a user leaves. | 458 """This trigger is used to update or stop the game when a user leaves. |
432 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} | 459 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} |
440 if self.isPlayer(room_jid_s, user.nick): | 467 if self.isPlayer(room_jid_s, user.nick): |
441 try: | 468 try: |
442 self.games[room_jid_s]['players'].remove(user.nick) | 469 self.games[room_jid_s]['players'].remove(user.nick) |
443 except ValueError: | 470 except ValueError: |
444 pass | 471 pass |
472 if len(self.games[room_jid_s]['players']) == 0: | |
473 del self.games[room_jid_s] # finish the game | |
474 return True | |
445 if self.wait_mode == self.FOR_ALL: | 475 if self.wait_mode == self.FOR_ALL: |
446 # allow this user to join the game again | 476 # allow this user to join the game again |
447 user_jid_s = user.entity.userhost() | 477 user_jid_s = user.entity.userhost() |
448 if len(self.invitations[room_jid_s]) == 0: | 478 if len(self.invitations[room_jid_s]) == 0: |
449 self.invitations[room_jid_s].append((time(), [user_jid_s])) | 479 self.invitations[room_jid_s].append((time(), [user_jid_s])) |
491 error(_("profile %s is unknown") % profile_key) | 521 error(_("profile %s is unknown") % profile_key) |
492 return | 522 return |
493 (create, sync) = self._checkCreateGameAndInit(room_jid_s, profile) | 523 (create, sync) = self._checkCreateGameAndInit(room_jid_s, profile) |
494 if not create: | 524 if not create: |
495 if sync: | 525 if sync: |
496 debug(_('Synchronize game %s in %s for %s') % (self.name, room_jid_s, ', '.join(nicks))) | 526 self._updatePlayers(room_jid_s, nicks, True, profile) |
497 self._updatePlayers(room_jid_s, nicks, profile) | |
498 return | 527 return |
499 self.games[room_jid_s]['started'] = True | 528 self.games[room_jid_s]['started'] = True |
500 self._updatePlayers(room_jid_s, nicks, profile) | 529 self._updatePlayers(room_jid_s, nicks, False, profile) |
501 if self.player_init: | 530 if self.player_init: |
502 # specific data to each player (score, private data) | 531 # specific data to each player (score, private data) |
503 self.games[room_jid_s].setdefault('players_data', {}) | 532 self.games[room_jid_s].setdefault('players_data', {}) |
504 for nick in nicks: | 533 for nick in nicks: |
505 # The dict must be COPIED otherwise it is shared between all users | 534 # The dict must be COPIED otherwise it is shared between all users |