comparison src/plugins/plugin_misc_room_game.py @ 791:23b0c949b86c

plugins room games, XEP-0045: small fixes, improved docstrings
author souliane <souliane@mailoo.org>
date Fri, 10 Jan 2014 18:07:36 +0100
parents 19262fb77230
children 1fe00f0c9a91
comparison
equal deleted inserted replaced
790:19262fb77230 791:23b0c949b86c
145 it is necessary to not modify 'players' outside of _updatePlayers. 145 it is necessary to not modify 'players' outside of _updatePlayers.
146 """ 146 """
147 referee = room_jid_s + '/' + referee_nick 147 referee = room_jid_s + '/' + referee_nick
148 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False} 148 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False}
149 self.games[room_jid_s].update(copy.deepcopy(self.game_init)) 149 self.games[room_jid_s].update(copy.deepcopy(self.game_init))
150 self.invitations.setdefault(room_jid_s, [])
150 151
151 def _gameExists(self, room_jid_s, started=False): 152 def _gameExists(self, room_jid_s, started=False):
152 """Return True if a game has been initialized/started. 153 """Return True if a game has been initialized/started.
153 @param started: if False, the game must be initialized to return True, 154 @param started: if False, the game must be initialized to return True,
154 otherwise it must be initialized and started with createGame. 155 otherwise it must be initialized and started with createGame.
170 if not self._gameExists(room_jid_s): 171 if not self._gameExists(room_jid_s):
171 auth = False 172 auth = False
172 elif self.join_mode == self.ALL or self.isPlayer(room_jid_s, nick): 173 elif self.join_mode == self.ALL or self.isPlayer(room_jid_s, nick):
173 auth = True 174 auth = True
174 elif self.join_mode == self.INVITED: 175 elif self.join_mode == self.INVITED:
176 user_jid_s = JID(user_jid_s).userhost()
175 # considering all the batches of invitations 177 # considering all the batches of invitations
176 for invitations in self.invitations[room_jid_s]: 178 for invitations in self.invitations[room_jid_s]:
177 if user_jid_s is not None: 179 if user_jid_s is not None:
178 if user_jid_s in invitations[1]: 180 if user_jid_s in invitations[1]:
179 auth = True 181 auth = True
188 if not auth and (verbose or _DEBUG): 190 if not auth and (verbose or _DEBUG):
189 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) 191 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s))
190 return auth 192 return auth
191 193
192 def _updatePlayers(self, room_jid_s, nicks, profile): 194 def _updatePlayers(self, room_jid_s, nicks, profile):
193 """Signal to the room that some players joined the game""" 195 """Update the list of players and signal to the room that some players joined the game.
196 Remark: self.games[room_jid_s]['players'] should not be modified outside this method.
197 @param room_jid_s: room userhost
198 @param nicks: list of players nicks in the room (referee included, in first position)
199 """
194 if nicks == []: 200 if nicks == []:
195 return 201 return
196 new_nicks = set(nicks).difference(self.games[room_jid_s]['players']) 202 # 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']]
197 if len(new_nicks) == 0: 204 if len(new_nicks) == 0:
198 return 205 return
199 self.games[room_jid_s]['players'].extend(new_nicks) 206 self.games[room_jid_s]['players'].extend(new_nicks)
200 self._signalPlayers(room_jid_s, [JID(room_jid_s)], profile) 207 self._signalPlayers(room_jid_s, [JID(room_jid_s)], profile)
201 208
202 def _signalPlayers(self, room_jid_s, recipients, profile): 209 def _signalPlayers(self, room_jid_s, recipients, profile):
203 """Let these guys know that we are playing (they may not play themselves).""" 210 """Let these guys know that we are playing (they may not play themselves).
211 @param room_jid_s: room userhost
212 @recipients: list of JIDs, the recipients of the message could be:
213 - room JID
214 - room JID + "/" + user nick
215 """
204 if self._gameExists(room_jid_s, started=True): 216 if self._gameExists(room_jid_s, started=True):
205 element = self._createStartElement(self.games[room_jid_s]['players']) 217 element = self._createStartElement(self.games[room_jid_s]['players'])
206 else: 218 else:
207 element = self._createStartElement(self.games[room_jid_s]['players'], name="players") 219 element = self._createStartElement(self.games[room_jid_s]['players'], name="players")
208 elements = [(element, None, None)] 220 elements = [(element, None, None)]
222 def _invitePlayers(self, room, other_players, nick, profile): 234 def _invitePlayers(self, room, other_players, nick, profile):
223 """Invite players to a room, associated game may exist or not. 235 """Invite players to a room, associated game may exist or not.
224 @param room: wokkel.muc.Room instance 236 @param room: wokkel.muc.Room instance
225 @param other_players: list of JID userhosts to invite 237 @param other_players: list of JID userhosts to invite
226 @param nick: nick of the user who send the invitation 238 @param nick: nick of the user who send the invitation
227 @return: list of the invited players who were already in the room 239 @return: list of room nicks for invited players who are already in the room
228 """ 240 """
229 room_jid = room.occupantJID.userhostJID() 241 room_jid = room.occupantJID.userhostJID()
230 room_jid_s = room.occupantJID.userhost() 242 room_jid_s = room.occupantJID.userhost()
231 if not self._checkInviteAuth(room_jid_s, nick): 243 if not self._checkInviteAuth(room_jid_s, nick):
232 return [] 244 return []
233 self.invitations.setdefault(room_jid_s, [])
234 # TODO: remove invitation waiting for too long, using the time data 245 # TODO: remove invitation waiting for too long, using the time data
235 self.invitations[room_jid_s].append((time(), other_players)) 246 players_jids = [JID(player) for player in other_players]
236 nicks = [nick] 247 self.invitations[room_jid_s].append((time(), [player.userhost() for player in players_jids]))
237 for player_jid in [JID(player) for player in other_players]: 248 nicks = []
249 for player_jid in [player.userhostJID() for player in players_jids]:
238 # TODO: find a way to make it secure 250 # TODO: find a way to make it secure
239 other_nick = self.host.plugins["XEP-0045"].getRoomNickOfUser(room, player_jid, secure=False) 251 other_nick = self.host.plugins["XEP-0045"].getRoomNickOfUser(room, player_jid, secure=False)
240 if other_nick is None: 252 if other_nick is None:
241 self.host.plugins["XEP-0249"].invite(player_jid, room_jid, {"game": self.name}, profile) 253 self.host.plugins["XEP-0249"].invite(player_jid, room_jid, {"game": self.name}, profile)
242 else: 254 else:
252 """ 264 """
253 auth = False 265 auth = False
254 if self.invite_mode == self.FROM_ALL or not self._gameExists(room_jid_s): 266 if self.invite_mode == self.FROM_ALL or not self._gameExists(room_jid_s):
255 auth = True 267 auth = True
256 elif self.invite_mode == self.FROM_NONE: 268 elif self.invite_mode == self.FROM_NONE:
257 auth = not self._gameExists(room_jid_s, started=True) 269 auth = not self._gameExists(room_jid_s, started=True) and self.isReferee(room_jid_s, nick)
258 elif self.invite_mode == self.FROM_REFEREE: 270 elif self.invite_mode == self.FROM_REFEREE:
259 auth = self.isReferee(room_jid_s, nick) 271 auth = self.isReferee(room_jid_s, nick)
260 elif self.invite_mode == self.FROM_PLAYERS: 272 elif self.invite_mode == self.FROM_PLAYERS:
261 auth = self.isPlayer(room_jid_s, nick) 273 auth = self.isPlayer(room_jid_s, nick)
262 if not auth and (verbose or _DEBUG): 274 if not auth and (verbose or _DEBUG):
286 return nick in self.games[room_jid_s]['players'] or self.isReferee(room_jid_s, nick) 298 return nick in self.games[room_jid_s]['players'] or self.isReferee(room_jid_s, nick)
287 299
288 def _checkWaitAuth(self, room, other_players, verbose=False): 300 def _checkWaitAuth(self, room, other_players, verbose=False):
289 """Check if we must wait for other players before starting the game. 301 """Check if we must wait for other players before starting the game.
290 @param room: wokkel.muc.Room instance 302 @param room: wokkel.muc.Room instance
291 @param other_players: list of the players without the referee 303 @param other_players: list of players JID userhosts without the referee
292 @param verbose: display debug message 304 @param verbose: display debug message
293 @return: (x, y, z) with: 305 @return: (x, y, z) with:
294 x: False if we must wait, True otherwise 306 x: False if we must wait, True otherwise
295 y: the nicks of the players that have been checked and confirmed 307 y: the nicks of the players that have been checked and confirmed
296 z: the players that have not been checked or that are missing 308 z: the players that have not been checked or that are missing
297 """ 309 """
298 if self.wait_mode == self.FOR_NONE or other_players == []: 310 if self.wait_mode == self.FOR_NONE or other_players == []:
299 result = (True, [], other_players) 311 result = (True, [], other_players)
300 elif len(room.roster) < len(other_players) + 1: 312 elif len(room.roster) < len(other_players):
313 # do not check the players until we may actually have them all
301 result = (False, [], other_players) 314 result = (False, [], other_players)
302 else: 315 else:
303 # TODO: find a way to make it secure 316 # TODO: find a way to make it secure
304 (nicks, missing) = self.host.plugins["XEP-0045"].getRoomNicksOfUsers(room, other_players, secure=False) 317 (nicks, missing) = self.host.plugins["XEP-0045"].getRoomNicksOfUsers(room, other_players, secure=False)
305 result = (len(nicks) == len(other_players), nicks, missing) 318 result = (len(nicks) == len(other_players), nicks, missing)
328 error(_("Unknown profile")) 341 error(_("Unknown profile"))
329 return 342 return
330 343
331 def roomJoined(room): 344 def roomJoined(room):
332 """@param room: instance of wokkel.muc.Room""" 345 """@param room: instance of wokkel.muc.Room"""
333 self._createOrInvite(room, other_players, profile) 346 self._createOrInvite(room, [JID(player).userhost() for player in other_players], profile)
334 347
335 def afterClientInit(room_jid_s): 348 def afterClientInit(room_jid_s):
336 """Create/join the given room, or a unique generated one if no room is specified. 349 """Create/join the given room, or a unique generated one if no room is specified.
337 @param room_jids: userhost of the room to join 350 @param room_jids: userhost of the room to join
338 """ 351 """
363 """ 376 """
364 room_jid_s = room.occupantJID.userhost() 377 room_jid_s = room.occupantJID.userhost()
365 profile_nick = room.occupantJID.resource 378 profile_nick = room.occupantJID.resource
366 if not self.isReferee(room_jid_s, profile_nick): 379 if not self.isReferee(room_jid_s, profile_nick):
367 return True # profile is not the referee 380 return True # profile is not the referee
368 if not self._checkJoinAuth(room_jid_s, nick=user.nick): 381 if not self._checkJoinAuth(room_jid_s, user.entity.userhost() if user.entity else None, user.nick):
369 # user not allowed but let him know that we are playing :p 382 # user not allowed but let him know that we are playing :p
370 self._signalPlayers(room_jid_s, [JID(room_jid_s + '/' + user.nick)], profile) 383 self._signalPlayers(room_jid_s, [JID(room_jid_s + '/' + user.nick)], profile)
371 return True 384 return True
372 if self.wait_mode == self.FOR_ALL: 385 if self.wait_mode == self.FOR_ALL:
373 # considering the last batch of invitations 386 # considering the last batch of invitations
401 self.games[room_jid_s]['players'].remove(user.nick) 414 self.games[room_jid_s]['players'].remove(user.nick)
402 except ValueError: 415 except ValueError:
403 pass 416 pass
404 if self.wait_mode == self.FOR_ALL: 417 if self.wait_mode == self.FOR_ALL:
405 # allow this user to join the game again 418 # allow this user to join the game again
406 user_jid = user.entity.userhost() 419 user_jid_s = user.entity.userhost()
407 if len(self.invitations[room_jid_s]) == 0: 420 if len(self.invitations[room_jid_s]) == 0:
408 self.invitations[room_jid_s].append((time(), [user_jid])) 421 self.invitations[room_jid_s].append((time(), [user_jid_s]))
409 else: 422 else:
410 batch = 0 # add to the first batch of invitations 423 batch = 0 # add to the first batch of invitations
411 if user_jid not in self.invitations[room_jid_s][batch][1]: 424 if user_jid_s not in self.invitations[room_jid_s][batch][1]:
412 self.invitations[room_jid_s][batch][1].append(user_jid) 425 self.invitations[room_jid_s][batch][1].append(user_jid_s)
413 return True 426 return True
414 427
415 def _checkCreateGameAndInit(self, room_jid_s, profile): 428 def _checkCreateGameAndInit(self, room_jid_s, profile):
416 """Check if that profile can create the game. If the game can be created 429 """Check if that profile can create the game. If the game can be created
417 but is not initialized yet, this method will also do the initialization. 430 but is not initialized yet, this method will also do the initialization.
440 def createGame(self, room_jid_s, nicks=[], profile_key='@NONE@'): 453 def createGame(self, room_jid_s, nicks=[], profile_key='@NONE@'):
441 """Create a new game - this can be called directly from a frontend 454 """Create a new game - this can be called directly from a frontend
442 and skips all the checks and invitation system, but the game must 455 and skips all the checks and invitation system, but the game must
443 not exist and all the players must be in the room already. 456 not exist and all the players must be in the room already.
444 @param room_jid: JID userhost of the room 457 @param room_jid: JID userhost of the room
445 @param nicks: list of players nicks in the room 458 @param nicks: list of players nicks in the room (referee included, in first position)
446 @param profile_key: %(doc_profile_key)s""" 459 @param profile_key: %(doc_profile_key)s"""
447 debug(_("Creating %s game in room %s") % (self.name, room_jid_s)) 460 debug(_("Creating %s game in room %s") % (self.name, room_jid_s))
448 profile = self.host.memory.getProfileName(profile_key) 461 profile = self.host.memory.getProfileName(profile_key)
449 if not profile: 462 if not profile:
450 error(_("profile %s is unknown") % profile_key) 463 error(_("profile %s is unknown") % profile_key)