comparison src/plugins/plugin_misc_room_game.py @ 746:539f278bc265

plugin room_games, radiocol: send the current queue to new players
author souliane <souliane@mailoo.org>
date Thu, 28 Nov 2013 19:23:59 +0100
parents 074970227bc0
children bfabeedbf32e
comparison
equal deleted inserted replaced
745:812dc38c0094 746:539f278bc265
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 from wokkel import disco, iwokkel 24 from wokkel import disco, iwokkel
25 from zope.interface import implements 25 from zope.interface import implements
26 import copy
26 try: 27 try:
27 from twisted.words.protocols.xmlstream import XMPPHandler 28 from twisted.words.protocols.xmlstream import XMPPHandler
28 except ImportError: 29 except ImportError:
29 from wokkel.subprotocols import XMPPHandler 30 from wokkel.subprotocols import XMPPHandler
30 31
31 # Don't forget to set it to False before you commit 32 # Don't forget to set it to False before you commit
32 _DEBUG = False 33 _DEBUG = False
33 _DEBUG_FILE = False
34 34
35 PLUGIN_INFO = { 35 PLUGIN_INFO = {
36 "name": "Room game", 36 "name": "Room game",
37 "import_name": "ROOM-GAME", 37 "import_name": "ROOM-GAME",
38 "type": "MISC", 38 "type": "MISC",
121 <players /> message to be emitted whenever a new player is joining, 121 <players /> message to be emitted whenever a new player is joining,
122 it is necessary to not modify 'players' outside of updatePlayers. 122 it is necessary to not modify 'players' outside of updatePlayers.
123 """ 123 """
124 referee = room_jid_s + '/' + referee_nick 124 referee = room_jid_s + '/' + referee_nick
125 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False} 125 self.games[room_jid_s] = {'referee': referee, 'players': [], 'started': False}
126 self.games[room_jid_s].update(self.game_init) 126 self.games[room_jid_s].update(copy.deepcopy(self.game_init))
127 127
128 def gameExists(self, room_jid_s, started=False): 128 def gameExists(self, room_jid_s, started=False):
129 """Return True if a game has been initialized/started. 129 """Return True if a game has been initialized/started.
130 @param started: if False, the game must be initialized only, 130 @param started: if False, the game must be initialized only,
131 otherwise it must be initialized and started with createGame. 131 otherwise it must be initialized and started with createGame.
164 if not auth and (verbose or _DEBUG): 164 if not auth and (verbose or _DEBUG):
165 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) 165 debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s))
166 return auth 166 return auth
167 167
168 def updatePlayers(self, room_jid_s, nicks, profile): 168 def updatePlayers(self, room_jid_s, nicks, profile):
169 """Signal to the room or to each player that some players joined the game""" 169 """Signal to the room that some players joined the game"""
170 if nicks == []: 170 if nicks == []:
171 return 171 return
172 new_nicks = set(nicks).difference(self.games[room_jid_s]['players']) 172 new_nicks = set(nicks).difference(self.games[room_jid_s]['players'])
173 if len(new_nicks) == 0: 173 if len(new_nicks) == 0:
174 return 174 return
179 """Let these guys know that we are playing (they may not play themselves).""" 179 """Let these guys know that we are playing (they may not play themselves)."""
180 if self.gameExists(room_jid_s, started=True): 180 if self.gameExists(room_jid_s, started=True):
181 element = self.createStartElement(self.games[room_jid_s]['players']) 181 element = self.createStartElement(self.games[room_jid_s]['players'])
182 else: 182 else:
183 element = self.createStartElement(self.games[room_jid_s]['players'], name="players") 183 element = self.createStartElement(self.games[room_jid_s]['players'], name="players")
184 elements = [(element, None, None)]
185 for child in self.getSyncData(room_jid_s):
186 # TODO: sync data may be different and private to each player,
187 # in that case send a separate message to the new players
188 elements.append((child, None, None))
184 for recipient in recipients: 189 for recipient in recipients:
185 self.send(recipient, element, profile=profile) 190 self.sendElements(recipient, elements, profile=profile)
191
192 def getSyncData(self, room_jid_s):
193 """This method may be overwritten by any child class.
194 @return: a list of child elements to be added for the game to be synchronized.
195 """
196 return []
186 197
187 def invitePlayers(self, room, other_players, nick, profile): 198 def invitePlayers(self, room, other_players, nick, profile):
188 """Invite players to a room, associated game may exist or not. 199 """Invite players to a room, associated game may exist or not.
189 @param room: wokkel.muc.Room instance 200 @param room: wokkel.muc.Room instance
190 @param other_players: list of JID userhosts to invite 201 @param other_players: list of JID userhosts to invite
406 # specific data to each player 417 # specific data to each player
407 status = {} 418 status = {}
408 players_data = {} 419 players_data = {}
409 for nick in nicks: 420 for nick in nicks:
410 # The dict must be COPIED otherwise it is shared between all users 421 # The dict must be COPIED otherwise it is shared between all users
411 players_data[nick] = self.player_init.copy() 422 players_data[nick] = copy.deepcopy(self.player_init)
412 status[nick] = "init" 423 status[nick] = "init"
413 self.games[room_jid_s].update({'status': status, 'players_data': players_data}) 424 self.games[room_jid_s].update({'status': status, 'players_data': players_data})
414 425
415 def playerReady(self, player, referee, profile_key='@NONE@'): 426 def playerReady(self, player, referee, profile_key='@NONE@'):
416 """Must be called when player is ready to start a new game""" 427 """Must be called when player is ready to start a new game"""
427 game_data = self.games[room_jid.userhost()] 438 game_data = self.games[room_jid.userhost()]
428 players = game_data['players'] 439 players = game_data['players']
429 players_data = game_data['players_data'] 440 players_data = game_data['players_data']
430 game_data['stage'] = "init" 441 game_data['stage'] = "init"
431 442
432 common_data, msg_elts = data if data is not None else (None, None) 443 common_data, msg_elts = copy.deepcopy(data) if data is not None else (None, None)
433 444
434 if isinstance(msg_elts, dict): 445 if isinstance(msg_elts, dict):
435 for player in players: 446 for player in players:
436 to_jid = JID(room_jid.userhost() + "/" + player) # FIXME: gof: 447 to_jid = JID(room_jid.userhost() + "/" + player) # FIXME: gof:
437 elem = msg_elts[player] if isinstance(msg_elts[player], domish.Element) else None 448 elem = msg_elts[player] if isinstance(msg_elts[player], domish.Element) else None
465 player_elt['index'] = str(idx) 476 player_elt['index'] = str(idx)
466 idx += 1 477 idx += 1
467 started_elt.addChild(player_elt) 478 started_elt.addChild(player_elt)
468 return started_elt 479 return started_elt
469 480
481 def sendElements(self, to_jid, data, profile=None):
482 """
483 @param to_jid: recipient JID
484 @param data: list of (elem, attr, content) with:
485 - elem: domish.Element, unicode or a couple:
486 - domish.Element to be directly added as a child to the message
487 - unicode name or couple (uri, name) to create a new domish.Element
488 and add it as a child to the message (see domish.Element.addElement)
489 - attrs: dictionary of attributes for the new child
490 - content: unicode that is appended to the child content
491 @param profile: the profile from which the message is sent
492 """
493 if profile is None:
494 error(_("Message can not be sent without a sender profile"))
495 return
496 msg = self.createGameElt(to_jid)
497 for elem, attrs, content in data:
498 if elem is not None:
499 if isinstance(elem, domish.Element):
500 msg.firstChildElement().addChild(elem)
501 else:
502 elem = msg.firstChildElement().addElement(elem)
503 if attrs is not None:
504 elem.attributes.update(attrs)
505 if content is not None:
506 elem.addContent(content)
507 self.host.profiles[profile].xmlstream.send(msg)
508
509
470 def send(self, to_jid, elem=None, attrs=None, content=None, profile=None): 510 def send(self, to_jid, elem=None, attrs=None, content=None, profile=None):
471 """ 511 """
472 @param to_jid: recipient JID 512 @param to_jid: recipient JID
473 @param elem: domish.Element, unicode or a couple: 513 @param elem: domish.Element, unicode or a couple:
474 - domish.Element to be directly added as a child to the message 514 - domish.Element to be directly added as a child to the message
476 and add it as a child to the message (see domish.Element.addElement) 516 and add it as a child to the message (see domish.Element.addElement)
477 @param attrs: dictionary of attributes for the new child 517 @param attrs: dictionary of attributes for the new child
478 @param content: unicode that is appended to the child content 518 @param content: unicode that is appended to the child content
479 @param profile: the profile from which the message is sent 519 @param profile: the profile from which the message is sent
480 """ 520 """
481 if profile is None: 521 self.sendElements(to_jid, [(elem, attrs, content)], profile)
482 error(_("Message can not be sent without a sender profile"))
483 return
484 msg = self.createGameElt(to_jid)
485 if elem is not None:
486 if isinstance(elem, domish.Element):
487 msg.firstChildElement().addChild(elem)
488 else:
489 elem = msg.firstChildElement().addElement(elem)
490 if attrs is not None:
491 elem.attributes.update(attrs)
492 if content is not None:
493 elem.addContent(content)
494 self.host.profiles[profile].xmlstream.send(msg)
495
496 if _DEBUG_FILE:
497 # From here you will see all the game messages
498 file_ = open("/tmp/game_messages", "a")
499 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()))
500 file_.close()
501 522
502 def getHandler(self, profile): 523 def getHandler(self, profile):
503 return RoomGameHandler(self) 524 return RoomGameHandler(self)
504 525
505 526