stuff
This commit is contained in:
parent
e8c81933f1
commit
1477d5263e
119
README.md
119
README.md
@ -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
|
||||
```
|
6
anm.py
6
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)
|
||||
|
||||
|
||||
|
@ -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("<L", fp.read(4))[0]
|
||||
|
||||
|
||||
def read_byte(fp):
|
||||
advance_track(fp.tell(), 1)
|
||||
return struct.unpack("<B", fp.read(1))[0]
|
||||
|
||||
|
||||
def read_float(fp):
|
||||
advance_track(fp.tell(), 4)
|
||||
return struct.unpack("<f", fp.read(4))[0]
|
||||
|
||||
|
||||
def read_short(fp):
|
||||
advance_track(fp.tell(), 2)
|
||||
return struct.unpack("<H", fp.read(2))[0]
|
||||
|
||||
|
||||
@ -22,6 +55,7 @@ def read_string(fp, size):
|
||||
|
||||
|
||||
def read_bytes(fp, size):
|
||||
advance_track(fp.tell(), size)
|
||||
return bytes(struct.unpack('<' + str(size) + 'B', fp.read(size)))
|
||||
|
||||
|
||||
@ -74,29 +108,29 @@ def decompress(compressed_bytes, original_size: int):
|
||||
|
||||
def read_int_and_print(n, b):
|
||||
a = read_int(b)
|
||||
print("%s=%s" % (n, a))
|
||||
debug_print("%s=%s" % (n, a))
|
||||
return a
|
||||
|
||||
|
||||
def read_float_and_print(n, b):
|
||||
a = read_float(b)
|
||||
print("%s=%s" % (n, a))
|
||||
debug_print("%s=%s" % (n, a))
|
||||
return a
|
||||
|
||||
|
||||
def read_byte_and_print(n, b):
|
||||
a = read_byte(b)
|
||||
print("%s=%s" % (n, a))
|
||||
debug_print("%s=%s" % (n, a))
|
||||
return a
|
||||
|
||||
|
||||
def read_short_and_print(n, b):
|
||||
a = read_short(b)
|
||||
print("%s=%s" % (n, a))
|
||||
debug_print("%s=%s" % (n, a))
|
||||
return a
|
||||
|
||||
|
||||
def read_string_until_none_and_print(n, b):
|
||||
s = read_string_until_none(b)
|
||||
print("%s=%s" % (n, s))
|
||||
return s
|
||||
debug_print("%s=%s" % (n, s))
|
||||
return s
|
||||
|
198
lib/skn_anm.py
198
lib/skn_anm.py
@ -4,8 +4,9 @@ from typing import List, Union
|
||||
import math
|
||||
import prettyprinter
|
||||
from prettyprinter import pprint
|
||||
import sys
|
||||
|
||||
prettyprinter.install_extras()
|
||||
prettyprinter.install_extras(exclude=["ipython", "django", "ipython_repr_pretty", "attrs"])
|
||||
|
||||
|
||||
def with_offset(func):
|
||||
@ -35,6 +36,28 @@ ANM_NODE_FLAG_SCL_ANIMATED = (1 << 3)
|
||||
ANM_NODE_FLAG_AFF_ANIMATED = (1 << 4)
|
||||
ANM_NODE_FLAG_USR_ANIMATED = (1 << 5)
|
||||
ANM_NODE_FLAG_ANIMATED = ((1 << 6) - 1)
|
||||
NAM_STRING_KEY = 0
|
||||
NAM_HANDLE_KEY = 1
|
||||
|
||||
|
||||
class ANM_KeyType:
|
||||
@classmethod
|
||||
def get_name(cls, i):
|
||||
for d in cls.__dict__:
|
||||
if cls.__dict__[d] == i:
|
||||
return d
|
||||
return None
|
||||
ANM_KEYS_TYPE_NULL = 0
|
||||
ANM_KEYS_TYPE_REAL_TCB = 1
|
||||
ANM_KEYS_TYPE_REAL_BEZ = 2
|
||||
ANM_KEYS_TYPE_REAL_LIN = 3
|
||||
ANM_KEYS_TYPE_VEC3_TCB = 4
|
||||
ANM_KEYS_TYPE_VEC3_BEZ = 5
|
||||
ANM_KEYS_TYPE_VEC3_LIN = 6
|
||||
ANM_KEYS_TYPE_QUAT_TCB = 7
|
||||
ANM_KEYS_TYPE_QUAT_BEZ = 8
|
||||
ANM_KEYS_TYPE_QUAT_LIN = 9
|
||||
ANM_KEYS_TYPE_AFFINE_SAM = 10
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -62,13 +85,28 @@ class Vec3Indexed(Vec3):
|
||||
@classmethod
|
||||
@with_offset
|
||||
def create(cls, b):
|
||||
x = read_float_and_print("Vec3->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)
|
||||
|
@ -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")
|
||||
|
173
ps2_read.py
Normal file
173
ps2_read.py
Normal file
@ -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()
|
@ -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)
|
||||
|
61
skn.py
61
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()
|
||||
|
Loading…
Reference in New Issue
Block a user