Resource information is now centralized in resources.csv.

The old scripts that trolled content/ and src/ for information
have been retired, and the new script reads the CSV file and
generates the resource files directly.

Future changes to the resource indices or content should be
done by modifying resources.csv and regenerating the data.


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2925 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
mcmartin
2008-02-24 22:06:03 +00:00
parent 9d914998b9
commit d0dcf67ac6
10 changed files with 148 additions and 19 deletions
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/python
import sys
import os
import os.path
import explorer
import mastermap
import relst
if len(sys.argv) < 3:
basedir = os.path.join(os.path.pardir, os.path.pardir, "sc2", "content")
else:
basedir = sys.argv[2]
if len(sys.argv) < 2:
targetrmp = os.path.join (basedir, "uqm.rmp")
else:
targetrmp = sys.argv[1]
verbose = True
types = ['UNKNOWN', 'KEY_CONFIG', 'GFXRES', 'FONTRES', 'STRTAB', 'SNDRES', 'MUSICRES', 'RES_INDEX', 'CODE']
def read_types():
result = {}
pkgnames = explorer.collect_extension(basedir, '.ls2')
packages = [(x, explorer.read_list(x)) for x in pkgnames]
for (name, pkg) in packages:
for ((p, i, t), target) in pkg:
result[target] = types[t]
return result
def convert_map (mapfile, typemap):
result = []
for line in file(mapfile):
xs = line.split('=', 1)
if len(xs) == 2:
resid = xs[0].strip()
resname = typemap[resid] + ":" + xs[1].strip()
result.append("%s = %s" % (resid, resname))
return result
def go():
typemap = read_types()
for x in convert_map(targetrmp, typemap):
print x
if __name__ == '__main__':
go()
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/python
import sys
import os
import os.path
import explorer
import mastermap
import relst
if len(sys.argv) < 2:
basedir = os.path.join(os.path.pardir, os.path.pardir, "sc2", "content")
else:
basedir = sys.argv[1]
verbose = True
def deploy_map():
target = os.path.join(basedir, "uqm.rmp")
outfile = file(target, 'wt')
if verbose:
print "Writing %s..." % target
for l in mastermap.create_map(basedir):
print>>outfile, l
outfile.close()
def deploy_ls2(name, pkg):
newpkg = os.path.splitext(name)[0]+'.ls2'
newvals = relst.process(pkg)
outfile = file(newpkg, 'wt')
print "Writing %s..." % newpkg
for l in newvals:
print>>outfile, l
outfile.close()
def deploy_ls2s():
pkgnames = explorer.get_lists(basedir)
packages = [(x, explorer.read_list(x)) for x in pkgnames]
for (name, pkg) in packages:
deploy_ls2(name, pkg)
if __name__ == '__main__':
deploy_map()
deploy_ls2s()
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/python
import sys
import os
import os.path
import re
def collect_extension(d, ext):
result = []
for (dirpath, dirnames, filenames) in os.walk(d):
for l in [f for f in filenames if f.endswith(ext)]:
result.append(os.path.join(dirpath, l))
return result
def collect_res_headers(d, pattern="i.*\\.h$"):
result = []
regex = re.compile(pattern)
for (dirpath, dirnames, filenames) in os.walk(d):
for l in [f for f in filenames if regex.match(f) != None]:
result.append(os.path.join(dirpath, l))
return result
def read_list(f):
result = []
for line in file(f):
parsed = line.split()
if len(parsed) == 4:
result.append(((int(parsed[0]), int(parsed[1]), int(parsed[2])),
parsed[3]))
return result
def read_header(f):
result = []
for line in file(f):
line = line.strip()
if line.startswith("#define"):
parsed = [x.strip() for x in line.split()]
if len(parsed) == 3 and parsed[2].startswith('0') and parsed[2].endswith('L'):
result.append((parsed[1], parsed[2]))
return result
if __name__ == "__main__":
print "This is a library and isn't intended to be run directly."
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/python
import sys
import os
import os.path
import explorer
import stridgen
from optparse import OptionParser
def process (res):
result = []
for line in res:
line = line.strip()
if len(line) == 0:
continue
mapline = stridgen.makeid(line)
# Remap not to .lst files but to .ls2 ones.
if line.endswith('lst'):
line = os.path.splitext(line)[0]+'.ls2'
if mapline is None:
toadd = "# NO MATCH FOR %s" % line
else:
toadd = "%s = %s" % (mapline, line)
if toadd not in result:
result.append(toadd)
result.sort()
return result
def get_lists(d, ext):
result = []
packages = [explorer.read_list(x) for x in explorer.collect_extension(d, ext)]
for package in packages:
for line in package:
if line[1] not in result:
result.append(line[1])
return result
def get_resources(d, ext):
result = []
if not d.endswith(os.path.sep):
d += os.path.sep
for res in explorer.collect_extension (d, ext):
res = res[len(d):]
if res not in result:
result.append(res)
return result
def create_map(resources):
resmap = process(resources)
keys = []
result = []
for r in resmap:
key = r.split('=')[0].strip()
if key in keys:
result.append("# ERROR: DUPLICATE KEY %s" % key)
else:
keys.append(key)
result.append(r)
return result
if __name__ == "__main__":
opts = OptionParser(usage="usage: %prog [options]")
opts.add_option("-d", "--content-dir", dest="d",
help="Directory to search for resources",
default=os.path.join(os.path.pardir, os.path.pardir, "sc2", "content"))
opts.add_option("-r", "--raw", action="store_true", default=False,
dest="raw", help="do not treat target resources as lists")
opts.add_option("-e", "--extension", dest="ext",
help="Extension for files to search", default=".lst")
(options, args)=opts.parse_args()
if options.raw:
l = get_resources(options.d, options.ext)
else:
l = get_lists(options.d, options.ext)
for line in create_map(l):
print line
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/python
import sys
import os
import os.path
import explorer
import stridgen
def process (res):
result = []
for ((a, b, c), d) in res:
mapline = stridgen.makeid(d)
if mapline is None:
mapline = "ERROR"
result.append("%3d %3d %3d %s" % (a, b, c, mapline))
return result
if __name__ == "__main__":
if len(sys.argv) < 2:
d = os.path.join(os.path.pardir, os.path.pardir, "sc2", "content")
else:
d = sys.argv[1]
pkgnames = explorer.get_lists(d)
packages = [explorer.read_list(x) for x in pkgnames]
for (name, pkg) in zip(pkgnames, packages):
newpkg = os.path.splitext(name)[0]+'.ls2'
print newpkg
print '-'*len(newpkg)
newvals = process(pkg)
for l in newvals:
print l
print
+280
View File
@@ -0,0 +1,280 @@
#!/usr/bin/python
import scan_defines as scan
# 72-5-4 for colortable.str_cts_ -- 0x09000504L -- OOLITE_COLOR_TAB. Goes up through
# 202-87-2 for PLANET00_BIG_MASK_PMAP_ANIM. Goes up through 58.
# MAROON and CRIMSON seem swapped!
planettypes = ['oolite',
'yttric',
'quasidegenerate',
'lanthanide',
'treasure',
'urea',
'metal',
'radioactive',
'opalescent',
'cyanic',
'acid',
'alkali',
'halide',
'green',
'copper',
'carbide',
'ultramarine',
'noble',
'azure',
'chondrite',
'purple',
'superdense',
'pellucid',
'dust',
'crimson',
'cimmerian',
'infrared',
'selenic',
'auric',
'fluorescent',
'ultraviolet',
'plutonic',
'rainbow',
'shattered',
'sapphire',
'organic',
'xenolithic',
'redux',
'primordial',
'emerald',
'chlorine',
'magnetic',
'water',
'telluric',
'hydrocarbon',
'iodine',
'vinylogous',
'ruby',
'magma',
'maroon',
'bluegas', # PLANET50 # (As per colorcodes)
'cyangas',
'greengas',
'greygas',
'orangegas',
'purplegas',
'redgas',
'violetgas',
'yellowgas']
headersymbols = {'quasidegenerate': 'quasi_degenerate',
'superdense': 'super_dense',
'bluegas': 'blu_gas',
'cyangas': 'cya_gas',
'greengas': 'grn_gas',
'greygas': 'gry_gas',
'orangegas': 'ora_gas',
'purplegas': 'pur_gas',
'redgas': 'red_gas',
'violetgas': 'vio_gas',
'yellowgas': 'yel_gas' }
xlattabs = ['oolite',
'yttric',
'quasidegenerate',
'yttric',
'quasidegenerate',
'urea',
'metal',
'yttric',
'opalescent',
'quasidegenerate',
'yttric',
'yttric',
'yttric',
'urea',
'quasidegenerate',
'opalescent',
'urea',
'yttric',
'urea',
'chondrite',
'urea',
'quasidegenerate',
'opalescent',
'yttric',
'urea',
'quasidegenerate',
'opalescent',
'urea',
'quasidegenerate',
'opalescent',
'yttric',
'yttric',
'rainbow',
'shattered',
'sapphire',
'quasidegenerate',
'opalescent',
'redux',
'yttric',
'sapphire',
'chlorine',
'opalescent',
'chlorine',
'yttric',
'quasidegenerate',
'urea',
'opalescent',
'sapphire',
'quasidegenerate',
'urea',
'gas',
'gas',
'gas',
'gas',
'gas',
'gas',
'gas',
'gas',
'gas']
colorcodes = ['blu', 'cya', 'grn', 'gry', 'ora', 'pur', 'red', 'vio', 'yel']
# androsyn -> androsynth
# blackurq -> kohrah
# human -> earthling
# slylandr -> slylandro
# thradd -> thraddash
# zoqfot -> zoqfotpik
shiptypes = ['arilou',
'chmmr',
'earthling',
'orz',
'pkunk',
'shofixti',
'spathi',
'supox',
'thraddash',
'utwig',
'vux',
'yehat',
'melnorme',
'druuge',
'ilwrath',
'mycon',
'slylandro',
'umgah',
'urquan',
'zoqfotpik',
'syreen',
'kohrah',
'androsynth',
'chenjesu',
'mmrnmhrm']
#blackur -> kohrah
#comandr -> commander
#melnorm -> melnorme
#shofixt -> shofixti
#slyland -> slylandro
#starbas -> starbase
#talkpet -> talkingpet
#thradd -> thraddash
#zoqfot -> zoqfotpik
convtypes = ['arilou',
'chmmr',
'commander',
'orz',
'pkunk',
'shofixti',
'spathi',
'supox',
'thraddash',
'utwig',
'vux',
'yehat',
'melnorme',
'druuge',
'ilwrath',
'mycon',
'slylandro',
'umgah',
'urquan',
'zoqfotpik',
'syreen',
'kohrah',
'talkingpet',
'slyhome']
def write_planet_gfx():
vals = scan.collect_data()
planetanibase = vals.index([x for x in vals if x[0] == 'PLANET00_BIG_MASK_PMAP_ANIM'][0])
(pkg, inst, typ) = scan.res_decode_str(vals[planetanibase][1])
resmap = []
for planettype in planettypes:
for size in ['large', 'medium', 'small']:
print "%3d %3d %3d planet.%s.%s" % (pkg, inst, typ, planettype, size)
resmap.append(("planet.%s.%s" % (planettype, size), vals[planetanibase][3]))
planetanibase += 1
inst += 1
pkg += 1
print
print "---"
print
for (key, val) in resmap:
print "%s = GFXRES:%s" % (key, val)
def write_planet_str():
vals = scan.collect_data()
planetctbase = [x for x in vals if x[0] == 'OOLITE_COLOR_TAB'][0]
(basepkg, ctinst, typ) = scan.res_decode_str(planetctbase[1])
xltinst = ctinst + 1
reslist = []
deflist = []
rmplist = []
pkg = basepkg
for (planettype, xltindex) in zip(planettypes, xlattabs):
ctres = "planet.%s.colortable" % planettype
xltres = "planet.%s.translatetable" % planettype
defname = planettype
if planettype in headersymbols:
defname = headersymbols[defname]
defname = defname.upper()
ctdef = "%s_COLOR_TAB" % defname
xltdef = "%s_XLAT_TAB" % defname
if xltindex in headersymbols:
oldxltdef = "%s_XLAT_TAB" % headersymbols[xltindex].upper()
else:
oldxltdef = "%s_XLAT_TAB" % xltindex.upper()
ctmatch = [x for x in vals if x[0] == ctdef]
xltmatch = [x for x in vals if x[0] == oldxltdef]
if len(ctmatch) != 1:
raise ValueError, "Couldn't find unique %s" % ctdef
if len(xltmatch) != 1:
raise ValueError, "Couldn't find unique %s" % oldxltdef
ctfile = ctmatch[0][3]
xltfile = xltmatch[0][3]
reslist.append("%3d %3d %3d %s" % (pkg, ctinst, typ, ctres))
reslist.append("%3d %3d %3d %s" % (pkg, xltinst, typ, xltres))
deflist.append("#define %s %s" % (ctdef, scan.res_encode_str(pkg, ctinst, typ)))
deflist.append("#define %s %s" % (xltdef, scan.res_encode_str(pkg, xltinst, typ)))
rmplist.append("%s = STRTAB:%s" % (ctres, ctfile))
rmplist.append("%s = STRTAB:%s" % (xltres, xltfile))
pkg += 1
for l in reslist:
print l
print
print "---"
print
for l in deflist:
print l
print
print "---"
print
for l in rmplist:
print l
if __name__ == '__main__':
write_planet_str()
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/python
import sys
import os
import os.path
import re
import explorer
if len(sys.argv) < 2:
basedir = os.path.join(os.path.pardir, os.path.pardir, "sc2")
else:
basedir = sys.argv[2]
contentdir = os.path.join (basedir, "content")
srcdir = os.path.join (basedir, "src")
verbose = True
def get_type(x):
return x & 0xFF
def get_instance(x):
return (x >> 8) & 0x1FFF
def get_package(x):
return (x >> 21) & 0x7FF
def res_decode(r):
return (get_package(r), get_instance(r), get_type(r))
def res_encode(pkg, instance, t):
return ((pkg & 0x7ff) << 21) | ((instance & 0x1FFF) << 8) | (t & 0xFF)
def res_encode_str (pkg, instance, t):
return "0x%08xL" % res_encode (pkg, instance, t)
def res_decode_str (resnum):
return res_decode (int(long(resnum, 16)))
def parse_packages():
result = {}
pkgnames = explorer.collect_extension(contentdir, '.ls2')
packages = [(x, explorer.read_list(x)) for x in pkgnames]
for (name, pkg) in packages:
name = name[len(contentdir)+1:]
this_index = {}
for ((p, i, t), target) in pkg:
this_index[res_encode(p, i, t)] = target
result[name] = this_index
return result
def parse_resmap():
result = {}
for line in file(os.path.join(contentdir, 'uqm.rmp')):
xs = [x.strip() for x in line.split('=', 1)]
if len (xs) == 2:
if ':' in xs[1]:
vt = xs[1][:xs[1].index(':')]
xs[1] = xs[1][xs[1].index(':')+1:]
else:
vt = "UNKNOWN_RES"
result[xs[0]] = (vt, xs[1])
return result
def get_index_from_header (h):
match = re.search (r"sc2code/comm/([^/]*)/.*\.h", h)
if match != None:
return "comm/%s.ls2" % match.group(1)
match = re.search (r"sc2code/ships/([^/]*)/.*\.h", h)
if match != None:
return "%s.ls2" % match.group(1)
return "starcon.ls2"
def parse_headers(pkgdata, fnamemap):
result = []
used_indices = {}
used_ids = {}
headernames = explorer.collect_res_headers(srcdir)
headerdata = [(x, explorer.read_header(x)) for x in headernames]
for (name, defines) in headerdata:
index = get_index_from_header (name)
name = name[len(srcdir)+1:]
if index in pkgdata:
resmap = pkgdata[index]
for (sym, val) in defines:
try:
(vp, vi, vt) = res_decode_str (val)
trueval = res_encode (vp, vi, vt)
used_indices[trueval]=True
if trueval in resmap:
res_id = resmap[trueval]
used_ids[res_id]=True
if res_id in fnamemap:
(res_type, fname) = fnamemap[res_id]
else:
fname = '--'
res_type = '--'
else:
res_id = '--'
fname = '--'
result.append((name, index, sym, vp,vi,vt, res_id, res_type, fname))
except ValueError:
# This was something that wasn't a resource index
pass
else:
print>>sys.stderr, "Warning: Unknown RES_INDEX '%s'" % index
for pkgname in pkgdata:
pkg = pkgdata[pkgname]
for id in pkg:
if id not in used_indices:
res_id = pkg[id]
used_ids[res_id]=True
if res_id in fnamemap:
fname = fnamemap[res_id]
else:
fname = '--'
(vp, vi, vt) = res_decode(id)
result.append(('--', '--', '--', vp, vi, vt, res_id, fname))
for id in fnamemap:
if id not in used_ids:
result.append(('--', '--', id, fnamemap[id]))
return result
def collect_data ():
return parse_headers (parse_packages(), parse_resmap())
def dump_html(vals):
print """<html>
<head>
<title>UQM Resource Mappings as of 0.6.4</title>
</head>
<body>
<h1>UQM Resource Mappings</h1>
<p>This table lists all of the various <tt>#define</tt>s used in the UQM code, the 32-bit RESOURCE index, the values it ultimately maps to.</p>
<table>
<tr><th>Header file</th><th>Resource File</th><th>Constant</th><th>Resource Number</th><th>Resource Name</th><th>Resource Type</th><th>Default filename</th></tr>"""
for x in vals:
print " <tr><td>%s</td><td>%s</td><td>%s</td><td>%d,%d,%d</td><td>%s</td><td>%s</td><td>%s</td></tr>" % x
print """ </table>
</body>
</html>"""
def dump_csv(vals):
for x in vals:
# Header file this belongs to
# Resource file this belongs to
# Source constant
# package, instance, type
# Resource id string
# Resource type string - must be consistant with type above
# filename
print "%s,%s,%s,%d,%d,%d,%s,%s,%s" % x
if __name__ == '__main__':
vs = collect_data()
# dump_csv(vs)
# print "--------"
dump_html(vs)
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/python
import re
def stripdots(x):
while x.endswith('.'):
x = x[:-1]
while x.startswith('.'):
x = x[1:]
return x
patterns = [("comm/(.*)/(.*)\.mod", lambda m: "comm.%s.music" % m.group(1)),
("comm/(.*)/(.*)\.ogg", lambda m: "comm.%s.music" % m.group(2)),
("comm/(.*)/(.*)\.ani", lambda m: "comm.%s.graphics" % m.group(1)),
("comm/(.*)/(.*)\.ct", lambda m: "comm.%s.colortable" % m.group(1)),
("comm/(.*)/(.*)\.fon", lambda m: "comm.%s.font" % m.group(1)),
("comm/(.*)/(.*)\.txt", lambda m: "comm.%s.dialogue" % m.group(1)),
("comm/(.*)\.lst", lambda m: "comm.%s.resources" % m.group(1)),
("credits/(.*)\.fon", lambda m: "credits.font.%s" % m.group(1)),
("credits/credback\.ani", lambda m: "credits.background"),
("credits/(.*)\.txt", lambda m: "credits.%s" % m.group(1)),
("credits/(.*)\.ogg", lambda m: "credits.%smusic" % m.group(1)),
("ipanims/(.*)\.txt", lambda m: "text.%s" % m.group(1)),
("ipanims/(.*)\.ani", lambda m: "graphics.%s" % m.group(1)),
("ipanims/(.*)\.ct", lambda m: "colortable.%s" % m.group(1)),
("ipanims/(.*)\.xlt", lambda m: "translate.%s" % m.group(1)),
("ipanims/(.*)\.fon", lambda m: "font.%s" % m.group(1)),
("ipanims/(.*)\.snd", lambda m: "sounds.%s" % m.group(1)),
("ipanims/(.*)\.mod", lambda m: "music.%s" % m.group(1)),
("ipanims/(.*)\.ogg", lambda m: "music.%s" % m.group(1)),
("lbm/(.*)\.ani", lambda m: "graphics.%s" % m.group(1)),
("lbm/(.*)\.mod", lambda m: "music.%s" % m.group(1)),
("lbm/(.*)\.ogg", lambda m: "music.%s" % m.group(1)),
("lbm/(.*)\.ct", lambda m: "colortable.%s" % m.group(1)),
("lbm/(.*)\.fon", lambda m: "font.%s" % m.group(1)),
("lbm/(.*)snd\.snd", lambda m: "sounds.%s" % m.group(1)),
("lbm/(.*)\.txt", lambda m: "text.%s" % m.group(1)),
("lbm/mainmenu\.ogg", lambda m: "music.mainmenu"),
("melee/melemenu\.ogg", lambda m: "music.meleemenu"),
("melee/(.*)\.ani", lambda m: "graphics.%s" % m.group(1)),
("slides/ending/sis_skel.ani", lambda m: "graphics.sisskeleton"),
("shofixti/oldcap.ani", lambda m: "ship.shofixti.graphics.oldcaptain"),
("(.*)/(.*)micon\.ani", lambda m: "ship.%s.meleeicons" % m.group(1)),
("(.*)/(.*)icons\.ani", lambda m: "ship.%s.icons" % m.group(1)),
("(.*)/(.*)\.cod", lambda m: "ship.%s.code" % m.group(1)),
("(.*)/(.*)\.snd", lambda m: "ship.%s.sounds" % m.group(1)),
("(.*)/(.*)\.mod", lambda m: "ship.%s.ditty" % m.group(1)),
("(.*)/(.*)\.ogg", lambda m: "ship.%s.ditty" % m.group(1)),
("(.*)/(.*)\.txt", lambda m: "ship.%s.text" % m.group(1)),
("(.*)/(.*)cap\.ani", lambda m: "ship.%s.graphics.captain" % m.group(1)),
("(.*)/(.*)big.*", lambda m: "ship.%s.graphics.%s.large" % (m.group(1), stripdots(m.group(2)))),
("(.*)/(.*)med.*", lambda m: "ship.%s.graphics.%s.medium" % (m.group(1), stripdots(m.group(2)))),
("(.*)/(.*)sml.*", lambda m: "ship.%s.graphics.%s.small" % (m.group(1), stripdots(m.group(2)))),
("(.*)/(.*)\.ani", lambda m: "ship.%s.graphics.%s" % (m.group(1), m.group(2))),
("(.*).lst", lambda m: "ship.%s.resources" % m.group(1))]
def makeid (fname):
for (pattern, response) in patterns:
m = re.match(pattern, fname)
if m is not None:
return response(m)
return None