Added parsing support for older lvl format.

This commit is contained in:
lcdr 2016-11-26 14:10:59 +01:00
parent b2946a5c28
commit 60dbb0178d

View File

@ -80,13 +80,15 @@ class LUZViewer(viewer.Viewer):
scene_name = stream.read(str, char_size=1, length_type=c_ubyte) scene_name = stream.read(str, char_size=1, length_type=c_ubyte)
scene = self.tree.insert(scenes, END, text="Scene", values=(filename, scene_id, scene_name)) scene = self.tree.insert(scenes, END, text="Scene", values=(filename, scene_id, scene_name))
assert stream.read(bytes, length=3) assert stream.read(bytes, length=3)
with open(os.path.join(os.path.dirname(luz_path), filename), "rb") as lvl: lvl_path = os.path.join(os.path.dirname(luz_path), filename)
print("Loading lvl", filename) if os.path.exists(lvl_path):
try: with open(lvl_path, "rb") as lvl:
self.parse_lvl(BitStream(lvl.read()), scene) print("Loading lvl", filename)
except Exception: try:
import traceback self.parse_lvl(BitStream(lvl.read()), scene)
traceback.print_exc() except Exception:
import traceback
traceback.print_exc()
assert stream.read(c_ubyte) == 0 assert stream.read(c_ubyte) == 0
### terrain ### terrain
@ -208,46 +210,63 @@ class LUZViewer(viewer.Viewer):
self.tree.insert(waypoint, END, text="Config", values=(config_name, config_type_and_value)) self.tree.insert(waypoint, END, text="Config", values=(config_name, config_type_and_value))
def parse_lvl(self, stream, scene): def parse_lvl(self, stream, scene):
while not stream.all_read(): if stream[0:4] == b"CHNK":
assert stream._read_offset//8 % 16 == 0 # seems everything is aligned like this? # newer lvl file structure
start_pos = stream._read_offset//8 # chunk based
assert stream.read(bytes, length=4) == b"CHNK" while not stream.all_read():
chunktype = stream.read(c_uint) assert stream._read_offset//8 % 16 == 0 # seems everything is aligned like this?
assert stream.read(c_ushort) == 1 start_pos = stream._read_offset//8
assert stream.read(c_ushort) in (1, 2) assert stream.read(bytes, length=4) == b"CHNK"
chunk_length = stream.read(c_uint) chunk_type = stream.read(c_uint)
data_pos = stream.read(c_uint) assert stream.read(c_ushort) == 1
stream._read_offset = data_pos * 8 assert stream.read(c_ushort) in (1, 2)
assert stream._read_offset//8 % 16 == 0 chunk_length = stream.read(c_uint)
if chunktype == 1000: data_pos = stream.read(c_uint)
pass stream._read_offset = data_pos * 8
elif chunktype == 2000: assert stream._read_offset//8 % 16 == 0
pass if chunk_type == 1000:
elif chunktype == 2001: pass
for _ in range(stream.read(c_uint)): elif chunk_type == 2000:
object_id = stream.read(c_int64) # seems like the object id, but without some bits pass
lot = stream.read(c_uint) elif chunk_type == 2001:
unknown1 = stream.read(c_uint) self.lvl_parse_chunk_type_2001(stream, scene)
unknown2 = stream.read(c_uint) elif chunk_type == 2002:
position = stream.read(c_float), stream.read(c_float), stream.read(c_float) pass
rotation = stream.read(c_float), stream.read(c_float), stream.read(c_float), stream.read(c_float) stream._read_offset = (start_pos + chunk_length) * 8 # go to the next CHNK
scale = stream.read(c_float) else:
config_data = stream.read(str, length_type=c_uint) # older lvl file structure
config_data = config_data.replace("{", "<crlbrktopen>").replace("}", "<crlbrktclose>").replace("\\", "<backslash>") # for some reason these characters aren't properly escaped when sent to Tk stream.skip_read(265)
assert stream.read(c_uint) == 0 stream.read(str, char_size=1, length_type=c_uint)
lot_name = "" for _ in range(5):
if lot == 176: stream.read(str, char_size=1, length_type=c_uint)
lot_name = "Spawner - " stream.skip_read(4)
lot = config_data[config_data.index("spawntemplate")+16:config_data.index("\n", config_data.index("spawntemplate")+16)] for _ in range(stream.read(c_uint)):
try: stream.read(c_float), stream.read(c_float), stream.read(c_float)
lot_name += self.db.execute("select name from Objects where id == "+str(lot)).fetchone()[0]
except TypeError: self.lvl_parse_chunk_type_2001(stream, scene)
print("Name for lot", lot, "not found")
lot_name += " - "+str(lot) def lvl_parse_chunk_type_2001(self, stream, scene):
self.tree.insert(scene, END, text="Object", values=(object_id, lot_name, unknown1, unknown2, position, rotation, scale, config_data)) for _ in range(stream.read(c_uint)):
elif chunktype == 2002: object_id = stream.read(c_int64) # seems like the object id, but without some bits
pass lot = stream.read(c_uint)
stream._read_offset = (start_pos + chunk_length) * 8 # go to the next CHNK unknown1 = stream.read(c_uint)
unknown2 = stream.read(c_uint)
position = stream.read(c_float), stream.read(c_float), stream.read(c_float)
rotation = stream.read(c_float), stream.read(c_float), stream.read(c_float), stream.read(c_float)
scale = stream.read(c_float)
config_data = stream.read(str, length_type=c_uint)
config_data = config_data.replace("{", "<crlbrktopen>").replace("}", "<crlbrktclose>").replace("\\", "<backslash>") # for some reason these characters aren't properly escaped when sent to Tk
assert stream.read(c_uint) == 0
lot_name = ""
if lot == 176:
lot_name = "Spawner - "
lot = config_data[config_data.index("spawntemplate")+16:config_data.index("\n", config_data.index("spawntemplate")+16)]
try:
lot_name += self.db.execute("select name from Objects where id == "+str(lot)).fetchone()[0]
except TypeError:
print("Name for lot", lot, "not found")
lot_name += " - "+str(lot)
self.tree.insert(scene, END, text="Object", values=(object_id, lot_name, unknown1, unknown2, position, rotation, scale, config_data))
def on_item_select(self, _): def on_item_select(self, _):
item = self.tree.selection()[0] item = self.tree.selection()[0]