roc/gamedata.py
2011-06-15 19:21:13 -06:00

265 lines
6.7 KiB
Python
Executable file

import glob
import os
try:
from xml.etree.cElementTree import parse
except ImportError:
from elementtree.ElementTree import parse
import files
import shader
from deprecate import deprecated
class MissingNode(object):
def __init__(self):
self.text = None
def get(self, name):
return None
class GameDataTagDef(object):
def __init__(self):
self.multi = False
self.opt = False
self.type = None
self.default = None
class GameDataNode(object):
def __init__(self):
self.dict = {}
def __setitem__(self, name, val):
self.dict[name] = val
def __getitem__(self, name):
return self.dict[name]._value
def __getattr__(self, name):
if name == 'dict':
raise AttributeError, name
try:
return self.dict[name]
except KeyError:
if name == '_value':
return None
raise AttributeError, name
def __setattr__(self, name, val):
if name == 'dict':
return object.__setattr__(self, name, val)
try:
self.dict[name] = val
except KeyError:
object.__setattr__(self, name, val)
def add_multi(self, key, value):
if not self.dict.has_key(key):
self.dict[key] = []
self.dict[key].append(value)
def add_single(self, key, value):
self.dict[key] = value
def __repr__(self):
return """<GameDataNode "%s">""" % (self.dict['_name'],)
def has_key(self, key):
return self.dict.has_key(key)
class XMLGameDataReader(object):
def __init__(self, bin, xml):
self._bin = bin
self._xml = xml
self._tree = self.construct()
self._name = xml.tag
def value_as_type(self, value, type):
if type == 'string':
return value
elif type == 'bool':
if value and value[0].lower() in ('y', 't', '1'):
return True
else:
return False
elif type == 'int':
return int(value)
elif type == 'float':
return float(value)
elif type == 'csvarray':
# csvarrays are always ints...
return [int(x.strip()) for x in value.split(',')]
else:
raise TypeError, type
def create_datatag_def(self, tag):
d = GameDataTagDef()
if tag.get('multiple') != None and tag.get('multiple')[0].lower() == 'y':
d.multi = True
if tag.get('optional') != None and tag.get('optional')[0].lower() == 'y':
d.opt = True
if tag.get('data') != None:
d.type = tag.get('data')
if tag.get('default') != None:
d.default = self.value_as_type(tag.get('default'), d.type)
d.opt = True
return d
def create_attribute_def(self, tag):
return self.create_datatag_def(tag)
def construct_node(self, bin, xml):
node = GameDataNode()
value = None
if bin.tag == 'datatag':
df = self.create_datatag_def(bin)
if df.type:
value = xml.text
if type(xml) == MissingNode and df.opt:
value = df.default
elif type(xml) == MissingNode:
raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),)
elif df.type == 'bool':
# tag exists, and since it is a bool, that means it's True
value = True
else:
value = self.value_as_type(value, df.type)
node['_value'] = value
elif bin.tag == 'attribute':
df = self.create_attribute_def(bin)
if df.type:
value = xml.get(bin.get('name'))
if value == None and df.opt:
value = df.default
elif not value:
raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),)
else:
value = self.value_as_type(value, df.type)
node['_value'] = value
node['_def'] = df
node['_name'] = bin.get('name')
return node
def construct_recurse(self, bin, xml):
xmldict = {}
tagdict = {}
attrdict = {}
if bin.tag == 'xml_binary_packing':
node = GameDataNode()
else:
node = self.construct_node(bin, xml)
for child in bin.getchildren():
if child.tag == 'datatag':
tagdict[child.get('name')] = child
elif child.tag == 'attribute':
attrdict[child.get('name')] = child
else:
raise ValueError
xmlattrdict = {}
for k, v in xml.items():
if not k in attrdict:
raise ValueError, "Key %s not a valid attribute: %s" % (k, attrdict.keys())
continue
binchild = attrdict[k]
xmlchild = xml
xmlattrdict[k] = 0
subnode = self.construct_node(binchild, xml)
if subnode._def.multi:
node.add_multi(k, subnode)
else:
node.add_single(k, subnode)
xmltagdict = {}
for child in xml.getchildren():
if not child.tag in tagdict:
raise ValueError
continue
binchild = tagdict[child.tag]
xmlchild = child
xmltagdict[child.tag] = 0
subnode = self.construct_recurse(binchild, xmlchild)
if subnode._def.multi:
node.add_multi(child.tag, subnode)
else:
node.add_single(child.tag, subnode)
missing = MissingNode()
for k in tagdict.keys():
if not k in xmltagdict:
# Missing datatag
subnode = self.construct_node(tagdict[k], missing)
if not subnode._def.multi:
node.add_single(k, subnode)
else:
node.add_single(k, [])
for k in attrdict.keys():
if not k in xmlattrdict:
# Missing attribute
subnode = self.construct_node(attrdict[k], missing)
if not subnode._def.multi:
node.add_single(k, subnode)
else:
node.add_single(k, [])
return node
def construct(self):
rootname = self._bin.get('name')
assert rootname == self._xml.tag
return self.construct_recurse(self._bin, self._xml)
def __getattr__(self, name):
if name == 'tree':
raise AttributeError, name
return self._tree.__getattr__(name)
def __getitem__(self, name):
return self._tree.__getitem__(name)
def load_xml_files(binfile, xmlfile):
bintree = parse(binfile).getroot()
xmltree = parse(xmlfile).getroot()
return XMLGameDataReader(bintree, xmltree)
def get(dataname):
if dataname in get.cache:
return get.cache[dataname]
bin = files.mgr.path("xml/def", "%s.xml" % (dataname,))
xml = files.mgr.path("xml", "%s.xml" % (dataname,))
if not os.path.exists(bin) or not os.path.exists(xml):
raise OSError("XML data file does not exist")
dataobj = load_xml_files(bin, xml)
get.cache[dataname] = dataobj
return dataobj
get.cache = {}
@deprecated
def load_gamedata():
bins = glob.glob(files.mgr.path("xml/def", "*.xml"))
xmls = glob.glob(files.mgr.path("xml", "*.xml"))
binfns = [os.path.split(x)[1] for x in bins]
xmlfns = [os.path.split(x)[1] for x in xmls]
ffns = []
for bfn in binfns:
if bfn in xmlfns:
ffns.append(bfn)
dataobjs = {}
for fn in ffns:
binfile = files.mgr.path("xml/def", fn)
xmlfile = files.mgr.path("xml", fn)
dataobj = load_xml_files(binfile, xmlfile)
dataobjs[dataobj._name] = dataobj
shader.mgr.load_shaders(dataobjs['shaders'])
return dataobjs