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
This commit is contained in:
souliane 2013-11-21 15:49:53 +01:00
commit ea67ed7a61
3 changed files with 378 additions and 196 deletions

View file

@ -25,23 +25,15 @@ from twisted.words.protocols.jabber import error as jab_error
from twisted.words.protocols.jabber.xmlstream import IQ
import random
from zope.interface import implements
from wokkel import disco, iwokkel, data_form
from wokkel import data_form
from sat.tools.xml_tools import dataForm2XML
from sat.tools.frontends.games import TarotCard
from sat.tools.plugins.games import RoomGame
from time import time
try:
from twisted.words.protocols.xmlstream import XMPPHandler
except ImportError:
from wokkel.subprotocols import XMPPHandler
MESSAGE = '/message'
NS_QG = 'http://www.goffi.org/protocol/quiz'
QG_TAG = 'quiz'
QG_REQUEST = MESSAGE + '/' + QG_TAG + '[@xmlns="' + NS_QG + '"]'
PLUGIN_INFO = {
"name": "Quiz game plugin",
@ -59,8 +51,7 @@ class Quiz(RoomGame):
def __init__(self, host):
info(_("Plugin Quiz initialization"))
RoomGame.__init__(self, host, PLUGIN_INFO, (NS_QG, QG_TAG), player_init_data={'score': 0},
options={'stage': None})
RoomGame.__init__(self, host, PLUGIN_INFO, (NS_QG, QG_TAG), game_init={'stage': None}, player_init={'score': 0})
host.bridge.addMethod("quizGameLaunch", ".plugin", in_sign='asss', out_sign='', method=self.prepareRoom) # args: players, room_jid, profile
host.bridge.addMethod("quizGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame) # args: room_jid, players, profile
host.bridge.addMethod("quizGameReady", ".plugin", in_sign='sss', out_sign='', method=self.playerReady) # args: player, referee, profile
@ -114,7 +105,6 @@ class Quiz(RoomGame):
'param_0': "room_jid: jid of game's room",
'param_1': "time_left: time left before timer expiration",
'param_2': '%(doc_profile)s'})
host.trigger.add("MUC user joined", self.userJoinedTrigger)
def __game_data_to_xml(self, game_data):
"""Convert a game data dict to domish element"""
@ -264,12 +254,13 @@ Attention, tu es prêt ?""")}
RoomGame.newRound(self, room_jid, (common_data, msg_elts), profile)
reactor.callLater(10, self.askQuestion, room_jid, profile)
def quiz_game_cmd(self, mess_elt, profile):
def room_game_cmd(self, mess_elt, profile):
from_jid = jid.JID(mess_elt['from'])
room_jid = jid.JID(from_jid.userhost())
game_elt = mess_elt.firstChildElement()
game_data = self.games[room_jid.userhost()]
players_data = game_data['players_data']
if 'players_data' in game_data:
players_data = game_data['players_data']
for elt in game_elt.elements():
@ -333,23 +324,3 @@ Attention, tu es prêt ?""")}
else:
error(_('Unmanaged game element: %s') % elt.name)
def getHandler(self, profile):
return QuizGameHandler(self)
class QuizGameHandler (XMPPHandler):
implements(iwokkel.IDisco)
def __init__(self, plugin_parent):
self.plugin_parent = plugin_parent
self.host = plugin_parent.host
def connectionInitialized(self):
self.xmlstream.addObserver(QG_REQUEST, self.plugin_parent.quiz_game_cmd, profile=self.parent.profile)
def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
return [disco.DiscoFeature(NS_QG)]
def getDiscoItems(self, requestor, target, nodeIdentifier=''):
return []

View file

@ -22,23 +22,14 @@ from twisted.words.xish import domish
from twisted.internet import reactor
from twisted.words.protocols.jabber import jid
from wokkel import disco, iwokkel
from zope.interface import implements
import os.path
from os import unlink
from mutagen.oggvorbis import OggVorbis, OggVorbisHeaderError
from sat.tools.plugins.games import RoomGame
try:
from twisted.words.protocols.xmlstream import XMPPHandler
except ImportError:
from wokkel.subprotocols import XMPPHandler
MESSAGE = '/message'
NC_RADIOCOL = 'http://www.goffi.org/protocol/radiocol'
RADIOC_TAG = 'radiocol'
RADIOC_REQUEST = MESSAGE + '/' + RADIOC_TAG + '[@xmlns="' + NC_RADIOCOL + '"]'
PLUGIN_INFO = {
"name": "Radio collective plugin",
@ -59,18 +50,18 @@ class Radiocol(RoomGame):
def __init__(self, host):
info(_("Radio collective initialization"))
RoomGame.__init__(self, host, PLUGIN_INFO, (NC_RADIOCOL, RADIOC_TAG),
options={'queue': [], 'upload': True, 'playing': False, 'to_delete': {}})
game_init={'queue': [], 'upload': True, 'playing': False, 'to_delete': {}})
self.host = host
host.bridge.addMethod("radiocolLaunch", ".plugin", in_sign='asss', out_sign='', method=self.prepareRoom)
host.bridge.addMethod("radiocolCreate", ".plugin", in_sign='ss', out_sign='', method=self.createCollectiveGame)
host.bridge.addMethod("radiocolCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame)
host.bridge.addMethod("radiocolSongAdded", ".plugin", in_sign='sss', out_sign='', method=self.radiocolSongAdded)
host.bridge.addSignal("radiocolStarted", ".plugin", signature='sss') # room_jid, referee, profile
host.bridge.addSignal("radiocolPlayers", ".plugin", signature='ssass') # room_jid, referee, players, profile
host.bridge.addSignal("radiocolStarted", ".plugin", signature='ssass') # room_jid, referee, players, profile
host.bridge.addSignal("radiocolSongRejected", ".plugin", signature='sss') # room_jid, reason, profile
host.bridge.addSignal("radiocolPreload", ".plugin", signature='ssssss') # room_jid, filename, title, artist, album, profile
host.bridge.addSignal("radiocolPlay", ".plugin", signature='sss') # room_jid, filename, profile
host.bridge.addSignal("radiocolNoUpload", ".plugin", signature='ss') # room_jid, profile
host.bridge.addSignal("radiocolUploadOk", ".plugin", signature='ss') # room_jid, profile
host.trigger.add("MUC user joined", self.userJoinedTrigger)
def __create_preload_elt(self, sender, filename, title, artist, album):
preload_elt = domish.Element((None, 'preload'))
@ -151,18 +142,23 @@ class Radiocol(RoomGame):
#we wait more than the song length to delete the file, to manage poorly reactive networks/clients
reactor.callLater(length + 90, unlink, file_to_delete) # FIXME: same host trick (see above)
def radiocol_game_cmd(self, mess_elt, profile):
def room_game_cmd(self, mess_elt, profile):
#FIXME: we should check sender (is it referee ?) here before accepting commands
from_jid = jid.JID(mess_elt['from'])
room_jid = jid.JID(from_jid.userhost())
radio_elt = mess_elt.firstChildElement()
radio_data = self.games[room_jid.userhost()]
queue = radio_data['queue']
if 'queue' in radio_data:
queue = radio_data['queue']
for elt in radio_elt.elements():
if elt.name == 'started': # new game created
self.host.bridge.radiocolStarted(room_jid.userhost(), from_jid.full(), profile)
if elt.name == 'started' or elt.name == 'players': # new game created
players = []
for player in elt.elements():
players.append(unicode(player))
signal = self.host.bridge.radiocolStarted if elt.name == 'started' else self.host.bridge.radiocolPlayers
signal(room_jid.userhost(), from_jid.full(), players, profile)
elif elt.name == 'preload': # a song is in queue and must be preloaded
self.host.bridge.radiocolPreload(room_jid.userhost(), elt['filename'], elt['title'], elt['artist'], elt['album'], profile)
elif elt.name == 'play':
@ -208,23 +204,3 @@ class Radiocol(RoomGame):
self.playNext(room_jid, profile)
else:
error(_('Unmanaged game element: %s') % elt.name)
def getHandler(self, profile):
return RadiocolHandler(self)
class RadiocolHandler (XMPPHandler):
implements(iwokkel.IDisco)
def __init__(self, plugin_parent):
self.plugin_parent = plugin_parent
self.host = plugin_parent.host
def connectionInitialized(self):
self.xmlstream.addObserver(RADIOC_REQUEST, self.plugin_parent.radiocol_game_cmd, profile=self.parent.profile)
def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
return [disco.DiscoFeature(NC_RADIOCOL)]
def getDiscoItems(self, requestor, target, nodeIdentifier=''):
return []

View file

@ -20,26 +20,17 @@
from logging import debug, info, warning, error
from twisted.words.xish import domish
from twisted.words.protocols.jabber import jid
import random
from wokkel import data_form
from zope.interface import implements
from wokkel import disco, iwokkel, data_form
from sat.tools.xml_tools import dataForm2XML
from sat.tools.frontends.games import TarotCard
from sat.tools.plugins.games import RoomGame
from time import time
import random
try:
from twisted.words.protocols.xmlstream import XMPPHandler
except ImportError:
from wokkel.subprotocols import XMPPHandler
MESSAGE = '/message'
NS_CG = 'http://www.goffi.org/protocol/card_game'
CG_TAG = 'card_game'
CG_REQUEST = MESSAGE + '/' + CG_TAG + '[@xmlns="' + NS_CG + '"]'
PLUGIN_INFO = {
"name": "Tarot cards plugin",
@ -57,14 +48,16 @@ class Tarot(RoomGame):
def __init__(self, host):
info(_("Plugin Tarot initialization"))
RoomGame.__init__(self, host, PLUGIN_INFO, (NS_CG, CG_TAG), player_init_data={'score': 0},
options={'hand_size': 18, 'init_player': 0, 'current_player': None, 'contrat': None, 'stage': None})
RoomGame.__init__(self, host, PLUGIN_INFO, (NS_CG, CG_TAG),
game_init={'hand_size': 18, 'init_player': 0, 'current_player': None, 'contrat': None, 'stage': None},
player_init={'score': 0})
self.contrats = [_('Passe'), _('Petite'), _('Garde'), _('Garde Sans'), _('Garde Contre')]
host.bridge.addMethod("tarotGameLaunch", ".plugin", in_sign='asss', out_sign='', method=self.prepareRoom) # args: players, room_jid, profile
host.bridge.addMethod("tarotGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame) # args: room_jid, players, profile
host.bridge.addMethod("tarotGameReady", ".plugin", in_sign='sss', out_sign='', method=self.playerReady) # args: player, referee, profile
host.bridge.addMethod("tarotGameContratChoosed", ".plugin", in_sign='ssss', out_sign='', method=self.contratChoosed) # args: player, referee, contrat, profile
host.bridge.addMethod("tarotGamePlayCards", ".plugin", in_sign='ssa(ss)s', out_sign='', method=self.play_cards) # args: player, referee, cards, profile
host.bridge.addSignal("tarotGamePlayers", ".plugin", signature='ssass') # args: room_jid, referee, players, profile
host.bridge.addSignal("tarotGameStarted", ".plugin", signature='ssass') # args: room_jid, referee, players, profile
host.bridge.addSignal("tarotGameNew", ".plugin", signature='sa(ss)s') # args: room_jid, hand, profile
host.bridge.addSignal("tarotGameChooseContrat", ".plugin", signature='sss') # args: room_jid, xml_data, profile
@ -73,7 +66,6 @@ class Tarot(RoomGame):
host.bridge.addSignal("tarotGameYourTurn", ".plugin", signature='ss') # args: room_jid, profile
host.bridge.addSignal("tarotGameScore", ".plugin", signature='ssasass') # args: room_jid, xml_data, winners (list of nicks), loosers (list of nicks), profile
host.bridge.addSignal("tarotGameInvalidCards", ".plugin", signature='ssa(ss)a(ss)s') # args: room_jid, game phase, played_cards, invalid_cards, profile
host.trigger.add("MUC user joined", self.userJoinedTrigger)
self.deck_ordered = []
for value in ['excuse'] + map(str, range(1, 22)):
self.deck_ordered.append(TarotCard(("atout", value)))
@ -443,7 +435,7 @@ class Tarot(RoomGame):
to_jid = jid.JID(room_jid.userhost() + "/" + player) # FIXME: gof:
self.send(to_jid, self.__ask_contrat(), profile=profile)
def card_game_cmd(self, mess_elt, profile):
def room_game_cmd(self, mess_elt, profile):
"""
@param mess_elt: instance of twisted.words.xish.domish.Element
"""
@ -451,15 +443,17 @@ class Tarot(RoomGame):
room_jid = jid.JID(from_jid.userhost())
game_elt = mess_elt.firstChildElement()
game_data = self.games[room_jid.userhost()]
players_data = game_data['players_data']
if 'players_data' in game_data:
players_data = game_data['players_data']
for elt in game_elt.elements():
if elt.name == 'started': # new game created
if elt.name == 'started' or elt.name == 'players': # new game created
players = []
for player in elt.elements():
players.append(unicode(player))
self.host.bridge.tarotGameStarted(room_jid.userhost(), from_jid.full(), players, profile)
signal = self.host.bridge.tarotGameStarted if elt.name == 'started' else self.host.bridge.tarotGamePlayers
signal(room_jid.userhost(), from_jid.full(), players, profile)
elif elt.name == 'player_ready': # ready to play
player = elt['player']
@ -625,23 +619,3 @@ class Tarot(RoomGame):
error(_('Unmanaged error type: %s') % elt['type'])
else:
error(_('Unmanaged card game element: %s') % elt.name)
def getHandler(self, profile):
return CardGameHandler(self)
class CardGameHandler (XMPPHandler):
implements(iwokkel.IDisco)
def __init__(self, plugin_parent):
self.plugin_parent = plugin_parent
self.host = plugin_parent.host
def connectionInitialized(self):
self.xmlstream.addObserver(CG_REQUEST, self.plugin_parent.card_game_cmd, profile=self.parent.profile)
def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
return [disco.DiscoFeature(NS_CG)]
def getDiscoItems(self, requestor, target, nodeIdentifier=''):
return []