276 lines
6.9 KiB
Python
Executable file
276 lines
6.9 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 = {}
|
|
self.missing = False
|
|
|
|
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 key not in self.dict:
|
|
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 key in self.dict
|
|
|
|
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, allow_missing=False):
|
|
node = GameDataNode()
|
|
if isinstance(xml, MissingNode):
|
|
node.missing = True
|
|
value = None
|
|
if bin.tag == 'datatag':
|
|
df = self.create_datatag_def(bin)
|
|
if df.type:
|
|
value = xml.text
|
|
if df.type == 'bool':
|
|
# if tag exists, since it is a bool, that means it's True
|
|
value = not node.missing
|
|
elif (node.missing or value == None) and df.opt:
|
|
value = df.default
|
|
elif (node.missing or value == None) and not allow_missing:
|
|
raise ValueError("Missing value for mandatory tag %s" % (bin.get('name'),))
|
|
elif (node.missing or value == None):
|
|
value = None
|
|
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 and not allow_missing:
|
|
raise ValueError("Missing value for mandatory tag %s" % (bin.get('name'),))
|
|
elif not value:
|
|
value = None
|
|
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, allow_missing=False):
|
|
xmldict = {}
|
|
tagdict = {}
|
|
attrdict = {}
|
|
|
|
if bin.tag == 'xml_binary_packing':
|
|
node = GameDataNode()
|
|
else:
|
|
node = self.construct_node(bin, xml, allow_missing)
|
|
|
|
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 = {}
|
|
xmltagdict = {}
|
|
|
|
if not isinstance(xml, MissingNode):
|
|
for k, v in list(xml.items()):
|
|
if not k in attrdict:
|
|
raise ValueError("Key %s not a valid attribute: %s" % (k, list(attrdict.keys())))
|
|
continue
|
|
binchild = attrdict[k]
|
|
xmlchild = xml
|
|
xmlattrdict[k] = 0
|
|
subnode = self.construct_node(binchild, xml, allow_missing)
|
|
if subnode._def.multi:
|
|
node.add_multi(k, subnode)
|
|
else:
|
|
node.add_single(k, subnode)
|
|
|
|
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, allow_missing)
|
|
if subnode._def.multi:
|
|
node.add_multi(child.tag, subnode)
|
|
else:
|
|
node.add_single(child.tag, subnode)
|
|
|
|
|
|
missing = MissingNode()
|
|
for k in list(tagdict.keys()):
|
|
if not k in xmltagdict:
|
|
# Missing datatag
|
|
subnode = self.construct_recurse(tagdict[k], missing, isinstance(xml, MissingNode))
|
|
if not subnode._def.multi:
|
|
node.add_single(k, subnode)
|
|
else:
|
|
node.add_single(k, [])
|
|
|
|
for k in list(attrdict.keys()):
|
|
if not k in xmlattrdict:
|
|
# Missing attribute
|
|
subnode = self.construct_node(attrdict[k], missing, isinstance(xml, MissingNode))
|
|
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
|
|
|
|
|
|
|