Mercurial > libervia-backend
comparison src/plugins/plugin_misc_room_game.py @ 790:19262fb77230
plugin room game: improved docstrings, added '_' as prefix for internal methods names
author | souliane <souliane@mailoo.org> |
---|---|
date | Thu, 09 Jan 2014 10:28:25 +0100 |
parents | bfabeedbf32e |
children | 23b0c949b86c |
comparison
equal
deleted
inserted
replaced
789:0cb423500fbb | 790:19262fb77230 |
---|---|
44 "description": _("""Base class for MUC games""") | 44 "description": _("""Base class for MUC games""") |
45 } | 45 } |
46 | 46 |
47 | 47 |
48 class RoomGame(object): | 48 class RoomGame(object): |
49 """This class is used to help launching a MUC game.""" | 49 """This class is used to help launching a MUC game. |
50 | |
51 Bridge methods callbacks: prepareRoom, playerReady, createGame | |
52 Triggered methods: userJoinedTrigger, userLeftTrigger | |
53 Also called from subclasses: newRound | |
54 | |
55 For examples of messages sequences, please look in sub-classes. | |
56 """ | |
50 | 57 |
51 # Values for self.invite_mode (who can invite after the game creation) | 58 # Values for self.invite_mode (who can invite after the game creation) |
52 FROM_ALL, FROM_NONE, FROM_REFEREE, FROM_PLAYERS = xrange(0, 4) | 59 FROM_ALL, FROM_NONE, FROM_REFEREE, FROM_PLAYERS = xrange(0, 4) |
53 # Values for self.wait_mode (for who we should wait before creating the game) | 60 # Values for self.wait_mode (for who we should wait before creating the game) |
54 FOR_ALL, FOR_NONE = xrange(0, 2) | 61 FOR_ALL, FOR_NONE = xrange(0, 2) |
59 | 66 |
60 MESSAGE = '/message' | 67 MESSAGE = '/message' |
61 REQUEST = '%s/%s[@xmlns="%s"]' | 68 REQUEST = '%s/%s[@xmlns="%s"]' |
62 | 69 |
63 def __init__(self, host): | 70 def __init__(self, host): |
71 """For other plugin to dynamically inherit this class, it is necessary to not use __init__ but _init_. | |
72 The subclass itself must be initialized this way: | |
73 | |
74 class MyGame(object): | |
75 | |
76 def inheritFromRoomGame(self, host): | |
77 global RoomGame | |
78 RoomGame = host.plugins["ROOM-GAME"].__class__ | |
79 self.__class__ = type(self.__class__.__name__, (self.__class__, RoomGame, object), {}) | |
80 | |
81 def __init__(self, host): | |
82 self.inheritFromRoomGame(host) | |
83 RoomGame._init_(self, host, ...) | |
84 | |
85 """ | |
64 self.host = host | 86 self.host = host |
65 | 87 |
66 def _init_(self, host, plugin_info, ns_tag, game_init={}, player_init={}): | 88 def _init_(self, host, plugin_info, ns_tag, game_init={}, player_init={}): |
67 """ | 89 """ |
68 @param host | 90 @param host |
69 @param plugin_info: PLUGIN_INFO map of the game plugin | 91 @param plugin_info: PLUGIN_INFO map of the game plugin |
70 @ns_tag: couple (nameservice, tag) to construct the messages | 92 @param ns_tag: couple (nameservice, tag) to construct the messages |
71 @param game_init: dictionary for general game initialization | 93 @param game_init: dictionary for general game initialization |
72 @param player_init: dictionary for player initialization, applicable to each player | 94 @param player_init: dictionary for player initialization, applicable to each player |
73 """ | 95 """ |
74 self.host = host | 96 self.host = host |
75 self.name = plugin_info["import_name"] | 97 self.name = plugin_info["import_name"] |
87 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 |
88 | 110 |
89 host.trigger.add("MUC user joined", self.userJoinedTrigger) | 111 host.trigger.add("MUC user joined", self.userJoinedTrigger) |
90 host.trigger.add("MUC user left", self.userLeftTrigger) | 112 host.trigger.add("MUC user left", self.userLeftTrigger) |
91 | 113 |
92 def createOrInvite(self, room, other_players, profile): | 114 def _createOrInvite(self, room, other_players, profile): |
93 """ | 115 """ |
94 This is called only when someone explicitly wants to play. | 116 This is called only when someone explicitly wants to play. |
95 The game must not be created if one already exists in the room, | 117 The game must not be created if one already exists in the room, |
96 or its creation could be postponed until all the expected players | 118 and its creation could be postponed until all the expected players |
97 join the room (in that case it will be created from userJoinedTrigger). | 119 join the room (in that case it will be created from userJoinedTrigger). |
98 @param room: instance of wokkel.muc.Room | 120 @param room: instance of wokkel.muc.Room |
99 @param other_players: list for other players JID userhosts | 121 @param other_players: list for other players JID userhosts |
100 """ | 122 """ |
101 user_jid = self.host.getJidNStream(profile)[0] | 123 user_jid = self.host.getJidNStream(profile)[0] |
102 room_jid_s = room.occupantJID.userhost() | 124 room_jid_s = room.occupantJID.userhost() |
103 nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid_s, profile) | 125 nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid_s, profile) |
104 nicks = [nick] | 126 nicks = [nick] |
105 if self.gameExists(room_jid_s): | 127 if self._gameExists(room_jid_s): |
106 if not self.checkJoinAuth(room_jid_s, user_jid.userhost(), nick): | 128 if not self._checkJoinAuth(room_jid_s, user_jid.userhost(), nick): |
107 return | 129 return |
108 nicks.extend(self.invitePlayers(room, other_players, nick, profile)) | 130 nicks.extend(self._invitePlayers(room, other_players, nick, profile)) |
109 self.updatePlayers(room_jid_s, nicks, profile) | 131 self._updatePlayers(room_jid_s, nicks, profile) |
110 else: | 132 else: |
111 self.initGame(room_jid_s, nick) | 133 self._initGame(room_jid_s, nick) |
112 (auth, waiting, missing) = self.checkWaitAuth(room, other_players) | 134 (auth, waiting, missing) = self._checkWaitAuth(room, other_players) |
113 nicks.extend(waiting) | 135 nicks.extend(waiting) |
114 nicks.extend(self.invitePlayers(room, missing, nick, profile)) | 136 nicks.extend(self._invitePlayers(room, missing, nick, profile)) |
115 if auth: | 137 if auth: |
116 self.createGame(room_jid_s, nicks, profile) | 138 self.createGame(room_jid_s, nicks, profile) |
117 else: | 139 else: |
118 self.updatePlayers(room_jid_s, nicks, profile) | 140 self._updatePlayers(room_jid_s, nicks, profile) |
119 | 141 |
120 def initGame(self, room_jid_s, referee_nick): | 142 def _initGame(self, room_jid_s, referee_nick): |
121 """Important: do not add the referee to 'players' yet. For a | 143 """Important: do not add the referee to 'players' yet. For a |
122 <players /> message to be emitted whenever a new player is joining, | 144 <players /> message to be emitted whenever a new player is joining, |
123 it is necessary to not modify 'players' outside of updatePlayers. | 145 it is necessary to not modify 'players' outside of _updatePlayers. |
124 """ | 146 """ |
125 referee = room_jid_s + '/' + referee_nick | 147 referee = room_jid_s + '/' + referee_nick |
126 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False} | 148 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False} |
127 self.games[room_jid_s].update(copy.deepcopy(self.game_init)) | 149 self.games[room_jid_s].update(copy.deepcopy(self.game_init)) |
128 | 150 |
129 def gameExists(self, room_jid_s, started=False): | 151 def _gameExists(self, room_jid_s, started=False): |
130 """Return True if a game has been initialized/started. | 152 """Return True if a game has been initialized/started. |
131 @param started: if False, the game must be initialized only, | 153 @param started: if False, the game must be initialized to return True, |
132 otherwise it must be initialized and started with createGame. | 154 otherwise it must be initialized and started with createGame. |
133 @return: True if a game is initialized/started in that room""" | 155 @return: True if a game is initialized/started in that room""" |
134 return room_jid_s in self.games and (not started or self.games[room_jid_s]['started']) | 156 return room_jid_s in self.games and (not started or self.games[room_jid_s]['started']) |
135 | 157 |
136 def checkJoinAuth(self, room_jid_s, user_jid_s=None, nick="", verbose=False): | 158 def _checkJoinAuth(self, room_jid_s, user_jid_s=None, nick="", verbose=False): |
137 """Checks if this profile is allowed to join the game. | 159 """Checks if this profile is allowed to join the game. |
138 The parameter nick is used to check if the user is already | 160 The parameter nick is used to check if the user is already |
139 a player in that game. When this method is called from | 161 a player in that game. When this method is called from |
140 userJoinedTrigger, nick is also used to check the user | 162 userJoinedTrigger, nick is also used to check the user |
141 identity instead of user_jid_s (see TODO remark below). | 163 identity instead of user_jid_s (see TODO comment below). |
142 @param room_jid_s: the room hosting the game | 164 @param room_jid_s: the room hosting the game |
143 @param user_jid_s: JID userhost of the user | 165 @param user_jid_s: JID userhost of the user |
144 @param nick: nick of the user | 166 @param nick: nick of the user |
167 @return: True if this profile can join the game | |
145 """ | 168 """ |
146 auth = False | 169 auth = False |
147 if not self.gameExists(room_jid_s): | 170 if not self._gameExists(room_jid_s): |
148 auth = False | 171 auth = False |
149 elif self.join_mode == self.ALL or self.isPlayer(room_jid_s, nick): | 172 elif self.join_mode == self.ALL or self.isPlayer(room_jid_s, nick): |
150 auth = True | 173 auth = True |
151 elif self.join_mode == self.INVITED: | 174 elif self.join_mode == self.INVITED: |
152 # considering all the batches of invitations | 175 # considering all the batches of invitations |
164 | 187 |
165 if not auth and (verbose or _DEBUG): | 188 if not auth and (verbose or _DEBUG): |
166 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) | 189 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) |
167 return auth | 190 return auth |
168 | 191 |
169 def updatePlayers(self, room_jid_s, nicks, profile): | 192 def _updatePlayers(self, room_jid_s, nicks, profile): |
170 """Signal to the room that some players joined the game""" | 193 """Signal to the room that some players joined the game""" |
171 if nicks == []: | 194 if nicks == []: |
172 return | 195 return |
173 new_nicks = set(nicks).difference(self.games[room_jid_s]['players']) | 196 new_nicks = set(nicks).difference(self.games[room_jid_s]['players']) |
174 if len(new_nicks) == 0: | 197 if len(new_nicks) == 0: |
175 return | 198 return |
176 self.games[room_jid_s]['players'].extend(new_nicks) | 199 self.games[room_jid_s]['players'].extend(new_nicks) |
177 self.signalPlayers(room_jid_s, [JID(room_jid_s)], profile) | 200 self._signalPlayers(room_jid_s, [JID(room_jid_s)], profile) |
178 | 201 |
179 def signalPlayers(self, room_jid_s, recipients, profile): | 202 def _signalPlayers(self, room_jid_s, recipients, profile): |
180 """Let these guys know that we are playing (they may not play themselves).""" | 203 """Let these guys know that we are playing (they may not play themselves).""" |
181 if self.gameExists(room_jid_s, started=True): | 204 if self._gameExists(room_jid_s, started=True): |
182 element = self.createStartElement(self.games[room_jid_s]['players']) | 205 element = self._createStartElement(self.games[room_jid_s]['players']) |
183 else: | 206 else: |
184 element = self.createStartElement(self.games[room_jid_s]['players'], name="players") | 207 element = self._createStartElement(self.games[room_jid_s]['players'], name="players") |
185 elements = [(element, None, None)] | 208 elements = [(element, None, None)] |
186 for child in self.getSyncData(room_jid_s): | 209 for child in self.getSyncData(room_jid_s): |
187 # TODO: sync data may be different and private to each player, | 210 # TODO: sync data may be different and private to each player, |
188 # in that case send a separate message to the new players | 211 # in that case send a separate message to the new players |
189 elements.append((child, None, None)) | 212 elements.append((child, None, None)) |
190 for recipient in recipients: | 213 for recipient in recipients: |
191 self.sendElements(recipient, elements, profile=profile) | 214 self._sendElements(recipient, elements, profile=profile) |
192 | 215 |
193 def getSyncData(self, room_jid_s): | 216 def getSyncData(self, room_jid_s): |
194 """This method may be overwritten by any child class. | 217 """This method may be overwritten by any child class. |
195 @return: a list of child elements to be added for the game to be synchronized. | 218 @return: a list of child elements to be added for the game to be synchronized. |
196 """ | 219 """ |
197 return [] | 220 return [] |
198 | 221 |
199 def invitePlayers(self, room, other_players, nick, profile): | 222 def _invitePlayers(self, room, other_players, nick, profile): |
200 """Invite players to a room, associated game may exist or not. | 223 """Invite players to a room, associated game may exist or not. |
201 @param room: wokkel.muc.Room instance | 224 @param room: wokkel.muc.Room instance |
202 @param other_players: list of JID userhosts to invite | 225 @param other_players: list of JID userhosts to invite |
203 @param nick: nick of the user who send the invitation | 226 @param nick: nick of the user who send the invitation |
204 @return: list of the invited players who were already in the room | 227 @return: list of the invited players who were already in the room |
205 """ | 228 """ |
206 room_jid = room.occupantJID.userhostJID() | 229 room_jid = room.occupantJID.userhostJID() |
207 room_jid_s = room.occupantJID.userhost() | 230 room_jid_s = room.occupantJID.userhost() |
208 if not self.checkInviteAuth(room_jid_s, nick): | 231 if not self._checkInviteAuth(room_jid_s, nick): |
209 return [] | 232 return [] |
210 self.invitations.setdefault(room_jid_s, []) | 233 self.invitations.setdefault(room_jid_s, []) |
211 # TODO: remove invitation waiting for too long, using the time data | 234 # TODO: remove invitation waiting for too long, using the time data |
212 self.invitations[room_jid_s].append((time(), other_players)) | 235 self.invitations[room_jid_s].append((time(), other_players)) |
213 nicks = [nick] | 236 nicks = [nick] |
218 self.host.plugins["XEP-0249"].invite(player_jid, room_jid, {"game": self.name}, profile) | 241 self.host.plugins["XEP-0249"].invite(player_jid, room_jid, {"game": self.name}, profile) |
219 else: | 242 else: |
220 nicks.append(other_nick) | 243 nicks.append(other_nick) |
221 return nicks | 244 return nicks |
222 | 245 |
223 def checkInviteAuth(self, room_jid_s, nick, verbose=False): | 246 def _checkInviteAuth(self, room_jid_s, nick, verbose=False): |
224 """Checks if this profile is allowed to invite players""" | 247 """Checks if this user is allowed to invite players |
248 @param room_jid_s: room userhost | |
249 @param nick: user nick in the room | |
250 @param verbose: display debug message | |
251 @return: True if the user is allowed to invite other players | |
252 """ | |
225 auth = False | 253 auth = False |
226 if self.invite_mode == self.FROM_ALL or not self.gameExists(room_jid_s): | 254 if self.invite_mode == self.FROM_ALL or not self._gameExists(room_jid_s): |
227 auth = True | 255 auth = True |
228 elif self.invite_mode == self.FROM_NONE: | 256 elif self.invite_mode == self.FROM_NONE: |
229 auth = not self.gameExists(room_jid_s, started=True) | 257 auth = not self._gameExists(room_jid_s, started=True) |
230 elif self.invite_mode == self.FROM_REFEREE: | 258 elif self.invite_mode == self.FROM_REFEREE: |
231 auth = self.isReferee(room_jid_s, nick) | 259 auth = self.isReferee(room_jid_s, nick) |
232 elif self.invite_mode == self.FROM_PLAYERS: | 260 elif self.invite_mode == self.FROM_PLAYERS: |
233 auth = self.isPlayer(room_jid_s, nick) | 261 auth = self.isPlayer(room_jid_s, nick) |
234 if not auth and (verbose or _DEBUG): | 262 if not auth and (verbose or _DEBUG): |
235 debug(_("%s not allowed to invite for the game %s in %s") % (nick, self.name, room_jid_s)) | 263 debug(_("%s not allowed to invite for the game %s in %s") % (nick, self.name, room_jid_s)) |
236 return auth | 264 return auth |
237 | 265 |
238 def isReferee(self, room_jid_s, nick): | 266 def isReferee(self, room_jid_s, nick): |
239 """Checks if the player with this nick is the referee for the game in this room""" | 267 """Checks if the player with this nick is the referee for the game in this room" |
240 if not self.gameExists(room_jid_s): | 268 @param room_jid_s: room userhost |
269 @param nick: user nick in the room | |
270 @return: True if the user is the referee of the game in this room | |
271 """ | |
272 if not self._gameExists(room_jid_s): | |
241 return False | 273 return False |
242 return room_jid_s + '/' + nick == self.games[room_jid_s]['referee'] | 274 return room_jid_s + '/' + nick == self.games[room_jid_s]['referee'] |
243 | 275 |
244 def isPlayer(self, room_jid_s, nick): | 276 def isPlayer(self, room_jid_s, nick): |
245 """Checks if the player with this nick is a player for the game in this room. | 277 """Checks if the user with this nick is a player for the game in this room. |
246 Important: the referee is not in the 'players' list right after the game | 278 @param room_jid_s: room userhost |
247 initialization - check with isReferee to be sure nick is not a player. | 279 @param nick: user nick in the room |
248 """ | 280 @return: True if the user is a player of the game in this room |
249 if not self.gameExists(room_jid_s): | 281 """ |
282 if not self._gameExists(room_jid_s): | |
250 return False | 283 return False |
284 # Important: the referee is not in the 'players' list right after | |
285 # the game initialization, that's why we do also check with isReferee | |
251 return nick in self.games[room_jid_s]['players'] or self.isReferee(room_jid_s, nick) | 286 return nick in self.games[room_jid_s]['players'] or self.isReferee(room_jid_s, nick) |
252 | 287 |
253 def checkWaitAuth(self, room, other_players, verbose=False): | 288 def _checkWaitAuth(self, room, other_players, verbose=False): |
254 """Check if we must wait before starting the game or not. | 289 """Check if we must wait for other players before starting the game. |
290 @param room: wokkel.muc.Room instance | |
291 @param other_players: list of the players without the referee | |
292 @param verbose: display debug message | |
255 @return: (x, y, z) with: | 293 @return: (x, y, z) with: |
256 x: False if we must wait, True otherwise | 294 x: False if we must wait, True otherwise |
257 y: the nicks of the players that have been checked and confirmed | 295 y: the nicks of the players that have been checked and confirmed |
258 z: the players that have not been checked or that are missing | 296 z: the players that have not been checked or that are missing |
259 """ | 297 """ |
268 if not result[0] and (verbose or _DEBUG): | 306 if not result[0] and (verbose or _DEBUG): |
269 debug(_("Still waiting for %s before starting the game %s in %s") % (result[2], self.name, room.occupantJID.userhost())) | 307 debug(_("Still waiting for %s before starting the game %s in %s") % (result[2], self.name, room.occupantJID.userhost())) |
270 return result | 308 return result |
271 | 309 |
272 def getUniqueName(self, muc_service="", profile_key='@DEFAULT@'): | 310 def getUniqueName(self, muc_service="", profile_key='@DEFAULT@'): |
311 """ | |
312 @param muc_service: you can leave empty to autofind the muc service | |
313 @param profile_key | |
314 @return: a unique name for a new room to be created | |
315 """ | |
273 room = self.host.plugins["XEP-0045"].getUniqueName(muc_service, profile_key=profile_key) | 316 room = self.host.plugins["XEP-0045"].getUniqueName(muc_service, profile_key=profile_key) |
274 return "sat_%s_%s" % (self.name.lower(), room) if room != "" else "" | 317 return "sat_%s_%s" % (self.name.lower(), room) if room != "" else "" |
275 | 318 |
276 def prepareRoom(self, other_players=[], room_jid=None, profile_key='@NONE@'): | 319 def prepareRoom(self, other_players=[], room_jid_s=None, profile_key='@NONE@'): |
277 """Prepare the room for a game: create it and invite players. | 320 """Prepare the room for a game: create it if it doesn't exist and invite players. |
278 @param other_players: list for other players JID userhosts | 321 @param other_players: list for other players JID userhosts |
279 @param room_jid: JID userhost of the room to reuse or None to create a new room | 322 @param room_jid_s: JID userhost of the room, or None to generate a unique name |
323 @param profile_key | |
280 """ | 324 """ |
281 debug(_('Preparing room for %s game') % self.name) | 325 debug(_('Preparing room for %s game') % self.name) |
282 profile = self.host.memory.getProfileName(profile_key) | 326 profile = self.host.memory.getProfileName(profile_key) |
283 if not profile: | 327 if not profile: |
284 error(_("Unknown profile")) | 328 error(_("Unknown profile")) |
285 return | 329 return |
286 | 330 |
287 def roomJoined(room): | 331 def roomJoined(room): |
288 """@param room: instance of wokkel.muc.Room""" | 332 """@param room: instance of wokkel.muc.Room""" |
289 self.createOrInvite(room, other_players, profile) | 333 self._createOrInvite(room, other_players, profile) |
290 | 334 |
291 def afterClientInit(room_jid): | 335 def afterClientInit(room_jid_s): |
292 """Create/join the given room, or a unique generated one if no room is specified. | 336 """Create/join the given room, or a unique generated one if no room is specified. |
293 @param room_jid: room to join | 337 @param room_jids: userhost of the room to join |
294 """ | 338 """ |
295 if room_jid is not None and room_jid != "": # a room name has been specified | 339 if room_jid_s is not None and room_jid_s != "": # a room name has been specified |
296 if room_jid in self.host.plugins["XEP-0045"].clients[profile].joined_rooms: | 340 if room_jid_s in self.host.plugins["XEP-0045"].clients[profile].joined_rooms: |
297 roomJoined(self.host.plugins["XEP-0045"].clients[profile].joined_rooms[room_jid]) | 341 roomJoined(self.host.plugins["XEP-0045"].clients[profile].joined_rooms[room_jid_s]) |
298 return | 342 return |
299 else: | 343 else: |
300 room_jid = self.getUniqueName(profile_key=profile_key) | 344 room_jid_s = self.getUniqueName(profile_key=profile_key) |
301 if room_jid == "": | 345 if room_jid_s == "": |
302 return | 346 return |
303 user_jid = self.host.getJidNStream(profile)[0] | 347 user_jid = self.host.getJidNStream(profile)[0] |
304 d = self.host.plugins["XEP-0045"].join(JID(room_jid), user_jid.user, {}, profile) | 348 d = self.host.plugins["XEP-0045"].join(JID(room_jid_s), user_jid.user, {}, profile) |
305 d.addCallback(roomJoined) | 349 d.addCallback(roomJoined) |
306 | 350 |
307 client = self.host.getClient(profile) | 351 client = self.host.getClient(profile) |
308 if not client: | 352 if not client: |
309 error(_('No client for this profile key: %s') % profile_key) | 353 error(_('No client for this profile key: %s') % profile_key) |
310 return | 354 return |
311 client.client_initialized.addCallback(lambda ignore: afterClientInit(room_jid)) | 355 client.client_initialized.addCallback(lambda ignore: afterClientInit(room_jid_s)) |
312 | 356 |
313 def userJoinedTrigger(self, room, user, profile): | 357 def userJoinedTrigger(self, room, user, profile): |
314 """This trigger is used to check if the new user can take part of a game, | 358 """This trigger is used to check if the new user can take part of a game, |
315 create the game if we were waiting for him or just update the players list. | 359 create the game if we were waiting for him or just update the players list. |
316 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} | 360 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} |
319 """ | 363 """ |
320 room_jid_s = room.occupantJID.userhost() | 364 room_jid_s = room.occupantJID.userhost() |
321 profile_nick = room.occupantJID.resource | 365 profile_nick = room.occupantJID.resource |
322 if not self.isReferee(room_jid_s, profile_nick): | 366 if not self.isReferee(room_jid_s, profile_nick): |
323 return True # profile is not the referee | 367 return True # profile is not the referee |
324 if not self.checkJoinAuth(room_jid_s, nick=user.nick): | 368 if not self._checkJoinAuth(room_jid_s, nick=user.nick): |
325 # user not allowed but let him know that we are playing :p | 369 # user not allowed but let him know that we are playing :p |
326 self.signalPlayers(room_jid_s, [JID(room_jid_s + '/' + user.nick)], profile) | 370 self._signalPlayers(room_jid_s, [JID(room_jid_s + '/' + user.nick)], profile) |
327 return True | 371 return True |
328 if self.wait_mode == self.FOR_ALL: | 372 if self.wait_mode == self.FOR_ALL: |
329 # considering the last batch of invitations | 373 # considering the last batch of invitations |
330 batch = len(self.invitations[room_jid_s]) - 1 | 374 batch = len(self.invitations[room_jid_s]) - 1 |
331 if batch < 0: | 375 if batch < 0: |
332 error("Invitations from %s to play %s in %s have been lost!" % (profile_nick, self.name, room_jid_s)) | 376 error("Invitations from %s to play %s in %s have been lost!" % (profile_nick, self.name, room_jid_s)) |
333 return True | 377 return True |
334 other_players = self.invitations[room_jid_s][batch][1] | 378 other_players = self.invitations[room_jid_s][batch][1] |
335 (auth, nicks, dummy) = self.checkWaitAuth(room, other_players) | 379 (auth, nicks, dummy) = self._checkWaitAuth(room, other_players) |
336 if auth: | 380 if auth: |
337 del self.invitations[room_jid_s][batch] | 381 del self.invitations[room_jid_s][batch] |
338 nicks.insert(0, profile_nick) # add the referee | 382 nicks.insert(0, profile_nick) # add the referee |
339 self.createGame(room_jid_s, nicks, profile_key=profile) | 383 self.createGame(room_jid_s, nicks, profile_key=profile) |
340 return True | 384 return True |
341 # let the room know that a new player joined | 385 # let the room know that a new player joined |
342 self.updatePlayers(room_jid_s, [user.nick], profile) | 386 self._updatePlayers(room_jid_s, [user.nick], profile) |
343 return True | 387 return True |
344 | 388 |
345 def userLeftTrigger(self, room, user, profile): | 389 def userLeftTrigger(self, room, user, profile): |
346 """This trigger is used to update or stop the game when a user leaves. | 390 """This trigger is used to update or stop the game when a user leaves. |
347 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} | 391 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} |
366 batch = 0 # add to the first batch of invitations | 410 batch = 0 # add to the first batch of invitations |
367 if user_jid not in self.invitations[room_jid_s][batch][1]: | 411 if user_jid not in self.invitations[room_jid_s][batch][1]: |
368 self.invitations[room_jid_s][batch][1].append(user_jid) | 412 self.invitations[room_jid_s][batch][1].append(user_jid) |
369 return True | 413 return True |
370 | 414 |
371 def checkCreateGameAndInit(self, room_jid_s, profile): | 415 def _checkCreateGameAndInit(self, room_jid_s, profile): |
372 """Check if that profile can create the game. If the game can be created | 416 """Check if that profile can create the game. If the game can be created |
373 but is not initialized yet, this method will also do the initialization | 417 but is not initialized yet, this method will also do the initialization. |
418 @param room_jid_s: room userhost | |
419 @param profile | |
374 @return: a couple (create, sync) with: | 420 @return: a couple (create, sync) with: |
375 - create: set to True to allow the game creation | 421 - create: set to True to allow the game creation |
376 - sync: set to True to advice a game synchronization | 422 - sync: set to True to advice a game synchronization |
377 """ | 423 """ |
378 user_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid_s, profile) | 424 user_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid_s, profile) |
379 if not user_nick: | 425 if not user_nick: |
380 error('Internal error') | 426 error('Internal error: profile %s has not joined the room %s' % (profile, room_jid_s)) |
381 return False, False | 427 return False, False |
382 if self.gameExists(room_jid_s): | 428 if self._gameExists(room_jid_s): |
383 referee = self.isReferee(room_jid_s, user_nick) | 429 is_referee = self.isReferee(room_jid_s, user_nick) |
384 if self.gameExists(room_jid_s, started=True): | 430 if self._gameExists(room_jid_s, started=True): |
385 warning(_("%s game already created in room %s") % (self.name, room_jid_s)) | 431 warning(_("%s game already created in room %s") % (self.name, room_jid_s)) |
386 return False, referee | 432 return False, is_referee |
387 elif not referee: | 433 elif not is_referee: |
388 warning(_("%s game in room %s can only be created by %s") % (self.name, room_jid_s, user_nick)) | 434 warning(_("%s game in room %s can only be created by %s") % (self.name, room_jid_s, user_nick)) |
389 return False, False | 435 return False, False |
390 else: | 436 else: |
391 self.initGame(room_jid_s, user_nick) | 437 self._initGame(room_jid_s, user_nick) |
392 return True, False | 438 return True, False |
393 | 439 |
394 def createGame(self, room_jid_s, nicks=[], profile_key='@NONE@'): | 440 def createGame(self, room_jid_s, nicks=[], profile_key='@NONE@'): |
395 """Create a new game - this can be called directly from a frontend | 441 """Create a new game - this can be called directly from a frontend |
396 and skips all the checks and invitation system, but the game must | 442 and skips all the checks and invitation system, but the game must |
401 debug(_("Creating %s game in room %s") % (self.name, room_jid_s)) | 447 debug(_("Creating %s game in room %s") % (self.name, room_jid_s)) |
402 profile = self.host.memory.getProfileName(profile_key) | 448 profile = self.host.memory.getProfileName(profile_key) |
403 if not profile: | 449 if not profile: |
404 error(_("profile %s is unknown") % profile_key) | 450 error(_("profile %s is unknown") % profile_key) |
405 return | 451 return |
406 (create, sync) = self.checkCreateGameAndInit(room_jid_s, profile) | 452 (create, sync) = self._checkCreateGameAndInit(room_jid_s, profile) |
407 if not create: | 453 if not create: |
408 if sync: | 454 if sync: |
409 debug(_('Synchronize game %s in %s for %s') % (self.name, room_jid_s, ', '.join(nicks))) | 455 debug(_('Synchronize game %s in %s for %s') % (self.name, room_jid_s, ', '.join(nicks))) |
410 # TODO: we should call a method to re-send the information to a player who left | 456 # TODO: we should call a method to re-send the information to a player who left |
411 # and joined the room again, currently: we may restart a whole new round... | 457 # and joined the room again, currently: we may restart a whole new round... |
412 self.updatePlayers(room_jid_s, nicks, profile) | 458 self._updatePlayers(room_jid_s, nicks, profile) |
413 return | 459 return |
414 self.games[room_jid_s]['started'] = True | 460 self.games[room_jid_s]['started'] = True |
415 self.updatePlayers(room_jid_s, nicks, profile) | 461 self._updatePlayers(room_jid_s, nicks, profile) |
416 if self.player_init == {}: | 462 if self.player_init == {}: |
417 return | 463 return |
418 # specific data to each player | 464 # specific data to each player |
419 status = {} | 465 status = {} |
420 players_data = {} | 466 players_data = {} |
423 players_data[nick] = copy.deepcopy(self.player_init) | 469 players_data[nick] = copy.deepcopy(self.player_init) |
424 status[nick] = "init" | 470 status[nick] = "init" |
425 self.games[room_jid_s].update({'status': status, 'players_data': players_data}) | 471 self.games[room_jid_s].update({'status': status, 'players_data': players_data}) |
426 | 472 |
427 def playerReady(self, player, referee, profile_key='@NONE@'): | 473 def playerReady(self, player, referee, profile_key='@NONE@'): |
428 """Must be called when player is ready to start a new game""" | 474 """Must be called when player is ready to start a new game |
475 @param player: the player nick in the room | |
476 @param referee: referee userhost | |
477 """ | |
429 profile = self.host.memory.getProfileName(profile_key) | 478 profile = self.host.memory.getProfileName(profile_key) |
430 if not profile: | 479 if not profile: |
431 error(_("profile %s is unknown") % profile_key) | 480 error(_("profile %s is unknown") % profile_key) |
432 return | 481 return |
433 debug('new player ready: %s' % profile) | 482 debug('new player ready: %s' % profile) |
483 # TODO: we probably need to add the game and room names in the sent message | |
434 self.send(JID(referee), 'player_ready', {'player': player}, profile=profile) | 484 self.send(JID(referee), 'player_ready', {'player': player}, profile=profile) |
435 | 485 |
436 def newRound(self, room_jid, data, profile): | 486 def newRound(self, room_jid, data, profile): |
437 """Launch a new round (reinit the user data)""" | 487 """Launch a new round (reinit the user data) |
488 @param room_jid: room userhost | |
489 @param data: a couple (common_data, msg_elts) with: | |
490 - common_data: backend initialization data for the new round | |
491 - msg_elts: dict to map each user to his specific initialization message | |
492 @param profile | |
493 """ | |
438 debug(_('new round for %s game') % self.name) | 494 debug(_('new round for %s game') % self.name) |
439 game_data = self.games[room_jid.userhost()] | 495 game_data = self.games[room_jid.userhost()] |
440 players = game_data['players'] | 496 players = game_data['players'] |
441 players_data = game_data['players_data'] | 497 players_data = game_data['players_data'] |
442 game_data['stage'] = "init" | 498 game_data['stage'] = "init" |
452 self.send(room_jid, msg_elts, profile=profile) | 508 self.send(room_jid, msg_elts, profile=profile) |
453 if common_data is not None: | 509 if common_data is not None: |
454 for player in players: | 510 for player in players: |
455 players_data[player].update(common_data) | 511 players_data[player].update(common_data) |
456 | 512 |
457 def createGameElt(self, to_jid, type_="normal"): | 513 def _createGameElt(self, to_jid): |
458 """Create a generic domish Element for the game""" | 514 """Create a generic domish Element for the game messages |
515 @param to_jid: JID of the recipient | |
516 @return: the created element | |
517 """ | |
459 type_ = "normal" if to_jid.resource else "groupchat" | 518 type_ = "normal" if to_jid.resource else "groupchat" |
460 elt = domish.Element((None, 'message')) | 519 elt = domish.Element((None, 'message')) |
461 elt["to"] = to_jid.full() | 520 elt["to"] = to_jid.full() |
462 elt["type"] = type_ | 521 elt["type"] = type_ |
463 elt.addElement(self.ns_tag) | 522 elt.addElement(self.ns_tag) |
464 return elt | 523 return elt |
465 | 524 |
466 def createStartElement(self, players=None, name="started"): | 525 def _createStartElement(self, players=None, name="started"): |
467 """Create a game "started" domish Element | 526 """Create a domish Element listing the game users |
468 @param name: element name (default: "started"). | 527 @param players: list of the players |
528 @param name: element name: | |
529 - "started" to signal the players that the game has been started | |
530 - "players" to signal the list of players when the game is not started yet | |
531 @return the create element | |
469 """ | 532 """ |
470 started_elt = domish.Element((None, name)) | 533 started_elt = domish.Element((None, name)) |
471 if players is None: | 534 if players is None: |
472 return started_elt | 535 return started_elt |
473 idx = 0 | 536 idx = 0 |
477 player_elt['index'] = str(idx) | 540 player_elt['index'] = str(idx) |
478 idx += 1 | 541 idx += 1 |
479 started_elt.addChild(player_elt) | 542 started_elt.addChild(player_elt) |
480 return started_elt | 543 return started_elt |
481 | 544 |
482 def sendElements(self, to_jid, data, profile=None): | 545 def _sendElements(self, to_jid, data, profile=None): |
483 """ | 546 """ |
484 @param to_jid: recipient JID | 547 @param to_jid: recipient JID |
485 @param data: list of (elem, attr, content) with: | 548 @param data: list of (elem, attr, content) with: |
486 - elem: domish.Element, unicode or a couple: | 549 - elem: domish.Element, unicode or a couple: |
487 - domish.Element to be directly added as a child to the message | 550 - domish.Element to be directly added as a child to the message |
492 @param profile: the profile from which the message is sent | 555 @param profile: the profile from which the message is sent |
493 """ | 556 """ |
494 if profile is None: | 557 if profile is None: |
495 error(_("Message can not be sent without a sender profile")) | 558 error(_("Message can not be sent without a sender profile")) |
496 return | 559 return |
497 msg = self.createGameElt(to_jid) | 560 msg = self._createGameElt(to_jid) |
498 for elem, attrs, content in data: | 561 for elem, attrs, content in data: |
499 if elem is not None: | 562 if elem is not None: |
500 if isinstance(elem, domish.Element): | 563 if isinstance(elem, domish.Element): |
501 msg.firstChildElement().addChild(elem) | 564 msg.firstChildElement().addChild(elem) |
502 else: | 565 else: |
517 and add it as a child to the message (see domish.Element.addElement) | 580 and add it as a child to the message (see domish.Element.addElement) |
518 @param attrs: dictionary of attributes for the new child | 581 @param attrs: dictionary of attributes for the new child |
519 @param content: unicode that is appended to the child content | 582 @param content: unicode that is appended to the child content |
520 @param profile: the profile from which the message is sent | 583 @param profile: the profile from which the message is sent |
521 """ | 584 """ |
522 self.sendElements(to_jid, [(elem, attrs, content)], profile) | 585 self._sendElements(to_jid, [(elem, attrs, content)], profile) |
523 | 586 |
524 def getHandler(self, profile): | 587 def getHandler(self, profile): |
525 return RoomGameHandler(self) | 588 return RoomGameHandler(self) |
526 | 589 |
527 | 590 |