comparison src/tools/plugins/games.py @ 717:358018c5c398

plugins (games): more factorization and flexibility for launching and joining games: - "MUC user joined", "MUC user left" and class XMPPHandler are managed directly in RoomGame - renamed __init__ parameters 'player_init_data' to 'player_init' and 'options' to 'game_init' - pass the players list in radiocol method 'createGame' and signal 'radiocolStarted' (needed for invitation system and for UI players identification) - added some parameters to manage who can invite, who can join, who to wait for... managed with check***Auth methods - joining a game that is already launched may be possible, regarding these parameters and the invitation list - leave and join a game again is partly managed: new tarot round is launched, we should keep playing the same round instead
author souliane <souliane@mailoo.org>
date Thu, 21 Nov 2013 15:49:53 +0100
parents ecc5a5b34ee1
children
comparison
equal deleted inserted replaced
716:30eb49e4e05d 717:358018c5c398
19 19
20 from logging import debug, warning, error 20 from logging import debug, warning, error
21 from twisted.words.protocols.jabber.jid import JID 21 from twisted.words.protocols.jabber.jid import JID
22 from twisted.words.xish import domish 22 from twisted.words.xish import domish
23 from time import time 23 from time import time
24 """This library help manage general games (e.g. card games) and it can be used by plugins""" 24 from wokkel import disco, iwokkel
25 from zope.interface import implements
26 try:
27 from twisted.words.protocols.xmlstream import XMPPHandler
28 except ImportError:
29 from wokkel.subprotocols import XMPPHandler
30
31
32 """This library help manage general games (e.g. card games) and it can be used by plugins."""
33
34 # Don't forget to set it to False before you commit
35 debugMsg = True
36 debugFile = True
25 37
26 38
27 class RoomGame(object): 39 class RoomGame(object):
28 """This class is used to help launching a MUC game.""" 40 """This class is used to help launching a MUC game."""
29 41
30 def __init__(self, host, plugin_info, ns_tag, player_init_data={}, options={}): 42 # Values for self.invite_mode (who can invite after the game creation)
43 FROM_ALL, FROM_NONE, FROM_REFEREE, FROM_PLAYERS = xrange(0, 4)
44 # Values for self.wait_mode (for who we should wait before creating the game)
45 FOR_ALL, FOR_NONE = xrange(0, 2)
46 # Values for self.join_mode (who can join the game - NONE means solo game)
47 ALL, INVITED, NONE = xrange(0, 3)
48 # Values for ready_mode (how to turn a MUC user into a player)
49 ASK, FORCE = xrange(0, 2)
50
51 MESSAGE = '/message'
52 REQUEST = '%s/%s[@xmlns="%s"]'
53
54 def __init__(self, host, plugin_info, ns_tag, game_init={}, player_init={}):
31 """ 55 """
32 @param host 56 @param host
33 @param plugin_info: PLUGIN_INFO map of the game plugin 57 @param plugin_info: PLUGIN_INFO map of the game plugin
34 @ns_tag: couple (nameservice, tag) to construct the messages 58 @ns_tag: couple (nameservice, tag) to construct the messages
35 @param player_init_data: dictionary for initialization data, applicable to each player 59 @param game_init: dictionary for general game initialization
36 @param options: dictionary for game options 60 @param player_init: dictionary for player initialization, applicable to each player
37 """ 61 """
38 self.host = host 62 self.host = host
39 self.name = plugin_info["import_name"] 63 self.name = plugin_info["import_name"]
40 self.ns_tag = ns_tag 64 self.ns_tag = ns_tag
41 self.player_init_data = player_init_data 65 self.request = self.REQUEST % (self.MESSAGE, ns_tag[1], ns_tag[0])
42 self.collectiveGame = self.player_init_data == {} 66 self.game_init = game_init
43 self.options = options 67 self.player_init = player_init
44 self.games = {} 68 self.games = {}
45 self.waiting_inv = {} # Invitation waiting for people to join to launch a game 69 self.invitations = {} # list of couple (x, y) with x the time and y a list of users
70
71 # These are the default settings, which can be overwritten by child class after initialization
72 self.invite_mode = self.FROM_PLAYERS if self.player_init == {} else self.FROM_NONE
73 self.wait_mode = self.FOR_NONE if self.player_init == {} else self.FOR_ALL
74 self.join_mode = self.INVITED
75 self.ready_mode = self.FORCE # TODO: asking for confirmation is not implemented
76
77 host.trigger.add("MUC user joined", self.userJoinedTrigger)
78 host.trigger.add("MUC user left", self.userLeftTrigger)
79
80 def createOrInvite(self, room, other_players, profile):
81 """
82 This is called only when someone explicitly wants to play.
83 The game must not be created if one already exists in the room,
84 or its creation could be postponed until all the expected players
85 join the room (in that case it will be created from userJoinedTrigger).
86 @param room: instance of wokkel.muc.Room
87 @param other_players: list for other players JID userhosts
88 """
89 user_jid = self.host.getJidNStream(profile)[0]
90 room_jid_s = room.occupantJID.userhost()
91 nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid_s, profile)
92 nicks = [nick]
93 if self.gameExists(room_jid_s):
94 if not self.checkJoinAuth(room_jid_s, user_jid.userhost(), nick):
95 return
96 nicks.extend(self.invitePlayers(room, other_players, nick, profile))
97 self.updatePlayers(room_jid_s, nicks, profile)
98 else:
99 self.initGame(room_jid_s, nick)
100 (auth, waiting, missing) = self.checkWaitAuth(room, other_players)
101 nicks.extend(waiting)
102 nicks.extend(self.invitePlayers(room, missing, nick, profile))
103 if auth:
104 self.createGame(room_jid_s, nicks, profile)
105 else:
106 self.updatePlayers(room_jid_s, nicks, profile)
107
108 def initGame(self, room_jid_s, referee_nick):
109 """Important: do not add the referee to 'players' yet. For a
110 <players /> message to be emitted whenever a new player is joining,
111 it is necessary to not modify 'players' outside of updatePlayers.
112 """
113 referee = room_jid_s + '/' + referee_nick
114 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False}
115 self.games[room_jid_s].update(self.game_init)
116
117 def gameExists(self, room_jid_s, started=False):
118 """Return True if a game has been initialized/started.
119 @param started: if False, the game must be initialized only,
120 otherwise it must be initialized and started with createGame.
121 @return: True if a game is initialized/started in that room"""
122 return room_jid_s in self.games and (not started or self.games[room_jid_s]['started'])
123
124 def checkJoinAuth(self, room_jid_s, user_jid_s=None, nick="", verbose=False):
125 """Checks if this profile is allowed to join the game.
126 The parameter nick is used to check if the user is already
127 a player in that game. When this method is called from
128 userJoinedTrigger, nick is also used to check the user
129 identity instead of user_jid_s (see TODO remark below).
130 @param room_jid_s: the room hosting the game
131 @param user_jid_s: JID userhost of the user
132 @param nick: nick of the user
133 """
134 auth = False
135 if not self.gameExists(room_jid_s):
136 auth = False
137 elif self.join_mode == self.ALL or self.isPlayer(room_jid_s, nick):
138 auth = True
139 elif self.join_mode == self.INVITED:
140 # considering all the batches of invitations
141 for invitations in self.invitations[room_jid_s]:
142 if user_jid_s is not None:
143 if user_jid_s in invitations[1]:
144 auth = True
145 break
146 else:
147 # TODO: that's not secure enough but what to do if
148 # wokkel.muc.User's 'entity' attribute is not set?!
149 if nick in [JID(invited).user for invited in invitations[1]]:
150 auth = True
151 break
152
153 if not auth and (verbose or debugMsg):
154 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s))
155 return auth
156
157 def updatePlayers(self, room_jid_s, nicks, profile):
158 """Signal to the room or to each player that some players joined the game"""
159 if nicks == []:
160 return
161 new_nicks = set(nicks).difference(self.games[room_jid_s]['players'])
162 if len(new_nicks) == 0:
163 return
164 self.games[room_jid_s]['players'].extend(new_nicks)
165 self.signalPlayers(room_jid_s, [JID(room_jid_s)], profile)
166
167 def signalPlayers(self, room_jid_s, recipients, profile):
168 """Let these guys know that we are playing (they may not play themselves)."""
169 if self.gameExists(room_jid_s, started=True):
170 element = self.createStartElement(self.games[room_jid_s]['players'])
171 else:
172 element = self.createStartElement(self.games[room_jid_s]['players'], name="players")
173 for recipient in recipients:
174 self.send(recipient, element, profile=profile)
175
176 def invitePlayers(self, room, other_players, nick, profile):
177 """Invite players to a room, associated game may exist or not.
178 @param room: wokkel.muc.Room instance
179 @param other_players: list of JID userhosts to invite
180 @param nick: nick of the user who send the invitation
181 @return: list of the invited players who were already in the room
182 """
183 room_jid = room.occupantJID.userhostJID()
184 room_jid_s = room.occupantJID.userhost()
185 if not self.checkInviteAuth(room_jid_s, nick):
186 return []
187 self.invitations.setdefault(room_jid_s, [])
188 # TODO: remove invitation waiting for too long, using the time data
189 self.invitations[room_jid_s].append((time(), other_players))
190 nicks = [nick]
191 for player_jid in [JID(player) for player in other_players]:
192 # TODO: find a way to make it secure
193 other_nick = self.host.plugins["XEP-0045"].getRoomNickOfUser(room, player_jid, secure=False)
194 if other_nick is None:
195 self.host.plugins["XEP-0249"].invite(player_jid, room_jid, {"game": self.name}, profile)
196 else:
197 nicks.append(other_nick)
198 return nicks
199
200 def checkInviteAuth(self, room_jid_s, nick, verbose=False):
201 """Checks if this profile is allowed to invite players"""
202 auth = False
203 if self.invite_mode == self.FROM_ALL or not self.gameExists(room_jid_s):
204 auth = True
205 elif self.invite_mode == self.FROM_NONE:
206 auth = not self.gameExists(room_jid_s, started=True)
207 elif self.invite_mode == self.FROM_REFEREE:
208 auth = self.isReferee(room_jid_s, nick)
209 elif self.invite_mode == self.FROM_PLAYERS:
210 auth = self.isPlayer(room_jid_s, nick)
211 if not auth and (verbose or debugMsg):
212 debug(_("%s not allowed to invite for the game %s in %s") % (nick, self.name, room_jid_s))
213 return auth
214
215 def isReferee(self, room_jid_s, nick):
216 """Checks if the player with this nick is the referee for the game in this room"""
217 if not self.gameExists(room_jid_s):
218 return False
219 return room_jid_s + '/' + nick == self.games[room_jid_s]['referee']
220
221 def isPlayer(self, room_jid_s, nick):
222 """Checks if the player with this nick is a player for the game in this room.
223 Important: the referee is not in the 'players' list right after the game
224 initialization - check with isReferee to be sure nick is not a player.
225 """
226 if not self.gameExists(room_jid_s):
227 return False
228 return nick in self.games[room_jid_s]['players'] or self.isReferee(room_jid_s, nick)
229
230 def checkWaitAuth(self, room, other_players, verbose=False):
231 """Check if we must wait before starting the game or not.
232 @return: (x, y, z) with:
233 x: False if we must wait, True otherwise
234 y: the nicks of the players that have been checked and confirmed
235 z: the players that have not been checked or that are missing
236 """
237 if self.wait_mode == self.FOR_NONE or other_players == []:
238 result = (True, [], other_players)
239 elif len(room.roster) < len(other_players) + 1:
240 result = (False, [], other_players)
241 else:
242 # TODO: find a way to make it secure
243 (nicks, missing) = self.host.plugins["XEP-0045"].getRoomNicksOfUsers(room, other_players, secure=False)
244 result = (len(nicks) == len(other_players), nicks, missing)
245 if not result[0] and (verbose or debugMsg):
246 debug(_("Still waiting for %s before starting the game %s in %s") % (result[2], self.name, room.occupantJID.userhost()))
247 return result
46 248
47 def getUniqueName(self, muc_service="", profile_key='@DEFAULT@'): 249 def getUniqueName(self, muc_service="", profile_key='@DEFAULT@'):
48 room = self.host.plugins["XEP-0045"].getUniqueName(muc_service, profile_key=profile_key) 250 room = self.host.plugins["XEP-0045"].getUniqueName(muc_service, profile_key=profile_key)
49 return "sat_%s_%s" % (self.name.lower(), room) if room != "" else "" 251 return "sat_%s_%s" % (self.name.lower(), room) if room != "" else ""
50 252
51 def prepareRoom(self, other_players, room_jid=None, profile_key='@NONE@'): 253 def prepareRoom(self, other_players=[], room_jid=None, profile_key='@NONE@'):
52 """Prepare the room for a game: create it and invite players. 254 """Prepare the room for a game: create it and invite players.
53 @param other_players: list for other players JID userhosts 255 @param other_players: list for other players JID userhosts
54 @param room_jid: JID of the room to reuse or None to create a new room 256 @param room_jid: JID userhost of the room to reuse or None to create a new room
55 """ 257 """
56 debug(_('Preparing room for %s game') % self.name) 258 debug(_('Preparing room for %s game') % self.name)
57 profile = self.host.memory.getProfileName(profile_key) 259 profile = self.host.memory.getProfileName(profile_key)
58 if not profile: 260 if not profile:
59 error(_("Unknown profile")) 261 error(_("Unknown profile"))
60 return 262 return
61 _jid, xmlstream = self.host.getJidNStream(profile)
62 if other_players is None:
63 other_players = []
64 players = other_players[:]
65 players.append(_jid.userhost())
66 263
67 def roomJoined(room): 264 def roomJoined(room):
68 """@param room: instance of wokkel.muc.Room""" 265 """@param room: instance of wokkel.muc.Room"""
69 _room = room.occupantJID.userhostJID() 266 self.createOrInvite(room, other_players, profile)
70 if self.collectiveGame is True or other_players == [] and _jid in [user.entity for user in room.roster.values()]: 267
71 self.createGame(_room.userhost(), [] if self.collectiveGame is True else players, profile_key=profile) 268 def afterClientInit(room_jid):
72 else: 269 """Create/join the given room, or a unique generated one if no room is specified.
73 self.waiting_inv[_room] = (time(), players) # TODO: remove invitation waiting for too long, using the time data 270 @param room_jid: room to join
74 for player in other_players: 271 """
75 self.host.plugins["XEP-0249"].invite(JID(player), room.occupantJID.userhostJID(), {"game": self.name}, profile) 272 if room_jid is not None and room_jid != "": # a room name has been specified
76
77 def after_init(room_jid):
78 if room_jid is not None and room_jid != "":
79 # a room name has been specified...
80 if room_jid in self.host.plugins["XEP-0045"].clients[profile].joined_rooms: 273 if room_jid in self.host.plugins["XEP-0045"].clients[profile].joined_rooms:
81 # and we're already in
82 roomJoined(self.host.plugins["XEP-0045"].clients[profile].joined_rooms[room_jid]) 274 roomJoined(self.host.plugins["XEP-0045"].clients[profile].joined_rooms[room_jid])
83 return 275 return
84 else: 276 else:
85 room_jid = self.getUniqueName(profile_key=profile_key) 277 room_jid = self.getUniqueName(profile_key=profile_key)
86 if room_jid == "": 278 if room_jid == "":
87 return 279 return
88 d = self.host.plugins["XEP-0045"].join(JID(room_jid), _jid.user, {}, profile) 280 user_jid = self.host.getJidNStream(profile)[0]
281 d = self.host.plugins["XEP-0045"].join(JID(room_jid), user_jid.user, {}, profile)
89 d.addCallback(roomJoined) 282 d.addCallback(roomJoined)
90 283
91 client = self.host.getClient(profile) 284 client = self.host.getClient(profile)
92 if not client: 285 if not client:
93 error(_('No client for this profile key: %s') % profile_key) 286 error(_('No client for this profile key: %s') % profile_key)
94 return 287 return
95 client.client_initialized.addCallback(lambda ignore: after_init(room_jid)) 288 client.client_initialized.addCallback(lambda ignore: afterClientInit(room_jid))
96 289
97 def userJoinedTrigger(self, room, user, profile): 290 def userJoinedTrigger(self, room, user, profile):
98 """This trigger is used to check if we are waiting for people in this room, 291 """This trigger is used to check if the new user can take part of a game,
99 and to create a game if everybody is here. 292 create the game if we were waiting for him or just update the players list.
100 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} 293 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User}
101 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID 294 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID
102 """ 295 @return: True to not interrupt the main process.
103 _room_jid = room.occupantJID.userhostJID() 296 """
104 if self.collectiveGame is True: 297 room_jid_s = room.occupantJID.userhost()
105 room_s = _room_jid.userhost() 298 profile_nick = room.occupantJID.resource
106 if room_s in self.games and self.games[room_s]["referee"] == room.occupantJID.full(): 299 if not self.isReferee(room_jid_s, profile_nick):
107 #we are in a radiocol room, let's start the party ! 300 return True # profile is not the referee
108 self.send(JID(room_s + '/' + user.nick), self.createStartElement(), profile=profile) 301 if not self.checkJoinAuth(room_jid_s, nick=user.nick):
302 # user not allowed but let him know that we are playing :p
303 self.signalPlayers(room_jid_s, [JID(room_jid_s + '/' + user.nick)], profile)
109 return True 304 return True
110 if _room_jid in self.waiting_inv and len(room.roster) >= len(self.waiting_inv[_room_jid][1]): 305 if self.wait_mode == self.FOR_ALL:
111 expected_players = self.waiting_inv[_room_jid][1] 306 # considering the last batch of invitations
112 players = [] 307 batch = len(self.invitations[room_jid_s]) - 1
113 for player in expected_players: 308 if batch < 0:
114 for user in room.roster.values(): 309 error("Invitations from %s to play %s in %s have been lost!" % (profile_nick, self.name, room_jid_s))
115 if user.entity is not None:
116 # check people identity
117 if user.entity.userhost() == player:
118 players.append(user.nick)
119 continue
120 else:
121 # TODO: how to check the identity with only a nickname??
122 if user.nick == JID(player).user:
123 players.append(user.nick)
124 if len(players) < len(expected_players):
125 # Someone here was not invited! He can stay but he doesn't play :p
126 return True 310 return True
127 # When we have all people in the room, we create the game 311 other_players = self.invitations[room_jid_s][batch][1]
128 del self.waiting_inv[_room_jid] 312 (auth, nicks, dummy) = self.checkWaitAuth(room, other_players)
129 self.createGame(_room_jid.userhost(), players, profile_key=profile) 313 if auth:
314 del self.invitations[room_jid_s][batch]
315 nicks.insert(0, profile_nick) # add the referee
316 self.createGame(room_jid_s, nicks, profile_key=profile)
317 return True
318 # let the room know that a new player joined
319 self.updatePlayers(room_jid_s, [user.nick], profile)
130 return True 320 return True
131 321
132 def createGame(self, room_jid, players=[], profile_key='@NONE@'): 322 def userLeftTrigger(self, room, user, profile):
133 """Create a new game 323 """This trigger is used to update or stop the game when a user leaves.
134 @param room_jid: jid of the room 324 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User}
135 @param players: list of players nick (nick must exist in the room) 325 @user: wokkel.muc.User object. user.nick is a unicode and user.entity a JID
326 @return: True to not interrupt the main process.
327 """
328 room_jid_s = room.occupantJID.userhost()
329 profile_nick = room.occupantJID.resource
330 if not self.isReferee(room_jid_s, profile_nick):
331 return True # profile is not the referee
332 if self.isPlayer(room_jid_s, user.nick):
333 try:
334 self.games[room_jid_s]['players'].remove(user.nick)
335 except ValueError:
336 pass
337 if self.wait_mode == self.FOR_ALL:
338 # allow this user to join the game again
339 user_jid = user.entity.userhost()
340 if len(self.invitations[room_jid_s]) == 0:
341 self.invitations[room_jid_s].append((time(), [user_jid]))
342 else:
343 batch = 0 # add to the first batch of invitations
344 if user_jid not in self.invitations[room_jid_s][batch][1]:
345 self.invitations[room_jid_s][batch][1].append(user_jid)
346 return True
347
348 def checkCreateGameAndInit(self, room_jid_s, profile):
349 """Check if that profile can create the game. If the game can be created
350 but is not initialized yet, this method will also do the initialization
351 @return: a couple (create, sync) with:
352 - create: set to True to allow the game creation
353 - sync: set to True to advice a game synchronization
354 """
355 user_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid_s, profile)
356 if not user_nick:
357 error('Internal error')
358 return False, False
359 if self.gameExists(room_jid_s):
360 referee = self.isReferee(room_jid_s, user_nick)
361 if self.gameExists(room_jid_s, started=True):
362 warning(_("%s game already created in room %s") % (self.name, room_jid_s))
363 return False, referee
364 elif not referee:
365 warning(_("%s game in room %s can only be created by %s") % (self.name, room_jid_s, user_nick))
366 return False, False
367 else:
368 self.initGame(room_jid_s, user_nick)
369 return True, False
370
371 def createGame(self, room_jid_s, nicks=[], profile_key='@NONE@'):
372 """Create a new game - this can be called directly from a frontend
373 and skips all the checks and invitation system, but the game must
374 not exist and all the players must be in the room already.
375 @param room_jid: JID userhost of the room
376 @param nicks: list of players nicks in the room
136 @param profile_key: %(doc_profile_key)s""" 377 @param profile_key: %(doc_profile_key)s"""
137 debug(_("Creating %s game") % self.name) 378 debug(_("Creating %s game in room %s") % (self.name, room_jid_s))
138 room = JID(room_jid).userhost()
139 profile = self.host.memory.getProfileName(profile_key) 379 profile = self.host.memory.getProfileName(profile_key)
140 if not profile: 380 if not profile:
141 error(_("profile %s is unknown") % profile_key) 381 error(_("profile %s is unknown") % profile_key)
142 return 382 return
143 room_nick = self.host.plugins["XEP-0045"].getRoomNick(room, profile) 383 (create, sync) = self.checkCreateGameAndInit(room_jid_s, profile)
144 if not room_nick: 384 if not create:
145 error('Internal error') 385 if sync:
146 return 386 debug(_('Synchronize game %s in %s for %s') % (self.name, room_jid_s, ', '.join(nicks)))
147 referee = room + '/' + room_nick 387 # TODO: we should call a method to re-send the information to a player who left
148 if room in self.games: 388 # and joined the room again, currently: we may restart a whole new round...
149 warning(_("%s game already started in room %s") % (self.name, room)) 389 self.updatePlayers(room_jid_s, nicks, profile)
150 return 390 return
151 self.games[room] = {'referee': referee} 391 self.games[room_jid_s]['started'] = True
152 self.games[room].update(self.options) 392 self.updatePlayers(room_jid_s, nicks, profile)
153 if self.collectiveGame is True: 393 if self.player_init == {}:
154 self.send(JID(room), self.createStartElement(), profile=profile) 394 return
155 return 395 # specific data to each player
156 # non collaborative game = individual data and messages
157 status = {} 396 status = {}
158 players_data = {} 397 players_data = {}
159 for player in players: 398 for nick in nicks:
160 # The dict must be COPIED otherwise it is shared between all users 399 # The dict must be COPIED otherwise it is shared between all users
161 players_data[player] = self.player_init_data.copy() 400 players_data[nick] = self.player_init.copy()
162 status[player] = "init" 401 status[nick] = "init"
163 # each player send a message to all the others 402 self.games[room_jid_s].update({'status': status, 'players_data': players_data})
164 self.send(JID(room + '/' + player), self.createStartElement(players), profile=profile)
165 # specific data to each player
166 self.games[room].update({'players': players, 'status': status, 'players_data': players_data})
167
168 def createCollectiveGame(self, room_jid, profile_key='@NONE@'):
169 return self.createGame(self, room_jid, players=[], profile_key=profile_key)
170 403
171 def playerReady(self, player, referee, profile_key='@NONE@'): 404 def playerReady(self, player, referee, profile_key='@NONE@'):
172 """Must be called when player is ready to start a new game""" 405 """Must be called when player is ready to start a new game"""
173 profile = self.host.memory.getProfileName(profile_key) 406 profile = self.host.memory.getProfileName(profile_key)
174 if not profile: 407 if not profile:
205 elt["to"] = to_jid.full() 438 elt["to"] = to_jid.full()
206 elt["type"] = type_ 439 elt["type"] = type_
207 elt.addElement(self.ns_tag) 440 elt.addElement(self.ns_tag)
208 return elt 441 return elt
209 442
210 def createStartElement(self, players=None): 443 def createStartElement(self, players=None, name="started"):
211 """Create a game "started" domish Element""" 444 """Create a game "started" domish Element
212 started_elt = domish.Element((None, 'started')) 445 @param name: element name (default: "started").
446 """
447 started_elt = domish.Element((None, name))
213 if players is None: 448 if players is None:
214 return started_elt 449 return started_elt
215 idx = 0 450 idx = 0
216 for player in players: 451 for player in players:
217 player_elt = domish.Element((None, 'player')) 452 player_elt = domish.Element((None, 'player'))
244 if attrs is not None: 479 if attrs is not None:
245 elem.attributes.update(attrs) 480 elem.attributes.update(attrs)
246 if content is not None: 481 if content is not None:
247 elem.addContent(content) 482 elem.addContent(content)
248 self.host.profiles[profile].xmlstream.send(msg) 483 self.host.profiles[profile].xmlstream.send(msg)
484
485 if debugFile:
486 # From here you will see all the game messages
487 file_ = open("/tmp/test", "a")
488 file_.write("%s from %s to %s: %s\n" % (self.name, profile, "room" if to_jid.resource is None else to_jid.resource, elem.toXml()))
489 file_.close()
490
491 def getHandler(self, profile):
492 return RoomGameHandler(self)
493
494
495 class RoomGameHandler (XMPPHandler):
496 implements(iwokkel.IDisco)
497
498 def __init__(self, plugin_parent):
499 self.plugin_parent = plugin_parent
500 self.host = plugin_parent.host
501
502 def connectionInitialized(self):
503 self.xmlstream.addObserver(self.plugin_parent.request, self.plugin_parent.room_game_cmd, profile=self.parent.profile)
504
505 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
506 return [disco.DiscoFeature(self.plugin_parent.ns_tag[0])]
507
508 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
509 return []