This commit is contained in:
2016-06-01 21:03:15 +02:00
parent c42113d712
commit 27d0d313d2
27 changed files with 1657 additions and 1518 deletions

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
@@ -35,77 +35,75 @@
# gamestate reported by Mumble positional audio plugins
#
from mumo_module import (MumoModule,
x2bool)
import json
import re
try:
import json
except ImportError: # Fallback for python < 2.6
import simplejson as json
from config import x2bool
from mumo_module import MumoModule
class bf2(MumoModule):
default_config = {'bf2':(
('gamecount', int, 1),
),
lambda x: re.match('g\d+', x):(
('name', str, ''),
('mumble_server', int, 1),
('ipport_filter_negate', x2bool, False),
('ipport_filter', re.compile, re.compile('.*')),
('base', int, 0),
('left', int, -1),
('blufor', int, -1),
('blufor_commander', int, -1),
('blufor_no_squad', int, -1),
('blufor_first_squad', int, -1),
('blufor_first_squad_leader', int, -1),
('blufor_second_squad', int, -1),
('blufor_second_squad_leader', int, -1),
('blufor_third_squad', int, -1),
('blufor_third_squad_leader', int, -1),
('blufor_fourth_squad', int, -1),
('blufor_fourth_squad_leader', int, -1),
('blufor_fifth_squad', int, -1),
('blufor_fifth_squad_leader', int, -1),
('blufor_sixth_squad', int, -1),
('blufor_sixth_squad_leader', int, -1),
('blufor_seventh_squad', int, -1),
('blufor_seventh_squad_leader', int, -1),
('blufor_eighth_squad', int, -1),
('blufor_eighth_squad_leader', int, -1),
('blufor_ninth_squad', int, -1),
('blufor_ninth_squad_leader', int, -1),
('opfor', int, -1),
('opfor_commander', int, -1),
('opfor_no_squad', int, -1),
('opfor_first_squad', int, -1),
('opfor_first_squad_leader', int, -1),
('opfor_second_squad', int, -1),
('opfor_second_squad_leader', int, -1),
('opfor_third_squad', int, -1),
('opfor_third_squad_leader', int, -1),
('opfor_fourth_squad', int, -1),
('opfor_fourth_squad_leader', int, -1),
('opfor_fifth_squad', int, -1),
('opfor_fifth_squad_leader', int, -1),
('opfor_sixth_squad', int, -1),
('opfor_sixth_squad_leader', int, -1),
('opfor_seventh_squad', int, -1),
('opfor_seventh_squad_leader', int, -1),
('opfor_eighth_squad', int, -1),
('opfor_eighth_squad_leader', int, -1),
('opfor_ninth_squad', int, -1),
('opfor_ninth_squad_leader', int, -1)
),
}
default_config = {'bf2': (
('gamecount', int, 1),
),
lambda x: re.match('g\d+', x): (
('name', str, ''),
('mumble_server', int, 1),
('ipport_filter_negate', x2bool, False),
('ipport_filter', re.compile, re.compile('.*')),
('base', int, 0),
('left', int, -1),
('blufor', int, -1),
('blufor_commander', int, -1),
('blufor_no_squad', int, -1),
('blufor_first_squad', int, -1),
('blufor_first_squad_leader', int, -1),
('blufor_second_squad', int, -1),
('blufor_second_squad_leader', int, -1),
('blufor_third_squad', int, -1),
('blufor_third_squad_leader', int, -1),
('blufor_fourth_squad', int, -1),
('blufor_fourth_squad_leader', int, -1),
('blufor_fifth_squad', int, -1),
('blufor_fifth_squad_leader', int, -1),
('blufor_sixth_squad', int, -1),
('blufor_sixth_squad_leader', int, -1),
('blufor_seventh_squad', int, -1),
('blufor_seventh_squad_leader', int, -1),
('blufor_eighth_squad', int, -1),
('blufor_eighth_squad_leader', int, -1),
('blufor_ninth_squad', int, -1),
('blufor_ninth_squad_leader', int, -1),
('opfor', int, -1),
('opfor_commander', int, -1),
('opfor_no_squad', int, -1),
('opfor_first_squad', int, -1),
('opfor_first_squad_leader', int, -1),
('opfor_second_squad', int, -1),
('opfor_second_squad_leader', int, -1),
('opfor_third_squad', int, -1),
('opfor_third_squad_leader', int, -1),
('opfor_fourth_squad', int, -1),
('opfor_fourth_squad_leader', int, -1),
('opfor_fifth_squad', int, -1),
('opfor_fifth_squad_leader', int, -1),
('opfor_sixth_squad', int, -1),
('opfor_sixth_squad_leader', int, -1),
('opfor_seventh_squad', int, -1),
('opfor_seventh_squad_leader', int, -1),
('opfor_eighth_squad', int, -1),
('opfor_eighth_squad_leader', int, -1),
('opfor_ninth_squad', int, -1),
('opfor_ninth_squad_leader', int, -1)
),
}
id_to_squad_name = ["no", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth"]
def __init__(self, name, manager, configuration = None):
def __init__(self, name, manager, configuration=None):
MumoModule.__init__(self, name, manager, configuration)
self.murmur = manager.getMurmurModule()
@@ -114,7 +112,7 @@ class bf2(MumoModule):
manager = self.manager()
log = self.log()
log.debug("Register for Server callbacks")
servers = set()
for i in range(cfg.bf2.gamecount):
try:
@@ -122,23 +120,24 @@ class bf2(MumoModule):
except KeyError:
log.error("Invalid configuration. Game configuration for 'g%d' not found.", i)
return
self.sessions = {} # {serverid:{sessionid:laststate}}
self.sessions = {} # {serverid:{sessionid:laststate}}
manager.subscribeServerCallbacks(self, servers)
manager.subscribeMetaCallbacks(self, servers)
def disconnected(self): pass
def disconnected(self):
pass
#
#--- Module specific state handling code
# --- Module specific state handling code
#
def update_state(self, server, oldstate, newstate):
log = self.log()
sid = server.id()
session = newstate.session
newoldchannel = newstate.channel
try:
opc = oldstate.parsedcontext
ogcfgname = opc["gamename"]
@@ -147,15 +146,15 @@ class bf2(MumoModule):
opi = oldstate.parsedidentity
except (AttributeError, KeyError):
og = None
opi = {}
opc = {}
if oldstate and oldstate.is_linked:
oli = True
else:
oli = False
try:
npc = newstate.parsedcontext
ngcfgname = npc["gamename"]
@@ -164,23 +163,25 @@ class bf2(MumoModule):
npi = newstate.parsedidentity
except (AttributeError, KeyError):
ng = None
npi = {}
npc = {}
nli = False
if newstate and newstate.is_linked:
nli = True
else:
nli = False
if not oli and nli:
log.debug("User '%s' (%d|%d) on server %d now linked", newstate.name, newstate.session, newstate.userid, sid)
log.debug("User '%s' (%d|%d) on server %d now linked", newstate.name, newstate.session, newstate.userid,
sid)
server.addUserToGroup(0, session, "bf2_linked")
if opi and opc:
squadname = self.id_to_squad_name[opi["squad"]]
log.debug("Removing user '%s' (%d|%d) on server %d from groups of game %s / squad %s", newstate.name, newstate.session, newstate.userid, sid, og or ogcfgname, squadname)
log.debug("Removing user '%s' (%d|%d) on server %d from groups of game %s / squad %s", newstate.name,
newstate.session, newstate.userid, sid, og or ogcfgname, squadname)
server.removeUserFromGroup(ogcfg["base"], session, "bf2_%s_game" % (og or ogcfgname))
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_commander")
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_squad_leader")
@@ -189,72 +190,74 @@ class bf2(MumoModule):
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_team")
channame = "left"
newstate.channel = ogcfg["left"]
if npc and npi:
log.debug("Updating user '%s' (%d|%d) on server %d in game %s: %s", newstate.name, newstate.session, newstate.userid, sid, ng or ngcfgname, str(npi))
log.debug("Updating user '%s' (%d|%d) on server %d in game %s: %s", newstate.name, newstate.session,
newstate.userid, sid, ng or ngcfgname, str(npi))
squadname = self.id_to_squad_name[npi["squad"]]
# Add to game group
location = "base"
group = "bf2_%s_game" % (ng or ngcfgname)
server.addUserToGroup(ngcfg[location], session, group)
log.debug("Added '%s' @ %s to group %s in %s", newstate.name, ng or ngcfgname, group, location)
# Then add to team group
location = npi["team"]
group = "bf2_team"
server.addUserToGroup(ngcfg[location], session, group)
log.debug("Added '%s' @ %s to group %s in %s", newstate.name, ng or ngcfgname, group, location)
# Then add to squad group
group = "bf2_%s_squad" % squadname
server.addUserToGroup(ngcfg[location], session, group)
log.debug("Added '%s' @ %s to group %s in %s", newstate.name, ng or ngcfgname, group, location)
channame = "%s_%s_squad" % (npi["team"], self.id_to_squad_name[npi["squad"]])
newstate.channel = ngcfg[channame]
if npi["squad_leader"]:
# In case the leader flag is set add to leader group
group = "bf2_%s_squad_leader" % squadname
server.addUserToGroup(ngcfg[location], session, group)
log.debug("Added '%s' @ %s to group %s in %s", newstate.name, ng or ngcfgname, group, location)
group = "bf2_squad_leader"
server.addUserToGroup(ngcfg[location], session, group)
log.debug("Added '%s' @ %s to group %s in %s", newstate.name, ng or ngcfgname, group, location)
# Override previous moves
channame = "%s_%s_squad_leader" % (npi["team"], self.id_to_squad_name[npi["squad"]])
newstate.channel = ngcfg[channame]
if npi["commander"]:
group = "bf2_commander"
server.addUserToGroup(ngcfg[location], session, group)
log.debug("Added '%s' @ %s to group %s in %s", newstate.name, ng or ngcfgname, group, location)
# Override previous moves
channame = "%s_commander" % npi["team"]
newstate.channel = ngcfg[channame]
if oli and not nli:
log.debug("User '%s' (%d|%d) on server %d no longer linked", newstate.name, newstate.session, newstate.userid, sid)
log.debug("User '%s' (%d|%d) on server %d no longer linked", newstate.name, newstate.session,
newstate.userid, sid)
server.removeUserFromGroup(0, session, "bf2_linked")
if newstate.channel >= 0 and newoldchannel != newstate.channel:
if ng == None:
if 0 <= newstate.channel != newoldchannel:
if ng is None:
log.debug("Moving '%s' leaving %s to channel %s", newstate.name, og or ogcfgname, channame)
else:
log.debug("Moving '%s' @ %s to channel %s", newstate.name, ng or ngcfgname, channame)
server.setState(newstate)
def handle(self, server, state):
def verify(mdict, key, vtype):
if not isinstance(mdict[key], vtype):
raise ValueError("'%s' of invalid type" % key)
cfg = self.cfg()
log = self.log()
sid = server.id()
@@ -263,17 +266,17 @@ class bf2(MumoModule):
state.parsedidentity = {}
state.parsedcontext = {}
state.is_linked = False
if sid not in self.sessions: # Make sure there is a dict to store states in
if sid not in self.sessions: # Make sure there is a dict to store states in
self.sessions[sid] = {}
update = False
if state.session in self.sessions[sid]:
if state.identity != self.sessions[sid][state.session].identity or \
state.context != self.sessions[sid][state.session].context:
state.context != self.sessions[sid][state.session].context:
# identity or context changed => update
update = True
else: # id and context didn't change hence the old data must still be valid
else: # id and context didn't change hence the old data must still be valid
state.is_linked = self.sessions[sid][state.session].is_linked
state.parsedcontext = self.sessions[sid][state.session].parsedcontext
state.parsedidentity = self.sessions[sid][state.session].parsedidentity
@@ -282,46 +285,48 @@ class bf2(MumoModule):
# New user with engaged plugin => update
self.sessions[sid][state.session] = None
update = True
if not update:
self.sessions[sid][state.session] = state
return
# The plugin will always prefix "Battlefield 2\0" to the context for the bf2 PA plugin
# don't bother analyzing anything if it isn't there
splitcontext = state.context.split('\0', 1)
if splitcontext[0] == "Battlefield 2":
state.is_linked = True
if state.identity and len(splitcontext) == 1:
#LEGACY: Assume broken Ice 3.2 which doesn't transmit context after \0
splitcontext.append('{"ipport":""}') # Obviously this doesn't give full functionality but it doesn't crash either ;-)
# LEGACY: Assume broken Ice 3.2 which doesn't transmit context after \0
splitcontext.append(
'{"ipport":""}') # Obviously this doesn't give full functionality but it doesn't crash either ;-)
if state.is_linked and len(splitcontext) == 2 and state.identity:
if state.is_linked and len(splitcontext) == 2 and state.identity:
try:
context = json.loads(splitcontext[1])
verify(context, "ipport", basestring)
verify(context, "ipport", str)
for i in range(cfg.bf2.gamecount):
# Try to find a matching game
gamename = "g%d" % i
gamecfg = getattr(cfg, gamename)
if gamecfg.mumble_server == server.id():
not_matched = (gamecfg.ipport_filter.match(context["ipport"]) == None)
not_matched = (gamecfg.ipport_filter.match(context["ipport"]) is None)
if not_matched == gamecfg.ipport_filter_negate:
break
gamename = None
if not gamename:
raise ValueError("No matching game found")
context["gamecfg"] = gamecfg
context["gamename"] = gamename
state.parsedcontext = context
except (ValueError, KeyError, AttributeError), e:
log.debug("Invalid context for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid, sid, repr(e))
except (ValueError, KeyError, AttributeError) as e:
log.debug("Invalid context for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid,
sid, repr(e))
try:
identity = json.loads(state.identity)
verify(identity, "commander", bool)
@@ -329,48 +334,57 @@ class bf2(MumoModule):
verify(identity, "squad", int)
if identity["squad"] < 0 or identity["squad"] > 9:
raise ValueError("Invalid squad number")
verify(identity, "team", basestring)
verify(identity, "team", str)
if identity["team"] != "opfor" and identity["team"] != "blufor":
raise ValueError("Invalid team identified")
#LEGACY: Ice 3.2 cannot handle unicode strings
# LEGACY: Ice 3.2 cannot handle unicode strings
identity["team"] = str(identity["team"])
state.parsedidentity = identity
except (KeyError, ValueError), e:
log.debug("Invalid identity for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid, sid, repr(e))
except (KeyError, ValueError) as e:
log.debug("Invalid identity for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid,
sid, repr(e))
# Update state and remember it
self.update_state(server, self.sessions[sid][state.session], state)
self.sessions[sid][state.session] = state
#
#--- Server callback functions
# --- Server callback functions
#
def userDisconnected(self, server, state, context = None):
def userDisconnected(self, server, state, context=None):
try:
sid = server.id()
del self.sessions[sid][state.session]
except KeyError: pass
def userStateChanged(self, server, state, context = None):
except KeyError:
pass
def userStateChanged(self, server, state, context=None):
self.handle(server, state)
def userConnected(self, server, state, context = None):
def userConnected(self, server, state, context=None):
self.handle(server, state)
def userTextMessage(self, server, user, message, current=None): pass
def channelCreated(self, server, state, context = None): pass
def channelRemoved(self, server, state, context = None): pass
def channelStateChanged(self, server, state, context = None): pass
def userTextMessage(self, server, user, message, current=None):
pass
def channelCreated(self, server, state, context=None):
pass
def channelRemoved(self, server, state, context=None):
pass
def channelStateChanged(self, server, state, context=None):
pass
#
#--- Meta callback functions
# --- Meta callback functions
#
def started(self, server, context = None):
def started(self, server, context=None):
self.sessions[server.id()] = {}
def stopped(self, server, context = None):
def stopped(self, server, context=None):
self.sessions[server.id()] = {}