From 1477d5263e43c93c7536f12c2ed831d3caa1816d Mon Sep 17 00:00:00 2001 From: Hipstercat Date: Sun, 30 May 2021 00:27:11 +0200 Subject: [PATCH] stuff --- README.md | 119 ---------------------------- anm.py | 6 +- lib/fileutils.py | 46 +++++++++-- lib/skn_anm.py | 198 +++++++++++++++++++++++++++++++++-------------- obj2gbs.py | 1 - ps2_read.py | 173 +++++++++++++++++++++++++++++++++++++++++ read_gzp.py | 6 +- skn.py | 61 ++++++++++++++- 8 files changed, 423 insertions(+), 187 deletions(-) delete mode 100644 README.md create mode 100644 ps2_read.py diff --git a/README.md b/README.md deleted file mode 100644 index f26133d..0000000 --- a/README.md +++ /dev/null @@ -1,119 +0,0 @@ -Giants Map Objects Extractor -============================ - -This tool is used to get what objects are in a map. It outputs the objects model and coords and doesn't do anything else yet. - -How it works ------------- - -Basically maps are just a zip file that contains a terrain file (.gti) and a meta file (.bin) which stores objects on the map. - -Objects in this file are stored using the following format: -``` -... -2a -> static byte which indicate the start of an object definition -model -> 4 bytes long value to indicate the model of the object -x -> 4 bytes float value -y -> 4 bytes float value -z -> 4 bytes float value -angle -> 4 bytes float value -... -``` - -Usage ----- - -``` -C:\Projects\gck-map-extract-objects> python .\extract.py -usage: extract.py [-h] map_file -extract.py: error: the following arguments are required: map_file -``` - -Example -------- - -``` -extract.py "MvM - Ultimate Winter Duel.gck" -2019-05-24 11:00:00,229 - __main__ - INFO - Opening MvM - Ultimate Winter Duel.gck -2019-05-24 11:00:00,230 - __main__ - INFO - Found file default.gti -2019-05-24 11:00:00,230 - __main__ - INFO - Found file w_M_Mecc_Ultimate Winter Duel.bin -2019-05-24 11:00:00,230 - __main__ - INFO - Found BIN file w_M_Mecc_Ultimate Winter Duel.bin -2019-05-24 11:00:00,230 - __main__ - INFO - Opening w_M_Mecc_Ultimate Winter Duel.bin -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=49 x=-469.0 y=-859.0 z=0.0 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-7.300000190734863 y=-652.510009765625 z=83.86000061035156 angle=-35.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-19.989999771118164 y=-88.2699966430664 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=1319 x=-195.02000427246094 y=-850.3099975585938 z=175.27999877929688 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-188.91000366210938 y=-23.510000228881836 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=193.85000610351562 y=-23.510000228881836 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-271.79998779296875 y=-937.969970703125 z=180.5800018310547 angle=-312.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=1285 x=-4.340000152587891 y=108.41000366210938 z=33.72999954223633 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=522 x=18.65999984741211 y=116.0999984741211 z=34.0099983215332 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=323.6099853515625 y=-876.6900024414062 z=201.82000732421875 angle=-151.6699981689453 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=1319 x=344.6300048828125 y=-904.1099853515625 z=201.82000732421875 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-260.9599914550781 y=132.4199981689453 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-153.16000366210938 y=-1101.010009765625 z=83.86000061035156 angle=-322.6700134277344 -2019-05-24 11:00:00,231 - __main__ - INFO - Object model=679 x=-172.30999755859375 y=273.4100036621094 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=679 x=285.4599914550781 y=197.58999633789062 z=1.2899999618530273 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1051 x=398.67999267578125 y=131.8300018310547 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=679 x=152.89999389648438 y=308.9200134277344 z=5.579999923706055 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=679 x=3.630000114440918 y=342.75 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1319 x=711.719970703125 y=-443.30999755859375 z=48.470001220703125 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=679 x=6.340000152587891 y=-1206.72998046875 z=83.86000061035156 angle=-191.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1050 x=741.4400024414062 y=-413.0400085449219 z=48.470001220703125 angle=-127.66999816894531 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=981 x=8.890000343322754 y=-1259.68994140625 z=83.86000061035156 angle=180.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1317 x=-893.8900146484375 y=-381.3900146484375 z=0.0 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1306 x=-267.07000732421875 y=479.6000061035156 z=4.239999771118164 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1050 x=-676.7000122070312 y=379.6300048828125 z=83.86000061035156 angle=81.66999816894531 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1320 x=-646.2100219726562 y=403.239990234375 z=83.86000061035156 angle=0.0 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=679 x=-399.5199890136719 y=-1388.6600341796875 z=169.30999755859375 angle=-207.3300018310547 -2019-05-24 11:00:00,232 - __main__ - INFO - Object model=1317 x=994.530029296875 y=-537.030029296875 z=0.0 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=257 x=-497.5 y=685.260009765625 z=48.130001068115234 angle=56.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1308 x=-382.2799987792969 y=-1584.050048828125 z=93.37999725341797 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=679 x=139.1699981689453 y=-1660.030029296875 z=269.6499938964844 angle=-191.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1319 x=178.2899932861328 y=-1661.4200439453125 z=269.6499938964844 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=679 x=77.22000122070312 y=919.5399780273438 z=83.86000061035156 angle=36.66999816894531 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1319 x=-316.8699951171875 y=950.2999877929688 z=78.8499984741211 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1319 x=209.67999267578125 y=1057.9200439453125 z=175.27999877929688 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1317 x=1045.1500244140625 y=585.3200073242188 z=0.0 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=679 x=-261.4700012207031 y=1129.1199951171875 z=201.82000732421875 angle=144.6699981689453 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1319 x=-318.7300109863281 y=1154.6800537109375 z=201.82000732421875 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=679 x=288.1300048828125 y=1146.27001953125 z=176.6199951171875 angle=-135.6699981689453 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1317 x=869.0900268554688 y=-1661.699951171875 z=0.0 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1317 x=-887.760009765625 y=929.8800048828125 z=0.0 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1317 x=-983.75 y=-1688.030029296875 z=0.0 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=1319 x=-111.12000274658203 y=-2063.580078125 z=169.3800048828125 angle=0.0 -2019-05-24 11:00:00,235 - __main__ - INFO - Object model=679 x=188.22000122070312 y=1288.4100341796875 z=83.86000061035156 angle=-135.6699981689453 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=679 x=47.5 y=1457.300048828125 z=83.86000061035156 angle=-5.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=981 x=46.77000045776367 y=1507.9599609375 z=83.86000061035156 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=679 x=468.04998779296875 y=1627.6600341796875 z=169.3800048828125 angle=-77.66999816894531 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=1317 x=64.48999786376953 y=-2515.27001953125 z=0.0 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=1308 x=422.0299987792969 y=1821.6500244140625 z=89.43000030517578 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=679 x=-90.0 y=1902.81005859375 z=269.6499938964844 angle=-5.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=1319 x=-70.79000091552734 y=1924.3399658203125 z=269.6499938964844 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=1317 x=1032.449951171875 y=1683.0 z=0.0 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=1317 x=-779.9600219726562 y=2074.550048828125 z=0.0 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=1317 x=328.82000732421875 y=2709.030029296875 z=0.0 angle=0.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=61.81365966796875 y=43.321990966796875 z=33.72548294067383 angle=30.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=-69.09912109375 y=63.499755859375 z=33.72548294067383 angle=270.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=111.51863098144531 y=117.34283447265625 z=33.72548294067383 angle=180.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=99.72610473632812 y=189.97406005859375 z=33.72548294067383 angle=59.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=-57.904052734375 y=136.96914672851562 z=33.72548294067383 angle=80.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=-30.401458740234375 y=187.08465576171875 z=33.72548294067383 angle=270.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=-15.68878173828125 y=63.614349365234375 z=33.72548294067383 angle=180.0 -2019-05-24 11:00:00,236 - __main__ - INFO - Object model=830 x=37.35343933105469 y=188.96652221679688 z=33.72548294067383 angle=270.0 -2019-05-24 11:00:00,237 - __main__ - INFO - Number of objects: 62 -2019-05-24 11:00:00,237 - __main__ - INFO - Model 679 was found 22 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1317 was found 10 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1319 was found 9 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 830 was found 8 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1050 was found 2 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 981 was found 2 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1308 was found 2 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 49 was found 1 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1285 was found 1 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 522 was found 1 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1051 was found 1 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1306 was found 1 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 1320 was found 1 times -2019-05-24 11:00:00,237 - __main__ - INFO - Model 257 was found 1 times -``` \ No newline at end of file diff --git a/anm.py b/anm.py index 000fb80..166b17e 100644 --- a/anm.py +++ b/anm.py @@ -1,14 +1,16 @@ from lib.skn_anm import * +import os -def read_skn(filepath) -> AnmAnim: +def read_anm(filepath) -> AnmAnim: with open(filepath, "rb") as fp: + init_filetrack(os.fstat(fp.fileno()).st_size) r = AnmFile.parse(fp, AnmAnim) return r def main(): - anm = read_skn("/home/tasty/Projects/gck-map-extract-objects/anm_skn/Mc_salute.anm") + anm = read_anm("/home/tasty/Projects/gck-map-extract-objects/anm_skn/verm_fly.anm") pprint(anm) diff --git a/lib/fileutils.py b/lib/fileutils.py index 0569142..d78de7f 100644 --- a/lib/fileutils.py +++ b/lib/fileutils.py @@ -1,19 +1,52 @@ import struct +file_track = [] +print_debug = False + + +def debug_print(s): + if print_debug: + print(s) + + +def init_filetrack(size): + global file_track + file_track = [0] * size + + +def advance_track(offset, size): + if not file_track: + return + for i in range(size): + file_track[offset+i] = 1 + + +def stat_track(): + r = 0 + total = len(file_track) + for i in file_track: + if i == 1: + r += 1 + return r/total*100 + def read_int(fp): + advance_track(fp.tell(), 4) return struct.unpack("x", b) - y = read_float_and_print("Vec3->y", b) - z = read_float_and_print("Vec3->z", b) - index = read_int_and_print("Vec3->index", b) + x = read_float_and_print("Vec3Indexed->x", b) + y = read_float_and_print("Vec3Indexed->y", b) + z = read_float_and_print("Vec3Indexed->z", b) + index = read_int_and_print("Vec3Indexed->index", b) return cls(x=x, y=y, z=z, index=index) +@dataclass +class Vec3IndexedWeighted(Vec3Indexed): + weight: float + + @classmethod + @with_offset + def create(cls, b): + x = read_float_and_print("Vec3IndexedWeighted->x", b) + y = read_float_and_print("Vec3IndexedWeighted->y", b) + z = read_float_and_print("Vec3IndexedWeighted->z", b) + index = read_int_and_print("Vec3IndexedWeighted->index", b) + weight = read_float_and_print("Vec3IndexedWeighted->weight", b) + return cls(x=x, y=y, z=z, index=index, weight=weight) + + @dataclass class Vec4(Vec3): w: float @@ -108,6 +146,7 @@ class AnmKeys: @with_offset def create(cls, b): keys_type = read_byte_and_print("ANM_Keys->Type", b) + debug_print("ANM_KeyType: %s" % ANM_KeyType.get_name(keys_type)) ort_before = read_byte_and_print("ANM_Keys->ORTBefore", b) ort_after = read_byte_and_print("ANM_Keys->ORTAfter", b) flags = read_byte_and_print("ANM_Keys->Flags", b) @@ -161,7 +200,7 @@ class AnmObj: class AnmCluster: custom: int = field(repr=False) obj: Union[AnmObj, None] = field(repr=False) - handle: int = field(repr=False) + handle: int bounding_box: List[Vec3] = field(repr=False) # size 2 num_vertices: int vertices: List[Vec3Indexed] = field(repr=False) @@ -196,58 +235,101 @@ class NamDictionnary: def create(cls, b, depth=1): r = {} - read_int_and_print("NAM_Dictionnary->pMemGroup", b) - namemapper = read_int_and_print("NAM_Dictionnary->pNameMapper", b) - flags = read_int_and_print("NAM_Dictionnary->Flags", b) - print("Flags: NAM_FlagHasHandles: %s, NAM_FlagCaseInsensitive: %s" % ( + read_int_and_print("NAM_Dictionnary->MemGroup", b) # MAP_MemGroup* + namemapper = read_int_and_print("NAM_Dictionnary->pNameMapper", b) # MAP_Mapper* + flags = read_int_and_print("NAM_Dictionnary->Flags", b) # X_BOOL + debug_print("Flags: NAM_FlagHasHandles: %s, NAM_FlagCaseInsensitive: %s" % ( flags & NAM_FlagHasHandles, flags & NAM_FlagCaseInsensitive)) - read_short_and_print("NAM_Dictionnary->NameHandle", b) + read_short_and_print("NAM_Dictionnary->NameHandle", b) # NAM_NameHandle -> X_UINT16 b.seek(namemapper) - read_int_and_print("pMemGroup", b) - read_int_and_print("MemBaseSize", b) - read_int_and_print("MemBlocks", b) - read_int_and_print("MemSize", b) - read_int_and_print("MemFree", b) - read_int_and_print("pMem", b) - read_int_and_print("MaxMappings", b) - totalmappings = read_int_and_print("TotalMappings", b) - read_int_and_print("TotalKeys", b) - p_key_contexts = read_int_and_print("pKeyContexts", b) + read_int_and_print("MemGroup*", b) # MAP_MemGroup* + read_int_and_print("MemBaseSize", b) # X_UINT + read_int_and_print("MemBlocks", b) # X_UINT + read_int_and_print("MemSize", b) # X_UINT + read_int_and_print("MemFree", b) # X_UINT + read_int_and_print("Mem*", b) # MAP_Mapping* + read_int_and_print("MaxMappings", b) # X_UINT + totalmappings = read_int_and_print("TotalMappings", b) # X_UINT + total_keys = read_int_and_print("TotalKeys", b) # X_UINT + p_key_contexts = read_int_and_print("KeyContexts*", b) # MAP_KeyContext* - b.seek(p_key_contexts) - _ = read_int_and_print("\tSize", b) - read_int_and_print("\tpCallback", b) - read_int_and_print("\tIndex", b) - read_int_and_print("\tTest", b) - p_lut = read_int_and_print("pLUT", b) - read_int_and_print("Reserve", b) - read_int_and_print("pData", b) + for key in range(total_keys): + key_context_size = [ + 4, # X_UINT Size + 4, # MAP_BinSearchCallback* Callback + 4, # X_UINT Index + 4, # X_INT Test + 4, # MAP_Mapping **LUT + 4, # X_UINT Reserve + 4, # X_VOID *Data + ] + key_context_size = sum(key_context_size) + key_context_begin = p_key_contexts + key * key_context_size + debug_print("getting keys for type %s" % key) + b.seek(key_context_begin) # NAM_Dictionnary.KeyContexts[KEY] + # we are now in the KeyContext for type "key" + debug_print("Current keycontext: %s" % b.tell()) + keytype_size = read_int_and_print("\tSize", b) # MAP_BinSearchContext -> X_UINT + read_int_and_print("\t\tpCallback", b) # MAP_BinSearchContext -> MAP_BinSearchCallback* + read_int_and_print("\t\tIndex", b) # MAP_BinSearchContext -> X_UINT + read_int_and_print("\t\tTest", b) # MAP_BinSearchContext -> X_INT + p_lut = read_int_and_print("\tMAP_Mapping** LUT", b) # MAP_Mapping** + read_int_and_print("\tReserve", b) # X_UINT + read_int_and_print("\tpData", b) # X_VOID* - for i in range(totalmappings): - b.seek(p_lut) - pindx = read_int(b) - for _ in range(i): - pindx = read_int(b) - b.seek(pindx) - if not flags & NAM_FlagHasHandles: - read_short_and_print("pPtr", b) - read_short_and_print("pPtr2", b) - val = read_int_and_print("Value", b) - name = read_string_until_none_and_print("name", b) - if depth > 1: - item = NamDictionnary.create(cls, b, depth - 1, offset=val) - else: - item = cls.create(b, offset=val) - r[name] = item - else: - refcnt = read_short_and_print("RefCnt", b) - handle = read_short_and_print("Handle", b) - read_int_and_print("Test", b) - read_int_and_print("Test", b) - bone_name = read_string_until_none_and_print("BoneName", b) - r[str(i)] = {"BoneName": bone_name} + # i=0; tant que l'addresse que renvoie MAP_MappingGet (Dictionary->NameMapper, i, NAM_STRING_KEY) != 0; i++ + # mappingget: return Mapper->KeyContexts[Key].LUT[Index]; + """ + + """ + key_index = 0 + while True: + if key_index >= totalmappings: + break + b.seek(p_lut + key_index * 4) # NAM_Dictionnary.KeyContexts[KEY].LUT[INDEX] -> LA je suis au MAP_Mapping* == NAM_Name* + debug_print("MAP_Mapping*") + addr_begin_mapping = read_int_and_print("MAP_Mapping*", b) # MAP_MapIndex* -> X_UINT16* + if addr_begin_mapping == 0: + break + b.seek(addr_begin_mapping) + # we are now in MAP_Mapping == NAM_Name header + """ + struct _MAP_Mapping + { + MAP_MapIndex TotalSize; + }; + typedef X_UINT16 MAP_MapIndex; + """ + debug_print("MAP_Mapping") + read_short_and_print("TotalSize", b) # MAP_MapIndex* -> X_UINT16* + after_mapping = b.tell() + b.seek(after_mapping + key * 2) + debug_print("MAP_MapIndex at %s" % b.tell()) + index = read_short_and_print("MAP_MapIndex value", b) + + b.seek(addr_begin_mapping+index) + debug_print("STRINGDATA* OU HANDLEDATA* at %s" % b.tell()) + # pdata = read_int_and_print("Data*", b) + # b.seek(pdata) + if key == NAM_STRING_KEY: + val = read_int_and_print("ValueOrCustom", b) # X_INT or X_VOID* + name = read_string_until_none_and_print("name", b) + if flags & NAM_FlagHasHandles: + r[key_index] = {"Name": name} + elif depth > 1: + item = NamDictionnary.create(cls, b, depth - 1, offset=val) + r[name] = item + else: + item = cls.create(b, offset=val) + r[name] = item + if key == NAM_HANDLE_KEY: + read_short_and_print("RefCnt", b) # NAM_NameRefCnt == X_UINT16 + handle = read_short_and_print("Handle", b) # NAM_NameHandle == X_UINT16 + r[key_index]["Handle"] = handle + key_index += 1 + debug_print("Key_index=%s" % key_index) return r @@ -438,11 +520,15 @@ class AnmSkin: @staticmethod def link(nodedict, defaultobjtree): + + m = {} + for node_index in nodedict: + node = nodedict[node_index] + m[node["Handle"]] = node["Name"] + for obj_name, obj in defaultobjtree.items(): for cluster in obj.clusters: - cluster_handle = cluster.handle - k = str(cluster_handle - 1) - cluster.bone_name = nodedict[k]["BoneName"] + cluster.bone_name = m[cluster.handle] @classmethod @with_offset @@ -463,7 +549,7 @@ class AnmSkin: treedict = NamDictionnary.create(AnmObj, b, depth=2, offset=tree) defaultobjdict = NamDictionnary.create(AnmObj, b, offset=defaultobj) - # AnmSkin.link(nodedict, defaultobjdict) + AnmSkin.link(nodedict, defaultobjdict) return cls(custom=custom, file_version=version, image=image, memgroup=memgroup, node_dictionnary=nodedict, tree_dictionnary=treedict, default_obj_dictionnary=defaultobjdict, total_number_trees=num_trees, total_number_objs=num_objs, total_number_clusters=num_clusters, name=name) diff --git a/obj2gbs.py b/obj2gbs.py index a8af783..323dab4 100644 --- a/obj2gbs.py +++ b/obj2gbs.py @@ -391,7 +391,6 @@ def convert_obj(path): output = "%s/%s.gbs" % (os.path.dirname(os.path.abspath(path)), os.path.basename(path)) print("Done! Output: %s" % output) - if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("path") diff --git a/ps2_read.py b/ps2_read.py new file mode 100644 index 0000000..6f5712b --- /dev/null +++ b/ps2_read.py @@ -0,0 +1,173 @@ +import argparse +import os.path + +from lib.fileutils import * +from lib.packet import Packet + + +def ftell(fp): + return hex(fp.tell()) + + +def read_bin(_input: str, _output: str): + with open(_input, "rb") as fp: + # read 0x30 bytes + fileversion = read_int(fp) + render_data = read_int(fp) + texturesmemory_size = read_int(fp) + unk2_size = read_int(fp) + objects_size = read_int(fp) + some_bytes = read_int(fp) + fx_size = read_int(fp) + world_size = read_int(fp) + huds_size = read_int(fp) + worldflags_size = read_int(fp) + unk = read_int(fp) + unk = read_int(fp) + + print("[%s] Game is %s bytes" % (ftell(fp), render_data)) + read_bytes(fp, render_data) + + print("[%s] World is %s bytes..." % (ftell(fp), world_size)) + read_bytes(fp, world_size) + + print("[%s] Texturesmemory is %s bytes..." % (ftell(fp), texturesmemory_size)) + texturesmemory = read_bytes(fp, texturesmemory_size) + + print("[%s] FX %s bytes..." % (ftell(fp), fx_size)) + read_bytes(fp, fx_size) + + print("[%s] unk2 %s bytes..." % (ftell(fp), unk2_size)) + read_bytes(fp, unk2_size) + + print("[%s] worldflags %s bytes..." % (ftell(fp), worldflags_size)) + read_bytes(fp, worldflags_size) + + print("[%s] huds %s bytes..." % (ftell(fp), huds_size)) + read_bytes(fp, huds_size) + + print("[%s] objects %s bytes..." % (ftell(fp), objects_size)) + objects = read_bytes(fp, objects_size) + + print("[%s] textures_attributes? %s bytes..." % (ftell(fp), some_bytes)) + # textures_attributes = read_bytes(fp, some_bytes) + + first_int = read_int(fp) + print("[%s] First int: %s" % (ftell(fp), first_int)) + + second_int = read_int(fp) + print("Second int: %s" % second_int) + + with open(_output, "wb") as fp: + fp.write(texturesmemory) + + print("Done") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("input_bin", help="PS2 bin file to read") + parser.add_argument("output_file", help="output bin for objects") + args = parser.parse_args() + read_bin(args.input_bin, args.output_file) + + +def read_textures(file_input): + print("Reading %s" % file_input) + + curr = 0 + + with open(file_input, "rb") as fp: + content = fp.read() + + while curr < len(content): + byte_index = content.find(b"END-OF-FIL", curr) + if byte_index != -1: + byte_index += 0xc + print("content: %s (%s)" % (content[byte_index], hex(content[byte_index]))) + while content[byte_index] == 0x2a or content[byte_index] == 0x00: + byte_index += 1 + + print("found texture at %s: %s %s" % (hex(byte_index), hex(content[byte_index]), hex(content[byte_index+1]))) + # after CLUTS + byte_index += 0x20 + p = Packet(content) + p.seek(byte_index) + # psm = p.get_short() + psm = content[byte_index] + psm = psm << 8 & 0x3f + + d_comp = p.get_long() + d_comp = p.get_long() + is_compressed = d_comp >> 0x12 & 0xf + compare = d_comp >> 0xe & 0xf + + if is_compressed != compare: + print(hex(d_comp)) + new_compare = compare - is_compressed + if new_compare <= 0: + print("ERROOOOOOOOOR") + if new_compare == 1: + decomp_bytes = 2 + elif new_compare == 2: + decomp_bytes = 3 + elif new_compare == 3: + decomp_bytes = 4 + else: + print("ERROOOOOOOOOOR: %s" % new_compare) + print("decomp_bytes: %s" % decomp_bytes) + print("psm: %s -> %s (compressed: %s, compare: %s)" % (psm, get_pixel_format(psm), is_compressed, compare)) + + curr = byte_index+1 + else: + curr = len(content) + + +def get_pixel_format(psm) -> str: + _data = { + 0: "PSMCT32", + 1: "PSMCT24", + 2: "PSMCT16", + 10: "PSMCT16S", + 19: "PSMT8", + 20: "PSMT4", + 27: "PSMT8H", + 26: "PSMT4HL", + 44: "PSMT4HH", + 48: "PSMZ32", + 49: "PSMZ24", + 50: "PSMZ16", + 58: "PSMZ16S", + } + + return _data.get(psm, "UNKNOWN") + + +def read_sizes(): + print("=====================================================================================") + print("=====================================================================================") + print("=====================================================================================") + print("=====================================================================================") + print("=====================================================================================") + print("=====================================================================================") + print("=====================================================================================") + parser = argparse.ArgumentParser() + parser.add_argument("input_bin", help="PS2 bin file to read") + args = parser.parse_args() + + all_num = 0 + + if os.path.isdir(args.input_bin): + for currdir, dirs, files in os.walk(args.input_bin): + for file in files: + if file.lower().endswith(".bin"): + read_textures(currdir+"/"+file) + else: + read_textures(args.input_bin) + + print("textures:%s" % all_num) + + +if __name__ == '__main__': + # main() + read_sizes() diff --git a/read_gzp.py b/read_gzp.py index a286995..fb2a050 100644 --- a/read_gzp.py +++ b/read_gzp.py @@ -49,9 +49,9 @@ def extract_gzp(gzp_file, extensions, output_dir): logger.info("Checksum OK") meta_info_offset = read_int(gzp_fp) - gzp_fp.seek(meta_info_offset) unk = read_int(gzp_fp) + print(unk) entries_count = read_int(gzp_fp) if entries_count == 0: @@ -69,6 +69,9 @@ def extract_gzp(gzp_file, extensions, output_dir): compression = read_byte(gzp_fp) # compression: 1 if compressed else 0 name_length = read_byte(gzp_fp) name = read_bytes(gzp_fp, name_length).decode("utf8").strip('\x00') + file_without_ext = ".".join(name.split(".")[0:-1]) + ext = name.split(".")[-1] + logger.info(name + " compression: " + str(compression) + ", filesize: " + sizeof_fmt( original_size) + ", start: " + str(content_offset)) @@ -91,6 +94,7 @@ def extract_gzp(gzp_file, extensions, output_dir): logger.info("File is compressed, decompressing it") buffer = decompress(buffer, original_size) + name = "%s.%s.%s" % (file_without_ext, os.path.basename(gzp_file), ext) logger.info("Writing file " + name) if not os.path.exists(output_dir): os.mkdir(output_dir) diff --git a/skn.py b/skn.py index e5915f8..ac8c13c 100644 --- a/skn.py +++ b/skn.py @@ -1,14 +1,17 @@ from lib.skn_anm import * +from lib.gbs import * def read_skn(filepath) -> AnmSkin: with open(filepath, "rb") as fp: + init_filetrack(os.fstat(fp.fileno()).st_size) r = AnmFile.parse(fp, AnmSkin) + print("Read %s%% of file" % stat_track()) return r -def main(): - f = ["/home/tasty/Projects/gck-map-extract-objects/anm_skn/rp_l0.skn"] +def test(): + f = ["/home/tasty/Projects/gck-map-extract-objects/anm_skn/Verm_l0.skn"] my_vertex = Vec3(-0.927200, 0.099500, 3.108000) mini_dist_v = Vec3(0, 0, 0) for p in f: @@ -24,5 +27,59 @@ def main(): print("%s: dist=%s" % (mini_dist_v, mini_dist_v.distance(my_vertex))) +def print_vertices(): + skn = read_skn("/home/tasty/Projects/gck-map-extract-objects/test/rp_l0.apatch.gzp.skn") + for obj_name in skn.default_obj_dictionnary: + obj = skn.default_obj_dictionnary[obj_name] + for cluster in obj.clusters: + for vertex in cluster.vertices: + print("v %s %s %s" % (vertex.x, vertex.y, vertex.z)) + + +def link_gbs_skn(): + basepath = "/home/tasty/Projects/gck-map-extract-objects/test/rp_l0.apatch.gzp" + skn = read_skn(basepath+".skn") + gbs = GbsData() + gbs.read(basepath+".gbs") + + vbase = 0 + with open("test.obj", "w") as fp: + for obj_name, obj in skn.default_obj_dictionnary.items(): + for cluster in obj.clusters: + for vertex in cluster.vertices: + base_vertex_i = vertex.index + vbase + base_vertex = gbs.vertices[base_vertex_i] + new_vertex = Vec3(base_vertex.x + vertex.x, base_vertex.y + vertex.y, base_vertex.z + vertex.z) + fp.write("v %s %s %s\n" % (new_vertex.x, new_vertex.y, new_vertex.z)) + vbase += obj.total_number_vertices + + +def main(): + skn = read_skn("/home/tasty/Projects/gck-map-extract-objects/test/rp_l0.apatch.gzp.skn") + pprint(skn) + vbase = 0 + for tree in skn.tree_dictionnary: + for obj_name in skn.tree_dictionnary[tree]: + print(obj_name) + obj = skn.tree_dictionnary[tree][obj_name] + for cluster in obj.clusters: + if cluster.num_vertices <= 0: + print("NO VERTICES") + for vertex in cluster.vertices: + pass + # print("vertex %s -> %s" % (vertex.index, vertex.index + vbase)) + vbase += obj.total_number_vertices + + with open("test.obj", "w") as fp: + vbase = 0 + for obj_name, obj in skn.default_obj_dictionnary.items(): + for cluster in obj.clusters: + # fp.write("name %s %s %s %s %s %s %s\n" % (cluster.bone_name.strip().replace(" ", ""), cluster.bounding_box[0].x, cluster.bounding_box[0].y, cluster.bounding_box[0].z, cluster.bounding_box[1].x, cluster.bounding_box[1].y, cluster.bounding_box[1].z)) + for vertex in cluster.vertices: + fp.write("index %s\n" % (vertex.index + vbase)) + # fp.write("offset %s %s %s\n" % (vertex.x, vertex.y, vertex.z)) + vbase += obj.total_number_vertices + + if __name__ == "__main__": main()