Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_room_game.py @ 4037:524856bd7b19
massive refactoring to switch from camelCase to snake_case:
historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.
However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.
To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.
This is a massive change, and may result in some bugs.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 13:54:42 +0200 |
parents | be6d91572633 |
children |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
54 | 54 |
55 | 55 |
56 class RoomGame(object): | 56 class RoomGame(object): |
57 """This class is used to help launching a MUC game. | 57 """This class is used to help launching a MUC game. |
58 | 58 |
59 Bridge methods callbacks: _prepareRoom, _playerReady, _createGame | 59 bridge methods callbacks: _prepare_room, _player_ready, _create_game |
60 Triggered methods: userJoinedTrigger, userLeftTrigger | 60 Triggered methods: user_joined_trigger, user_left_trigger |
61 Also called from subclasses: newRound | 61 Also called from subclasses: new_round |
62 | 62 |
63 For examples of messages sequences, please look in sub-classes. | 63 For examples of messages sequences, please look in sub-classes. |
64 """ | 64 """ |
65 | 65 |
66 # Values for self.invite_mode (who can invite after the game creation) | 66 # Values for self.invite_mode (who can invite after the game creation) |
79 """For other plugin to dynamically inherit this class, it is necessary to not use __init__ but _init_. | 79 """For other plugin to dynamically inherit this class, it is necessary to not use __init__ but _init_. |
80 The subclass itself must be initialized this way: | 80 The subclass itself must be initialized this way: |
81 | 81 |
82 class MyGame(object): | 82 class MyGame(object): |
83 | 83 |
84 def inheritFromRoomGame(self, host): | 84 def inherit_from_room_game(self, host): |
85 global RoomGame | 85 global RoomGame |
86 RoomGame = host.plugins["ROOM-GAME"].__class__ | 86 RoomGame = host.plugins["ROOM-GAME"].__class__ |
87 self.__class__ = type(self.__class__.__name__, (self.__class__, RoomGame, object), {}) | 87 self.__class__ = type(self.__class__.__name__, (self.__class__, RoomGame, object), {}) |
88 | 88 |
89 def __init__(self, host): | 89 def __init__(self, host): |
90 self.inheritFromRoomGame(host) | 90 self.inherit_from_room_game(host) |
91 RoomGame._init_(self, host, ...) | 91 RoomGame._init_(self, host, ...) |
92 | 92 |
93 """ | 93 """ |
94 self.host = host | 94 self.host = host |
95 | 95 |
123 # this has been added for testing purpose. It is sometimes needed to remove a dependence | 123 # this has been added for testing purpose. It is sometimes needed to remove a dependence |
124 # while building the synchronization data, for example to replace a call to time.time() | 124 # while building the synchronization data, for example to replace a call to time.time() |
125 # by an arbitrary value. If needed, this attribute would be set to True from the testcase. | 125 # by an arbitrary value. If needed, this attribute would be set to True from the testcase. |
126 self.testing = False | 126 self.testing = False |
127 | 127 |
128 host.trigger.add("MUC user joined", self.userJoinedTrigger) | 128 host.trigger.add("MUC user joined", self.user_joined_trigger) |
129 host.trigger.add("MUC user left", self.userLeftTrigger) | 129 host.trigger.add("MUC user left", self.user_left_trigger) |
130 | 130 |
131 def _createOrInvite(self, room_jid, other_players, profile): | 131 def _create_or_invite(self, room_jid, other_players, profile): |
132 """ | 132 """ |
133 This is called only when someone explicitly wants to play. | 133 This is called only when someone explicitly wants to play. |
134 | 134 |
135 The game will not be created if one already exists in the room, | 135 The game will not be created if one already exists in the room, |
136 also its creation could be postponed until all the expected players | 136 also its creation could be postponed until all the expected players |
137 join the room (in that case it will be created from userJoinedTrigger). | 137 join the room (in that case it will be created from user_joined_trigger). |
138 @param room (wokkel.muc.Room): the room | 138 @param room (wokkel.muc.Room): the room |
139 @param other_players (list[jid.JID]): list of the other players JID (bare) | 139 @param other_players (list[jid.JID]): list of the other players JID (bare) |
140 """ | 140 """ |
141 # FIXME: broken ! | 141 # FIXME: broken ! |
142 raise NotImplementedError("To be fixed") | 142 raise NotImplementedError("To be fixed") |
143 client = self.host.getClient(profile) | 143 client = self.host.get_client(profile) |
144 user_jid = self.host.getJidNStream(profile)[0] | 144 user_jid = self.host.get_jid_n_stream(profile)[0] |
145 nick = self.host.plugins["XEP-0045"].getRoomNick(client, room_jid) | 145 nick = self.host.plugins["XEP-0045"].get_room_nick(client, room_jid) |
146 nicks = [nick] | 146 nicks = [nick] |
147 if self._gameExists(room_jid): | 147 if self._game_exists(room_jid): |
148 if not self._checkJoinAuth(room_jid, user_jid, nick): | 148 if not self._check_join_auth(room_jid, user_jid, nick): |
149 return | 149 return |
150 nicks.extend(self._invitePlayers(room_jid, other_players, nick, profile)) | 150 nicks.extend(self._invite_players(room_jid, other_players, nick, profile)) |
151 self._updatePlayers(room_jid, nicks, True, profile) | 151 self._update_players(room_jid, nicks, True, profile) |
152 else: | 152 else: |
153 self._initGame(room_jid, nick) | 153 self._init_game(room_jid, nick) |
154 (auth, waiting, missing) = self._checkWaitAuth(room_jid, other_players) | 154 (auth, waiting, missing) = self._check_wait_auth(room_jid, other_players) |
155 nicks.extend(waiting) | 155 nicks.extend(waiting) |
156 nicks.extend(self._invitePlayers(room_jid, missing, nick, profile)) | 156 nicks.extend(self._invite_players(room_jid, missing, nick, profile)) |
157 if auth: | 157 if auth: |
158 self.createGame(room_jid, nicks, profile) | 158 self.create_game(room_jid, nicks, profile) |
159 else: | 159 else: |
160 self._updatePlayers(room_jid, nicks, False, profile) | 160 self._update_players(room_jid, nicks, False, profile) |
161 | 161 |
162 def _initGame(self, room_jid, referee_nick): | 162 def _init_game(self, room_jid, referee_nick): |
163 """ | 163 """ |
164 | 164 |
165 @param room_jid (jid.JID): JID of the room | 165 @param room_jid (jid.JID): JID of the room |
166 @param referee_nick (unicode): nickname of the referee | 166 @param referee_nick (unicode): nickname of the referee |
167 """ | 167 """ |
168 # Important: do not add the referee to 'players' yet. For a | 168 # Important: do not add the referee to 'players' yet. For a |
169 # <players /> message to be emitted whenever a new player is joining, | 169 # <players /> message to be emitted whenever a new player is joining, |
170 # it is necessary to not modify 'players' outside of _updatePlayers. | 170 # it is necessary to not modify 'players' outside of _update_players. |
171 referee_jid = jid.JID(room_jid.userhost() + "/" + referee_nick) | 171 referee_jid = jid.JID(room_jid.userhost() + "/" + referee_nick) |
172 self.games[room_jid] = { | 172 self.games[room_jid] = { |
173 "referee": referee_jid, | 173 "referee": referee_jid, |
174 "players": [], | 174 "players": [], |
175 "started": False, | 175 "started": False, |
176 "status": {}, | 176 "status": {}, |
177 } | 177 } |
178 self.games[room_jid].update(copy.deepcopy(self.game_init)) | 178 self.games[room_jid].update(copy.deepcopy(self.game_init)) |
179 self.invitations.setdefault(room_jid, []) | 179 self.invitations.setdefault(room_jid, []) |
180 | 180 |
181 def _gameExists(self, room_jid, started=False): | 181 def _game_exists(self, room_jid, started=False): |
182 """Return True if a game has been initialized/started. | 182 """Return True if a game has been initialized/started. |
183 @param started: if False, the game must be initialized to return True, | 183 @param started: if False, the game must be initialized to return True, |
184 otherwise it must be initialized and started with createGame. | 184 otherwise it must be initialized and started with create_game. |
185 @return: True if a game is initialized/started in that room""" | 185 @return: True if a game is initialized/started in that room""" |
186 return room_jid in self.games and (not started or self.games[room_jid]["started"]) | 186 return room_jid in self.games and (not started or self.games[room_jid]["started"]) |
187 | 187 |
188 def _checkJoinAuth(self, room_jid, user_jid=None, nick="", verbose=False): | 188 def _check_join_auth(self, room_jid, user_jid=None, nick="", verbose=False): |
189 """Checks if this profile is allowed to join the game. | 189 """Checks if this profile is allowed to join the game. |
190 | 190 |
191 The parameter nick is used to check if the user is already | 191 The parameter nick is used to check if the user is already |
192 a player in that game. When this method is called from | 192 a player in that game. When this method is called from |
193 userJoinedTrigger, nick is also used to check the user | 193 user_joined_trigger, nick is also used to check the user |
194 identity instead of user_jid_s (see TODO comment below). | 194 identity instead of user_jid_s (see TODO comment below). |
195 @param room_jid (jid.JID): the JID of the room hosting the game | 195 @param room_jid (jid.JID): the JID of the room hosting the game |
196 @param user_jid (jid.JID): JID of the user | 196 @param user_jid (jid.JID): JID of the user |
197 @param nick (unicode): nick of the user | 197 @param nick (unicode): nick of the user |
198 @return: True if this profile can join the game | 198 @return: True if this profile can join the game |
199 """ | 199 """ |
200 auth = False | 200 auth = False |
201 if not self._gameExists(room_jid): | 201 if not self._game_exists(room_jid): |
202 auth = False | 202 auth = False |
203 elif self.join_mode == self.ALL or self.isPlayer(room_jid, nick): | 203 elif self.join_mode == self.ALL or self.is_player(room_jid, nick): |
204 auth = True | 204 auth = True |
205 elif self.join_mode == self.INVITED: | 205 elif self.join_mode == self.INVITED: |
206 # considering all the batches of invitations | 206 # considering all the batches of invitations |
207 for invitations in self.invitations[room_jid]: | 207 for invitations in self.invitations[room_jid]: |
208 if user_jid is not None: | 208 if user_jid is not None: |
225 "room": room_jid.userhost(), | 225 "room": room_jid.userhost(), |
226 } | 226 } |
227 ) | 227 ) |
228 return auth | 228 return auth |
229 | 229 |
230 def _updatePlayers(self, room_jid, nicks, sync, profile): | 230 def _update_players(self, room_jid, nicks, sync, profile): |
231 """Update the list of players and signal to the room that some players joined the game. | 231 """Update the list of players and signal to the room that some players joined the game. |
232 If sync is True, the news players are synchronized with the game data they have missed. | 232 If sync is True, the news players are synchronized with the game data they have missed. |
233 Remark: self.games[room_jid]['players'] should not be modified outside this method. | 233 Remark: self.games[room_jid]['players'] should not be modified outside this method. |
234 @param room_jid (jid.JID): JID of the room | 234 @param room_jid (jid.JID): JID of the room |
235 @param nicks (list[unicode]): list of players nicks in the room (referee included, in first position) | 235 @param nicks (list[unicode]): list of players nicks in the room (referee included, in first position) |
249 for nick in new_nicks: | 249 for nick in new_nicks: |
250 self.games[room_jid]["status"][nick] = status | 250 self.games[room_jid]["status"][nick] = status |
251 | 251 |
252 sync = ( | 252 sync = ( |
253 sync | 253 sync |
254 and self._gameExists(room_jid, True) | 254 and self._game_exists(room_jid, True) |
255 and len(self.games[room_jid]["players"]) > 0 | 255 and len(self.games[room_jid]["players"]) > 0 |
256 ) | 256 ) |
257 setStatus("desync" if sync else "init") | 257 setStatus("desync" if sync else "init") |
258 self.games[room_jid]["players"].extend(new_nicks) | 258 self.games[room_jid]["players"].extend(new_nicks) |
259 self._synchronizeRoom(room_jid, [room_jid], profile) | 259 self._synchronize_room(room_jid, [room_jid], profile) |
260 if sync: | 260 if sync: |
261 setStatus("init") | 261 setStatus("init") |
262 | 262 |
263 def _synchronizeRoom(self, room_jid, recipients, profile): | 263 def _synchronize_room(self, room_jid, recipients, profile): |
264 """Communicate the list of players to the whole room or only to some users, | 264 """Communicate the list of players to the whole room or only to some users, |
265 also send the synchronization data to the players who recently joined the game. | 265 also send the synchronization data to the players who recently joined the game. |
266 @param room_jid (jid.JID): JID of the room | 266 @param room_jid (jid.JID): JID of the room |
267 @recipients (list[jid.JID]): list of JIDs, the recipients of the message could be: | 267 @recipients (list[jid.JID]): list of JIDs, the recipients of the message could be: |
268 - room JID | 268 - room JID |
269 - room JID + "/" + user nick | 269 - room JID + "/" + user nick |
270 @param profile (unicode): %(doc_profile)s | 270 @param profile (unicode): %(doc_profile)s |
271 """ | 271 """ |
272 if self._gameExists(room_jid, started=True): | 272 if self._game_exists(room_jid, started=True): |
273 element = self._createStartElement(self.games[room_jid]["players"]) | 273 element = self._create_start_element(self.games[room_jid]["players"]) |
274 else: | 274 else: |
275 element = self._createStartElement( | 275 element = self._create_start_element( |
276 self.games[room_jid]["players"], name="players" | 276 self.games[room_jid]["players"], name="players" |
277 ) | 277 ) |
278 elements = [(element, None, None)] | 278 elements = [(element, None, None)] |
279 | 279 |
280 sync_args = [] | 280 sync_args = [] |
281 sync_data = self._getSyncData(room_jid) | 281 sync_data = self._get_sync_data(room_jid) |
282 for nick in sync_data: | 282 for nick in sync_data: |
283 user_jid = jid.JID(room_jid.userhost() + "/" + nick) | 283 user_jid = jid.JID(room_jid.userhost() + "/" + nick) |
284 if user_jid in recipients: | 284 if user_jid in recipients: |
285 user_elements = copy.deepcopy(elements) | 285 user_elements = copy.deepcopy(elements) |
286 for child in sync_data[nick]: | 286 for child in sync_data[nick]: |
289 else: | 289 else: |
290 user_elements = [(child, None, None) for child in sync_data[nick]] | 290 user_elements = [(child, None, None) for child in sync_data[nick]] |
291 sync_args.append(([user_jid, user_elements], {"profile": profile})) | 291 sync_args.append(([user_jid, user_elements], {"profile": profile})) |
292 | 292 |
293 for recipient in recipients: | 293 for recipient in recipients: |
294 self._sendElements(recipient, elements, profile=profile) | 294 self._send_elements(recipient, elements, profile=profile) |
295 for args, kwargs in sync_args: | 295 for args, kwargs in sync_args: |
296 self._sendElements(*args, **kwargs) | 296 self._send_elements(*args, **kwargs) |
297 | 297 |
298 def _getSyncData(self, room_jid, force_nicks=None): | 298 def _get_sync_data(self, room_jid, force_nicks=None): |
299 """The synchronization data are returned for each player who | 299 """The synchronization data are returned for each player who |
300 has the state 'desync' or if he's been contained by force_nicks. | 300 has the state 'desync' or if he's been contained by force_nicks. |
301 @param room_jid (jid.JID): JID of the room | 301 @param room_jid (jid.JID): JID of the room |
302 @param force_nicks: force the synchronization for this list of the nicks | 302 @param force_nicks: force the synchronization for this list of the nicks |
303 @return: a mapping between player nicks and a list of elements to | 303 @return: a mapping between player nicks and a list of elements to |
304 be sent by self._synchronizeRoom for the game to be synchronized. | 304 be sent by self._synchronize_room for the game to be synchronized. |
305 """ | 305 """ |
306 if not self._gameExists(room_jid): | 306 if not self._game_exists(room_jid): |
307 return {} | 307 return {} |
308 data = {} | 308 data = {} |
309 status = self.games[room_jid]["status"] | 309 status = self.games[room_jid]["status"] |
310 nicks = [nick for nick in status if status[nick] == "desync"] | 310 nicks = [nick for nick in status if status[nick] == "desync"] |
311 if force_nicks is None: | 311 if force_nicks is None: |
312 force_nicks = [] | 312 force_nicks = [] |
313 for nick in force_nicks: | 313 for nick in force_nicks: |
314 if nick not in nicks: | 314 if nick not in nicks: |
315 nicks.append(nick) | 315 nicks.append(nick) |
316 for nick in nicks: | 316 for nick in nicks: |
317 elements = self.getSyncDataForPlayer(room_jid, nick) | 317 elements = self.get_sync_data_for_player(room_jid, nick) |
318 if elements: | 318 if elements: |
319 data[nick] = elements | 319 data[nick] = elements |
320 return data | 320 return data |
321 | 321 |
322 def getSyncDataForPlayer(self, room_jid, nick): | 322 def get_sync_data_for_player(self, room_jid, nick): |
323 """This method may (and should probably) be overwritten by a child class. | 323 """This method may (and should probably) be overwritten by a child class. |
324 @param room_jid (jid.JID): JID of the room | 324 @param room_jid (jid.JID): JID of the room |
325 @param nick: the nick of the player to be synchronized | 325 @param nick: the nick of the player to be synchronized |
326 @return: a list of elements to synchronize this player with the game. | 326 @return: a list of elements to synchronize this player with the game. |
327 """ | 327 """ |
328 return [] | 328 return [] |
329 | 329 |
330 def _invitePlayers(self, room_jid, other_players, nick, profile): | 330 def _invite_players(self, room_jid, other_players, nick, profile): |
331 """Invite players to a room, associated game may exist or not. | 331 """Invite players to a room, associated game may exist or not. |
332 | 332 |
333 @param other_players (list[jid.JID]): list of the players to invite | 333 @param other_players (list[jid.JID]): list of the players to invite |
334 @param nick (unicode): nick of the user who send the invitation | 334 @param nick (unicode): nick of the user who send the invitation |
335 @return: list[unicode] of room nicks for invited players who are already in the room | 335 @return: list[unicode] of room nicks for invited players who are already in the room |
336 """ | 336 """ |
337 raise NotImplementedError("Need to be fixed !") | 337 raise NotImplementedError("Need to be fixed !") |
338 # FIXME: this is broken and unsecure ! | 338 # FIXME: this is broken and unsecure ! |
339 if not self._checkInviteAuth(room_jid, nick): | 339 if not self._check_invite_auth(room_jid, nick): |
340 return [] | 340 return [] |
341 # TODO: remove invitation waiting for too long, using the time data | 341 # TODO: remove invitation waiting for too long, using the time data |
342 self.invitations[room_jid].append( | 342 self.invitations[room_jid].append( |
343 (time(), [player.userhostJID() for player in other_players]) | 343 (time(), [player.userhostJID() for player in other_players]) |
344 ) | 344 ) |
354 ) | 354 ) |
355 else: | 355 else: |
356 nicks.append(other_nick) | 356 nicks.append(other_nick) |
357 return nicks | 357 return nicks |
358 | 358 |
359 def _checkInviteAuth(self, room_jid, nick, verbose=False): | 359 def _check_invite_auth(self, room_jid, nick, verbose=False): |
360 """Checks if this user is allowed to invite players | 360 """Checks if this user is allowed to invite players |
361 | 361 |
362 @param room_jid (jid.JID): JID of the room | 362 @param room_jid (jid.JID): JID of the room |
363 @param nick: user nick in the room | 363 @param nick: user nick in the room |
364 @param verbose: display debug message | 364 @param verbose: display debug message |
365 @return: True if the user is allowed to invite other players | 365 @return: True if the user is allowed to invite other players |
366 """ | 366 """ |
367 auth = False | 367 auth = False |
368 if self.invite_mode == self.FROM_ALL or not self._gameExists(room_jid): | 368 if self.invite_mode == self.FROM_ALL or not self._game_exists(room_jid): |
369 auth = True | 369 auth = True |
370 elif self.invite_mode == self.FROM_NONE: | 370 elif self.invite_mode == self.FROM_NONE: |
371 auth = not self._gameExists(room_jid, started=True) and self.isReferee( | 371 auth = not self._game_exists(room_jid, started=True) and self.is_referee( |
372 room_jid, nick | 372 room_jid, nick |
373 ) | 373 ) |
374 elif self.invite_mode == self.FROM_REFEREE: | 374 elif self.invite_mode == self.FROM_REFEREE: |
375 auth = self.isReferee(room_jid, nick) | 375 auth = self.is_referee(room_jid, nick) |
376 elif self.invite_mode == self.FROM_PLAYERS: | 376 elif self.invite_mode == self.FROM_PLAYERS: |
377 auth = self.isPlayer(room_jid, nick) | 377 auth = self.is_player(room_jid, nick) |
378 if not auth and (verbose or _DEBUG): | 378 if not auth and (verbose or _DEBUG): |
379 log.debug( | 379 log.debug( |
380 _("%(user)s not allowed to invite for the game %(game)s in %(room)s") | 380 _("%(user)s not allowed to invite for the game %(game)s in %(room)s") |
381 % {"user": nick, "game": self.name, "room": room_jid.userhost()} | 381 % {"user": nick, "game": self.name, "room": room_jid.userhost()} |
382 ) | 382 ) |
383 return auth | 383 return auth |
384 | 384 |
385 def isReferee(self, room_jid, nick): | 385 def is_referee(self, room_jid, nick): |
386 """Checks if the player with this nick is the referee for the game in this room" | 386 """Checks if the player with this nick is the referee for the game in this room" |
387 @param room_jid (jid.JID): room JID | 387 @param room_jid (jid.JID): room JID |
388 @param nick: user nick in the room | 388 @param nick: user nick in the room |
389 @return: True if the user is the referee of the game in this room | 389 @return: True if the user is the referee of the game in this room |
390 """ | 390 """ |
391 if not self._gameExists(room_jid): | 391 if not self._game_exists(room_jid): |
392 return False | 392 return False |
393 return ( | 393 return ( |
394 jid.JID(room_jid.userhost() + "/" + nick) == self.games[room_jid]["referee"] | 394 jid.JID(room_jid.userhost() + "/" + nick) == self.games[room_jid]["referee"] |
395 ) | 395 ) |
396 | 396 |
397 def isPlayer(self, room_jid, nick): | 397 def is_player(self, room_jid, nick): |
398 """Checks if the user with this nick is a player for the game in this room. | 398 """Checks if the user with this nick is a player for the game in this room. |
399 @param room_jid (jid.JID): JID of the room | 399 @param room_jid (jid.JID): JID of the room |
400 @param nick: user nick in the room | 400 @param nick: user nick in the room |
401 @return: True if the user is a player of the game in this room | 401 @return: True if the user is a player of the game in this room |
402 """ | 402 """ |
403 if not self._gameExists(room_jid): | 403 if not self._game_exists(room_jid): |
404 return False | 404 return False |
405 # Important: the referee is not in the 'players' list right after | 405 # Important: the referee is not in the 'players' list right after |
406 # the game initialization, that's why we do also check with isReferee | 406 # the game initialization, that's why we do also check with is_referee |
407 return nick in self.games[room_jid]["players"] or self.isReferee(room_jid, nick) | 407 return nick in self.games[room_jid]["players"] or self.is_referee(room_jid, nick) |
408 | 408 |
409 def _checkWaitAuth(self, room, other_players, verbose=False): | 409 def _check_wait_auth(self, room, other_players, verbose=False): |
410 """Check if we must wait for other players before starting the game. | 410 """Check if we must wait for other players before starting the game. |
411 | 411 |
412 @param room (wokkel.muc.Room): the room | 412 @param room (wokkel.muc.Room): the room |
413 @param other_players (list[jid.JID]): list of the players without the referee | 413 @param other_players (list[jid.JID]): list of the players without the referee |
414 @param verbose (bool): display debug message | 414 @param verbose (bool): display debug message |
439 "room": room.occupantJID.userhost(), | 439 "room": room.occupantJID.userhost(), |
440 } | 440 } |
441 ) | 441 ) |
442 return result | 442 return result |
443 | 443 |
444 def getUniqueName(self, muc_service=None, profile_key=C.PROF_KEY_NONE): | 444 def get_unique_name(self, muc_service=None, profile_key=C.PROF_KEY_NONE): |
445 """Generate unique room name | 445 """Generate unique room name |
446 | 446 |
447 @param muc_service (jid.JID): you can leave empty to autofind the muc service | 447 @param muc_service (jid.JID): you can leave empty to autofind the muc service |
448 @param profile_key (unicode): %(doc_profile_key)s | 448 @param profile_key (unicode): %(doc_profile_key)s |
449 @return: jid.JID (unique name for a new room to be created) | 449 @return: jid.JID (unique name for a new room to be created) |
450 """ | 450 """ |
451 client = self.host.getClient(profile_key) | 451 client = self.host.get_client(profile_key) |
452 # FIXME: jid.JID must be used instead of strings | 452 # FIXME: jid.JID must be used instead of strings |
453 room = self.host.plugins["XEP-0045"].getUniqueName(client, muc_service) | 453 room = self.host.plugins["XEP-0045"].get_unique_name(client, muc_service) |
454 return jid.JID("sat_%s_%s" % (self.name.lower(), room.userhost())) | 454 return jid.JID("sat_%s_%s" % (self.name.lower(), room.userhost())) |
455 | 455 |
456 def _prepareRoom( | 456 def _prepare_room( |
457 self, other_players=None, room_jid_s="", profile_key=C.PROF_KEY_NONE | 457 self, other_players=None, room_jid_s="", profile_key=C.PROF_KEY_NONE |
458 ): | 458 ): |
459 room_jid = jid.JID(room_jid_s) if room_jid_s else None | 459 room_jid = jid.JID(room_jid_s) if room_jid_s else None |
460 other_players = [jid.JID(player).userhostJID() for player in other_players] | 460 other_players = [jid.JID(player).userhostJID() for player in other_players] |
461 return self.prepareRoom(other_players, room_jid, profile_key) | 461 return self.prepare_room(other_players, room_jid, profile_key) |
462 | 462 |
463 def prepareRoom(self, other_players=None, room_jid=None, profile_key=C.PROF_KEY_NONE): | 463 def prepare_room(self, other_players=None, room_jid=None, profile_key=C.PROF_KEY_NONE): |
464 """Prepare the room for a game: create it if it doesn't exist and invite players. | 464 """Prepare the room for a game: create it if it doesn't exist and invite players. |
465 | 465 |
466 @param other_players (list[JID]): list of other players JID (bare) | 466 @param other_players (list[JID]): list of other players JID (bare) |
467 @param room_jid (jid.JID): JID of the room, or None to generate a unique name | 467 @param room_jid (jid.JID): JID of the room, or None to generate a unique name |
468 @param profile_key (unicode): %(doc_profile_key)s | 468 @param profile_key (unicode): %(doc_profile_key)s |
469 """ | 469 """ |
470 # FIXME: need to be refactored | 470 # FIXME: need to be refactored |
471 client = self.host.getClient(profile_key) | 471 client = self.host.get_client(profile_key) |
472 log.debug(_("Preparing room for %s game") % self.name) | 472 log.debug(_("Preparing room for %s game") % self.name) |
473 profile = self.host.memory.getProfileName(profile_key) | 473 profile = self.host.memory.get_profile_name(profile_key) |
474 if not profile: | 474 if not profile: |
475 log.error(_("Unknown profile")) | 475 log.error(_("Unknown profile")) |
476 return defer.succeed(None) | 476 return defer.succeed(None) |
477 if other_players is None: | 477 if other_players is None: |
478 other_players = [] | 478 other_players = [] |
479 | 479 |
480 # Create/join the given room, or a unique generated one if no room is specified. | 480 # Create/join the given room, or a unique generated one if no room is specified. |
481 if room_jid is None: | 481 if room_jid is None: |
482 room_jid = self.getUniqueName(profile_key=profile_key) | 482 room_jid = self.get_unique_name(profile_key=profile_key) |
483 else: | 483 else: |
484 self.host.plugins["XEP-0045"].checkRoomJoined(client, room_jid) | 484 self.host.plugins["XEP-0045"].check_room_joined(client, room_jid) |
485 self._createOrInvite(client, room_jid, other_players) | 485 self._create_or_invite(client, room_jid, other_players) |
486 return defer.succeed(None) | 486 return defer.succeed(None) |
487 | 487 |
488 user_jid = self.host.getJidNStream(profile)[0] | 488 user_jid = self.host.get_jid_n_stream(profile)[0] |
489 d = self.host.plugins["XEP-0045"].join(room_jid, user_jid.user, {}, profile) | 489 d = self.host.plugins["XEP-0045"].join(room_jid, user_jid.user, {}, profile) |
490 return d.addCallback( | 490 return d.addCallback( |
491 lambda __: self._createOrInvite(client, room_jid, other_players) | 491 lambda __: self._create_or_invite(client, room_jid, other_players) |
492 ) | 492 ) |
493 | 493 |
494 def userJoinedTrigger(self, room, user, profile): | 494 def user_joined_trigger(self, room, user, profile): |
495 """This trigger is used to check if the new user can take part of a game, create the game if we were waiting for him or just update the players list. | 495 """This trigger is used to check if the new user can take part of a game, create the game if we were waiting for him or just update the players list. |
496 | 496 |
497 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} | 497 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} |
498 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID | 498 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID |
499 @return: True to not interrupt the main process. | 499 @return: True to not interrupt the main process. |
500 """ | 500 """ |
501 room_jid = room.occupantJID.userhostJID() | 501 room_jid = room.occupantJID.userhostJID() |
502 profile_nick = room.occupantJID.resource | 502 profile_nick = room.occupantJID.resource |
503 if not self.isReferee(room_jid, profile_nick): | 503 if not self.is_referee(room_jid, profile_nick): |
504 return True # profile is not the referee | 504 return True # profile is not the referee |
505 if not self._checkJoinAuth( | 505 if not self._check_join_auth( |
506 room_jid, user.entity if user.entity else None, user.nick | 506 room_jid, user.entity if user.entity else None, user.nick |
507 ): | 507 ): |
508 # user not allowed but let him know that we are playing :p | 508 # user not allowed but let him know that we are playing :p |
509 self._synchronizeRoom( | 509 self._synchronize_room( |
510 room_jid, [jid.JID(room_jid.userhost() + "/" + user.nick)], profile | 510 room_jid, [jid.JID(room_jid.userhost() + "/" + user.nick)], profile |
511 ) | 511 ) |
512 return True | 512 return True |
513 if self.wait_mode == self.FOR_ALL: | 513 if self.wait_mode == self.FOR_ALL: |
514 # considering the last batch of invitations | 514 # considering the last batch of invitations |
518 "Invitations from %s to play %s in %s have been lost!" | 518 "Invitations from %s to play %s in %s have been lost!" |
519 % (profile_nick, self.name, room_jid.userhost()) | 519 % (profile_nick, self.name, room_jid.userhost()) |
520 ) | 520 ) |
521 return True | 521 return True |
522 other_players = self.invitations[room_jid][batch][1] | 522 other_players = self.invitations[room_jid][batch][1] |
523 (auth, nicks, __) = self._checkWaitAuth(room, other_players) | 523 (auth, nicks, __) = self._check_wait_auth(room, other_players) |
524 if auth: | 524 if auth: |
525 del self.invitations[room_jid][batch] | 525 del self.invitations[room_jid][batch] |
526 nicks.insert(0, profile_nick) # add the referee | 526 nicks.insert(0, profile_nick) # add the referee |
527 self.createGame(room_jid, nicks, profile_key=profile) | 527 self.create_game(room_jid, nicks, profile_key=profile) |
528 return True | 528 return True |
529 # let the room know that a new player joined | 529 # let the room know that a new player joined |
530 self._updatePlayers(room_jid, [user.nick], True, profile) | 530 self._update_players(room_jid, [user.nick], True, profile) |
531 return True | 531 return True |
532 | 532 |
533 def userLeftTrigger(self, room, user, profile): | 533 def user_left_trigger(self, room, user, profile): |
534 """This trigger is used to update or stop the game when a user leaves. | 534 """This trigger is used to update or stop the game when a user leaves. |
535 | 535 |
536 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} | 536 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} |
537 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID | 537 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID |
538 @return: True to not interrupt the main process. | 538 @return: True to not interrupt the main process. |
539 """ | 539 """ |
540 room_jid = room.occupantJID.userhostJID() | 540 room_jid = room.occupantJID.userhostJID() |
541 profile_nick = room.occupantJID.resource | 541 profile_nick = room.occupantJID.resource |
542 if not self.isReferee(room_jid, profile_nick): | 542 if not self.is_referee(room_jid, profile_nick): |
543 return True # profile is not the referee | 543 return True # profile is not the referee |
544 if self.isPlayer(room_jid, user.nick): | 544 if self.is_player(room_jid, user.nick): |
545 try: | 545 try: |
546 self.games[room_jid]["players"].remove(user.nick) | 546 self.games[room_jid]["players"].remove(user.nick) |
547 except ValueError: | 547 except ValueError: |
548 pass | 548 pass |
549 if len(self.games[room_jid]["players"]) == 0: | 549 if len(self.games[room_jid]["players"]) == 0: |
557 batch = 0 # add to the first batch of invitations | 557 batch = 0 # add to the first batch of invitations |
558 if user_jid not in self.invitations[room_jid][batch][1]: | 558 if user_jid not in self.invitations[room_jid][batch][1]: |
559 self.invitations[room_jid][batch][1].append(user_jid) | 559 self.invitations[room_jid][batch][1].append(user_jid) |
560 return True | 560 return True |
561 | 561 |
562 def _checkCreateGameAndInit(self, room_jid, profile): | 562 def _check_create_game_and_init(self, room_jid, profile): |
563 """Check if that profile can create the game. If the game can be created | 563 """Check if that profile can create the game. If the game can be created |
564 but is not initialized yet, this method will also do the initialization. | 564 but is not initialized yet, this method will also do the initialization. |
565 | 565 |
566 @param room_jid (jid.JID): JID of the room | 566 @param room_jid (jid.JID): JID of the room |
567 @param profile | 567 @param profile |
568 @return: a couple (create, sync) with: | 568 @return: a couple (create, sync) with: |
569 - create: set to True to allow the game creation | 569 - create: set to True to allow the game creation |
570 - sync: set to True to advice a game synchronization | 570 - sync: set to True to advice a game synchronization |
571 """ | 571 """ |
572 user_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid, profile) | 572 user_nick = self.host.plugins["XEP-0045"].get_room_nick(room_jid, profile) |
573 if not user_nick: | 573 if not user_nick: |
574 log.error( | 574 log.error( |
575 "Internal error: profile %s has not joined the room %s" | 575 "Internal error: profile %s has not joined the room %s" |
576 % (profile, room_jid.userhost()) | 576 % (profile, room_jid.userhost()) |
577 ) | 577 ) |
578 return False, False | 578 return False, False |
579 if self._gameExists(room_jid): | 579 if self._game_exists(room_jid): |
580 is_referee = self.isReferee(room_jid, user_nick) | 580 is_referee = self.is_referee(room_jid, user_nick) |
581 if self._gameExists(room_jid, started=True): | 581 if self._game_exists(room_jid, started=True): |
582 log.info( | 582 log.info( |
583 _("%(game)s game already created in room %(room)s") | 583 _("%(game)s game already created in room %(room)s") |
584 % {"game": self.name, "room": room_jid.userhost()} | 584 % {"game": self.name, "room": room_jid.userhost()} |
585 ) | 585 ) |
586 return False, is_referee | 586 return False, is_referee |
589 _("%(game)s game in room %(room)s can only be created by %(user)s") | 589 _("%(game)s game in room %(room)s can only be created by %(user)s") |
590 % {"game": self.name, "room": room_jid.userhost(), "user": user_nick} | 590 % {"game": self.name, "room": room_jid.userhost(), "user": user_nick} |
591 ) | 591 ) |
592 return False, False | 592 return False, False |
593 else: | 593 else: |
594 self._initGame(room_jid, user_nick) | 594 self._init_game(room_jid, user_nick) |
595 return True, False | 595 return True, False |
596 | 596 |
597 def _createGame(self, room_jid_s, nicks=None, profile_key=C.PROF_KEY_NONE): | 597 def _create_game(self, room_jid_s, nicks=None, profile_key=C.PROF_KEY_NONE): |
598 self.createGame(jid.JID(room_jid_s), nicks, profile_key) | 598 self.create_game(jid.JID(room_jid_s), nicks, profile_key) |
599 | 599 |
600 def createGame(self, room_jid, nicks=None, profile_key=C.PROF_KEY_NONE): | 600 def create_game(self, room_jid, nicks=None, profile_key=C.PROF_KEY_NONE): |
601 """Create a new game. | 601 """Create a new game. |
602 | 602 |
603 This can be called directly from a frontend and skips all the checks and invitation system, | 603 This can be called directly from a frontend and skips all the checks and invitation system, |
604 but the game must not exist and all the players must be in the room already. | 604 but the game must not exist and all the players must be in the room already. |
605 @param room_jid (jid.JID): JID of the room | 605 @param room_jid (jid.JID): JID of the room |
608 """ | 608 """ |
609 log.debug( | 609 log.debug( |
610 _("Creating %(game)s game in room %(room)s") | 610 _("Creating %(game)s game in room %(room)s") |
611 % {"game": self.name, "room": room_jid} | 611 % {"game": self.name, "room": room_jid} |
612 ) | 612 ) |
613 profile = self.host.memory.getProfileName(profile_key) | 613 profile = self.host.memory.get_profile_name(profile_key) |
614 if not profile: | 614 if not profile: |
615 log.error(_("profile %s is unknown") % profile_key) | 615 log.error(_("profile %s is unknown") % profile_key) |
616 return | 616 return |
617 (create, sync) = self._checkCreateGameAndInit(room_jid, profile) | 617 (create, sync) = self._check_create_game_and_init(room_jid, profile) |
618 if nicks is None: | 618 if nicks is None: |
619 nicks = [] | 619 nicks = [] |
620 if not create: | 620 if not create: |
621 if sync: | 621 if sync: |
622 self._updatePlayers(room_jid, nicks, True, profile) | 622 self._update_players(room_jid, nicks, True, profile) |
623 return | 623 return |
624 self.games[room_jid]["started"] = True | 624 self.games[room_jid]["started"] = True |
625 self._updatePlayers(room_jid, nicks, False, profile) | 625 self._update_players(room_jid, nicks, False, profile) |
626 if self.player_init: | 626 if self.player_init: |
627 # specific data to each player (score, private data) | 627 # specific data to each player (score, private data) |
628 self.games[room_jid].setdefault("players_data", {}) | 628 self.games[room_jid].setdefault("players_data", {}) |
629 for nick in nicks: | 629 for nick in nicks: |
630 # The dict must be COPIED otherwise it is shared between all users | 630 # The dict must be COPIED otherwise it is shared between all users |
631 self.games[room_jid]["players_data"][nick] = copy.deepcopy( | 631 self.games[room_jid]["players_data"][nick] = copy.deepcopy( |
632 self.player_init | 632 self.player_init |
633 ) | 633 ) |
634 | 634 |
635 def _playerReady(self, player_nick, referee_jid_s, profile_key=C.PROF_KEY_NONE): | 635 def _player_ready(self, player_nick, referee_jid_s, profile_key=C.PROF_KEY_NONE): |
636 self.playerReady(player_nick, jid.JID(referee_jid_s), profile_key) | 636 self.player_ready(player_nick, jid.JID(referee_jid_s), profile_key) |
637 | 637 |
638 def playerReady(self, player_nick, referee_jid, profile_key=C.PROF_KEY_NONE): | 638 def player_ready(self, player_nick, referee_jid, profile_key=C.PROF_KEY_NONE): |
639 """Must be called when player is ready to start a new game | 639 """Must be called when player is ready to start a new game |
640 | 640 |
641 @param player: the player nick in the room | 641 @param player: the player nick in the room |
642 @param referee_jid (jid.JID): JID of the referee | 642 @param referee_jid (jid.JID): JID of the referee |
643 """ | 643 """ |
644 profile = self.host.memory.getProfileName(profile_key) | 644 profile = self.host.memory.get_profile_name(profile_key) |
645 if not profile: | 645 if not profile: |
646 log.error(_("profile %s is unknown") % profile_key) | 646 log.error(_("profile %s is unknown") % profile_key) |
647 return | 647 return |
648 log.debug("new player ready: %s" % profile) | 648 log.debug("new player ready: %s" % profile) |
649 # TODO: we probably need to add the game and room names in the sent message | 649 # TODO: we probably need to add the game and room names in the sent message |
650 self.send(referee_jid, "player_ready", {"player": player_nick}, profile=profile) | 650 self.send(referee_jid, "player_ready", {"player": player_nick}, profile=profile) |
651 | 651 |
652 def newRound(self, room_jid, data, profile): | 652 def new_round(self, room_jid, data, profile): |
653 """Launch a new round (reinit the user data) | 653 """Launch a new round (reinit the user data) |
654 | 654 |
655 @param room_jid: room userhost | 655 @param room_jid: room userhost |
656 @param data: a couple (common_data, msg_elts) with: | 656 @param data: a couple (common_data, msg_elts) with: |
657 - common_data: backend initialization data for the new round | 657 - common_data: backend initialization data for the new round |
679 self.send(room_jid, msg_elts, profile=profile) | 679 self.send(room_jid, msg_elts, profile=profile) |
680 if common_data is not None: | 680 if common_data is not None: |
681 for player in players: | 681 for player in players: |
682 players_data[player].update(copy.deepcopy(common_data)) | 682 players_data[player].update(copy.deepcopy(common_data)) |
683 | 683 |
684 def _createGameElt(self, to_jid): | 684 def _create_game_elt(self, to_jid): |
685 """Create a generic domish Element for the game messages | 685 """Create a generic domish Element for the game messages |
686 | 686 |
687 @param to_jid: JID of the recipient | 687 @param to_jid: JID of the recipient |
688 @return: the created element | 688 @return: the created element |
689 """ | 689 """ |
692 elt["to"] = to_jid.full() | 692 elt["to"] = to_jid.full() |
693 elt["type"] = type_ | 693 elt["type"] = type_ |
694 elt.addElement(self.ns_tag) | 694 elt.addElement(self.ns_tag) |
695 return elt | 695 return elt |
696 | 696 |
697 def _createStartElement(self, players=None, name="started"): | 697 def _create_start_element(self, players=None, name="started"): |
698 """Create a domish Element listing the game users | 698 """Create a domish Element listing the game users |
699 | 699 |
700 @param players: list of the players | 700 @param players: list of the players |
701 @param name: element name: | 701 @param name: element name: |
702 - "started" to signal the players that the game has been started | 702 - "started" to signal the players that the game has been started |
713 player_elt["index"] = str(idx) | 713 player_elt["index"] = str(idx) |
714 idx += 1 | 714 idx += 1 |
715 started_elt.addChild(player_elt) | 715 started_elt.addChild(player_elt) |
716 return started_elt | 716 return started_elt |
717 | 717 |
718 def _sendElements(self, to_jid, data, profile=None): | 718 def _send_elements(self, to_jid, data, profile=None): |
719 """ TODO | 719 """ TODO |
720 | 720 |
721 @param to_jid: recipient JID | 721 @param to_jid: recipient JID |
722 @param data: list of (elem, attr, content) with: | 722 @param data: list of (elem, attr, content) with: |
723 - elem: domish.Element, unicode or a couple: | 723 - elem: domish.Element, unicode or a couple: |
727 - attrs: dictionary of attributes for the new child | 727 - attrs: dictionary of attributes for the new child |
728 - content: unicode that is appended to the child content | 728 - content: unicode that is appended to the child content |
729 @param profile: the profile from which the message is sent | 729 @param profile: the profile from which the message is sent |
730 @return: a Deferred instance | 730 @return: a Deferred instance |
731 """ | 731 """ |
732 client = self.host.getClient(profile) | 732 client = self.host.get_client(profile) |
733 msg = self._createGameElt(to_jid) | 733 msg = self._create_game_elt(to_jid) |
734 for elem, attrs, content in data: | 734 for elem, attrs, content in data: |
735 if elem is not None: | 735 if elem is not None: |
736 if isinstance(elem, domish.Element): | 736 if isinstance(elem, domish.Element): |
737 msg.firstChildElement().addChild(elem) | 737 msg.firstChildElement().addChild(elem) |
738 else: | 738 else: |
755 @param attrs: dictionary of attributes for the new child | 755 @param attrs: dictionary of attributes for the new child |
756 @param content: unicode that is appended to the child content | 756 @param content: unicode that is appended to the child content |
757 @param profile: the profile from which the message is sent | 757 @param profile: the profile from which the message is sent |
758 @return: a Deferred instance | 758 @return: a Deferred instance |
759 """ | 759 """ |
760 return self._sendElements(to_jid, [(elem, attrs, content)], profile) | 760 return self._send_elements(to_jid, [(elem, attrs, content)], profile) |
761 | 761 |
762 def getHandler(self, client): | 762 def get_handler(self, client): |
763 return RoomGameHandler(self) | 763 return RoomGameHandler(self) |
764 | 764 |
765 | 765 |
766 @implementer(iwokkel.IDisco) | 766 @implementer(iwokkel.IDisco) |
767 class RoomGameHandler(XMPPHandler): | 767 class RoomGameHandler(XMPPHandler): |