roc/gamedata.py
cecilkorik deaa55d535 working textures!
completely overhauled models framework...
now loads Model, Mesh, Material, and Texture (plus TextureFile)

fixed a number of bugs/inflexibilities in gamedata xml parser

refactored the various modules to use "init" functions to better control when they get loaded (ie, before or after OpenGL init)
which it turns out is *very important*, because if the shaders and textures get loaded before OpenGL does, they don't work. go figure.
2011-06-17 19:54:49 -06:00

276 lines
7.2 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 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, 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 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, 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 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 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