Skip to content

Commit

Permalink
reverse physmat, improve ms2 collision layers
Browse files Browse the repository at this point in the history
  • Loading branch information
HENDRIX-ZT2 committed Nov 12, 2023
1 parent c52441d commit c78b349
Show file tree
Hide file tree
Showing 18 changed files with 386 additions and 41 deletions.
13 changes: 13 additions & 0 deletions experimentals/physmat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from generated.formats.ovl_base import OvlContext
from generated.formats.physmat.compounds.PhysmatRoot import PhysmatRoot

files = ("C:/Users/arnfi/Desktop/pz.physmat", "C:/Users/arnfi/Desktop/jwe2.physmat")
for fp in files:
with open(fp, "rb") as f:
mat = PhysmatRoot.from_stream(f, OvlContext())
print(mat)
for s in ("all_surfaces_names", "surface_res_names", "classnames_names"):
print("\n\n")
print(s)
for ind, offset in enumerate(getattr(mat, s)):
print(ind, mat.names.get_str_at(offset))
33 changes: 20 additions & 13 deletions generated/formats/ms2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,21 +490,28 @@ def clear(self):
# m.load("C:/Program Files (x86)/Steam/steamapps/common/Jurassic World Evolution 2/Win64/ovldata/walker_export/ContentPDLC5/Buildings/ModularStructures/LAG_NaturalWaterPool_Malta/LAG_NaturalWaterPool_Malta/models.ms2", read_editable=True)
# m.load("C:/Program Files (x86)/Steam/steamapps/common/Jurassic World Evolution 2/Win64/ovldata/walker_export/Content0/Buildings/Shared/Props/CharacterScale/CharacterScale/models.ms2", read_editable=True)
# m.load("C:/Program Files (x86)/Steam/steamapps/common/Planet Zoo/win64/ovldata/walker_export/Content0/Animals/Aardvarks/Aardvark/Aardvark_Female/Aardvark_Female/aardvark_female_.ms2", read_editable=True)
m.load("C:/Program Files (x86)/Steam/steamapps/common/Planet Zoo/win64/ovldata/walker_export/Content0/Animals/Big_Cats/Bengal_Tiger/Bengal_Tiger_Male/Bengal_Tiger_Male/bengal_tiger_male_.ms2", read_editable=True)
# m.load("C:/Program Files (x86)/Steam/steamapps/common/Planet Zoo/win64/ovldata/walker_export/Content0/Animals/Big_Cats/Bengal_Tiger/Bengal_Tiger_Male/Bengal_Tiger_Male/bengal_tiger_male_.ms2", read_editable=True)
# m.load("C:/Users/arnfi/Desktop/visual_lagoon_working.ms2", read_editable=True)
# m.load("C:/Users/arnfi/Desktop/visual_lagoon_no_optimizer.ms2", read_editable=True)
m.load("C:/Users/arnfi/Desktop/swizzled.ms2", read_editable=True)
# for i, bone_info in enumerate(m.models_reader.bone_infos):
# for bi, bone in enumerate(bone_info.bones):
# print(bi, bone.name)
# # for bi, bone in enumerate(bone_info.bones):
# # print(bi, bone.name)
# joints = bone_info.joints
# # test for orthogonal vecs
# # for ragdoll in joints.ragdoll_constraints:
# # ragdoll.x.max = 0
# # ragdoll.x.min = 0
# # # ragdoll.z.max = 0
# # ragdoll.z.min = 0
# # print(ragdoll.parent, ragdoll.child)
# # print(ragdoll.rot.data)
# # print(np.linalg.inv(ragdoll.rot.data))
# m.save("C:/Users/arnfi/Desktop/dlc11_stripdoors_.ms2")
# for j in joints.joint_infos:
# for hc in j.hitchecks:
# print(hc)
# hc.collider.is_optimized = 0
# # # test for orthogonal vecs
# # # for ragdoll in joints.ragdoll_constraints:
# # # ragdoll.x.max = 0
# # # ragdoll.x.min = 0
# # # # ragdoll.z.max = 0
# # # ragdoll.z.min = 0
# # # print(ragdoll.parent, ragdoll.child)
# # # print(ragdoll.rot.data)
# # # print(np.linalg.inv(ragdoll.rot.data))
# m.save("C:/Users/arnfi/Desktop/visual_lagoon_no_optimizer.ms2")
print(m)

# INFO | size 8 / count 1 = 8.0 in /PDLC_WorldFair/Rides/Coasters/Tracks/Track_003/Track_003/models.ms2; 0
Expand Down
12 changes: 6 additions & 6 deletions generated/formats/ms2/compounds/HitCheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def __init__(self, context, arg=0, template=None, set_default=True):

# probably a bitfield, not sure though, might be a list of ubytes too
self.collision_layers = name_type_map['Uint64'](self.context, 0, None)
self.collision_ignore = name_type_map['OffsetString'](self.context, self.arg, None)
self.collision_use = name_type_map['OffsetString'](self.context, self.arg, None)
self.classification_name = name_type_map['OffsetString'](self.context, self.arg, None)
self.surface_name = name_type_map['OffsetString'](self.context, self.arg, None)

# ?
self.zero_extra_pc = name_type_map['Uint'](self.context, 0, None)
Expand All @@ -43,8 +43,8 @@ def _get_attribute_list(cls):
yield 'flag_0', name_type_map['Ushort'], (0, None), (False, 0), (None, None)
yield 'flag_1', name_type_map['Ushort'], (0, None), (False, 0), (None, None)
yield 'collision_layers', name_type_map['Uint64'], (0, None), (False, None), (lambda context: context.version <= 47, None)
yield 'collision_ignore', name_type_map['OffsetString'], (None, None), (False, None), (lambda context: context.version >= 48, None)
yield 'collision_use', name_type_map['OffsetString'], (None, None), (False, None), (lambda context: context.version >= 48, None)
yield 'classification_name', name_type_map['OffsetString'], (None, None), (False, None), (lambda context: context.version >= 48, None)
yield 'surface_name', name_type_map['OffsetString'], (None, None), (False, None), (lambda context: context.version >= 48, None)
yield 'zero_extra_pc', name_type_map['Uint'], (0, None), (False, None), (lambda context: context.version <= 32, None)
yield 'name', name_type_map['OffsetString'], (None, None), (False, None), (None, None)
yield 'collider', name_type_map['Sphere'], (0, None), (False, None), (None, True)
Expand All @@ -65,8 +65,8 @@ def _get_filtered_attribute_list(cls, instance, include_abstract=True):
if instance.context.version <= 47:
yield 'collision_layers', name_type_map['Uint64'], (0, None), (False, None)
if instance.context.version >= 48:
yield 'collision_ignore', name_type_map['OffsetString'], (instance.arg, None), (False, None)
yield 'collision_use', name_type_map['OffsetString'], (instance.arg, None), (False, None)
yield 'classification_name', name_type_map['OffsetString'], (instance.arg, None), (False, None)
yield 'surface_name', name_type_map['OffsetString'], (instance.arg, None), (False, None)
if instance.context.version <= 32:
yield 'zero_extra_pc', name_type_map['Uint'], (0, None), (False, None)
yield 'name', name_type_map['OffsetString'], (instance.arg, None), (False, None)
Expand Down
4 changes: 2 additions & 2 deletions generated/formats/ms2/ms2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -722,8 +722,8 @@
<add name="flag_0" type="ushort" default="0">PC: apparently bitflag, always a power of 2; PZ, JWE2 always 0</add>
<add name="flag_1" type="ushort" default="0">PC: 0; JWE: 16; PZ, JWE2 always 0</add>
<add name="collision_layers" type="uint64" until="47">probably a bitfield, not sure though, might be a list of ubytes too</add>
<add name="collision_ignore" type="OffsetString" arg="#ARG#" since="48"/>
<add name="collision_use" type="OffsetString" arg="#ARG#" since="48"/>
<add name="ClassificationName" type="OffsetString" arg="#ARG#" since="48"/>from physicsskeleton.specdef
<add name="SurfaceName" type="OffsetString" arg="#ARG#" since="48"/>
<add name="zero_extra_pc" type="uint" until="32">?</add>
<add name="name" type="OffsetString" arg="#ARG#"/>

Expand Down
1 change: 1 addition & 0 deletions generated/formats/physmat/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from generated.formats.physmat.imports import name_type_map
58 changes: 58 additions & 0 deletions generated/formats/physmat/compounds/PhysmatRoot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from generated.array import Array
from generated.formats.ovl_base.compounds.MemStruct import MemStruct
from generated.formats.physmat.imports import name_type_map


class PhysmatRoot(MemStruct):

__name__ = 'PhysmatRoot'


def __init__(self, context, arg=0, template=None, set_default=True):
super().__init__(context, arg, template, set_default=False)
self.all_surfaces_count = name_type_map['Uint'](self.context, 0, None)
self.surface_res_count = name_type_map['Uint'](self.context, 0, None)
self.classnames_count = name_type_map['Uint'](self.context, 0, None)
self.stringbuffer_size = name_type_map['Uint'](self.context, 0, None)
self.pointers = Array(self.context, 0, None, (0,), name_type_map['Uint64'])
self.all_surfaces_flags = Array(self.context, 0, None, (0,), name_type_map['Uint64'])
self.surface_res_indices = Array(self.context, 0, None, (0,), name_type_map['Uint'])
self.all_surfaces_names = Array(self.context, 0, None, (0,), name_type_map['Uint'])
self.surface_res_names = Array(self.context, 0, None, (0,), name_type_map['Uint'])
self.classnames_names = Array(self.context, 0, None, (0,), name_type_map['Uint'])
self.classnames_indices = Array(self.context, 0, None, (0,), name_type_map['Ubyte'])
self.names = name_type_map['ZStringBuffer'](self.context, self.stringbuffer_size, None)
if set_default:
self.set_defaults()

@classmethod
def _get_attribute_list(cls):
yield from super()._get_attribute_list()
yield 'all_surfaces_count', name_type_map['Uint'], (0, None), (False, None), (None, None)
yield 'surface_res_count', name_type_map['Uint'], (0, None), (False, None), (None, None)
yield 'classnames_count', name_type_map['Uint'], (0, None), (False, None), (None, None)
yield 'stringbuffer_size', name_type_map['Uint'], (0, None), (False, None), (None, None)
yield 'pointers', Array, (0, None, (5,), name_type_map['Uint64']), (False, None), (None, None)
yield 'all_surfaces_flags', Array, (0, None, (None,), name_type_map['Uint64']), (False, None), (None, None)
yield 'surface_res_indices', Array, (0, None, (None,), name_type_map['Uint']), (False, None), (None, None)
yield 'all_surfaces_names', Array, (0, None, (None,), name_type_map['Uint']), (False, None), (None, None)
yield 'surface_res_names', Array, (0, None, (None,), name_type_map['Uint']), (False, None), (None, None)
yield 'classnames_names', Array, (0, None, (None,), name_type_map['Uint']), (False, None), (None, None)
yield 'classnames_indices', Array, (0, None, (None,), name_type_map['Ubyte']), (False, None), (None, None)
yield 'names', name_type_map['ZStringBuffer'], (None, None), (False, None), (None, None)

@classmethod
def _get_filtered_attribute_list(cls, instance, include_abstract=True):
yield from super()._get_filtered_attribute_list(instance, include_abstract)
yield 'all_surfaces_count', name_type_map['Uint'], (0, None), (False, None)
yield 'surface_res_count', name_type_map['Uint'], (0, None), (False, None)
yield 'classnames_count', name_type_map['Uint'], (0, None), (False, None)
yield 'stringbuffer_size', name_type_map['Uint'], (0, None), (False, None)
yield 'pointers', Array, (0, None, (5,), name_type_map['Uint64']), (False, None)
yield 'all_surfaces_flags', Array, (0, None, (instance.all_surfaces_count,), name_type_map['Uint64']), (False, None)
yield 'surface_res_indices', Array, (0, None, (instance.surface_res_count,), name_type_map['Uint']), (False, None)
yield 'all_surfaces_names', Array, (0, None, (instance.all_surfaces_count,), name_type_map['Uint']), (False, None)
yield 'surface_res_names', Array, (0, None, (instance.surface_res_count,), name_type_map['Uint']), (False, None)
yield 'classnames_names', Array, (0, None, (instance.classnames_count,), name_type_map['Uint']), (False, None)
yield 'classnames_indices', Array, (0, None, (instance.classnames_count,), name_type_map['Ubyte']), (False, None)
yield 'names', name_type_map['ZStringBuffer'], (instance.stringbuffer_size, None), (False, None)
Empty file.
50 changes: 50 additions & 0 deletions generated/formats/physmat/imports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from importlib import import_module


type_module_name_map = {
'Byte': 'generated.formats.base.basic',
'Ubyte': 'generated.formats.base.basic',
'Uint64': 'generated.formats.base.basic',
'Int64': 'generated.formats.base.basic',
'Uint': 'generated.formats.base.basic',
'Ushort': 'generated.formats.base.basic',
'Int': 'generated.formats.base.basic',
'Short': 'generated.formats.base.basic',
'Char': 'generated.formats.base.basic',
'Normshort': 'generated.formats.base.basic',
'Rangeshort': 'generated.formats.base.basic',
'Float': 'generated.formats.base.basic',
'Double': 'generated.formats.base.basic',
'Hfloat': 'generated.formats.base.basic',
'ZString': 'generated.formats.base.basic',
'ZStringBuffer': 'generated.formats.base.compounds.ZStringBuffer',
'PadAlign': 'generated.formats.base.compounds.PadAlign',
'FixedString': 'generated.formats.base.compounds.FixedString',
'Vector2': 'generated.formats.base.compounds.Vector2',
'Vector3': 'generated.formats.base.compounds.Vector3',
'Vector4': 'generated.formats.base.compounds.Vector4',
'Bool': 'generated.formats.ovl_base.basic',
'OffsetString': 'generated.formats.ovl_base.basic',
'Compression': 'generated.formats.ovl_base.enums.Compression',
'VersionInfo': 'generated.formats.ovl_base.bitfields.VersionInfo',
'Pointer': 'generated.formats.ovl_base.compounds.Pointer',
'Reference': 'generated.formats.ovl_base.compounds.Reference',
'LookupPointer': 'generated.formats.ovl_base.compounds.LookupPointer',
'ArrayPointer': 'generated.formats.ovl_base.compounds.ArrayPointer',
'CondPointer': 'generated.formats.ovl_base.compounds.CondPointer',
'ForEachPointer': 'generated.formats.ovl_base.compounds.ForEachPointer',
'MemStruct': 'generated.formats.ovl_base.compounds.MemStruct',
'SmartPadding': 'generated.formats.ovl_base.compounds.SmartPadding',
'ZStringObfuscated': 'generated.formats.ovl_base.basic',
'GenericHeader': 'generated.formats.ovl_base.compounds.GenericHeader',
'Empty': 'generated.formats.ovl_base.compounds.Empty',
'ZStringList': 'generated.formats.ovl_base.compounds.ZStringList',
'PhysmatRoot': 'generated.formats.physmat.compounds.PhysmatRoot',
}

name_type_map = {}
for type_name, module in type_module_name_map.items():
name_type_map[type_name] = getattr(import_module(module), type_name)
for class_object in name_type_map.values():
if callable(getattr(class_object, 'init_attributes', None)):
class_object.init_attributes()
25 changes: 25 additions & 0 deletions generated/formats/physmat/physmat.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE niftoolsxml>
<niftoolsxml version="0.7.1.0">

<xi:include href="../ovl_base/ovl_base.xml" xmlns:xi="http://www.w3.org/2001/XInclude" xpointer="xpointer(*/*)" />

<compound name="PhysmatRoot" inherit="MemStruct">

<add name="all_surfaces_count" type="uint" />
<add name="surface_res_count" type="uint" />
<add name="classnames_count" type="uint" />
<add name="stringbuffer_size" type="uint" />

<add name="pointers" type="uint64" arr1="5"/>
<add name="all_surfaces_flags" type="uint64" arr1="all_surfaces_count"/>

<add name="surface_res_indices" type="uint" arr1="surface_res_count"/>
<add name="all_surfaces_names" type="uint" arr1="all_surfaces_count"/>
<add name="surface_res_names" type="uint" arr1="surface_res_count"/>
<add name="classnames_names" type="uint" arr1="classnames_count"/>
<add name="classnames_indices" type="ubyte" arr1="classnames_count"/>
<add name="names" type="ZStringBuffer" arg="stringbuffer_size"/>
</compound>

</niftoolsxml>
152 changes: 152 additions & 0 deletions generated/formats/physmat/versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from enum import Enum

from generated.base_version import VersionBase
from generated.formats.ovl_base.bitfields.VersionInfo import VersionInfo


def is_dla(context):
if context.version == 15:
return True


def set_dla(context):
context.version = 15


def is_jwe(context):
if context.version == 19 and context.user_version in (24724, 25108, 24596):
return True


def set_jwe(context):
context.version = 19
context.user_version._value = 24724


def is_jwe2(context):
if context.version == 20 and context.user_version in (24724, 25108, 24596):
return True


def set_jwe2(context):
context.version = 20
context.user_version._value = 24724


def is_jwe2dev(context):
if context.version == 20 and context.user_version in (24724, 25108, 24596) and context.is_dev == 1:
return True


def set_jwe2dev(context):
context.version = 20
context.user_version._value = 24724
context.is_dev = 1


def is_pc(context):
if context.version == 18 and context.user_version in (8340, 8724, 8212) and context.version_flag == 8:
return True


def set_pc(context):
context.version = 18
context.user_version._value = 8340
context.version_flag = 8


def is_pz(context):
if context.version == 19 and context.user_version in (8340, 8724, 8212):
return True


def set_pz(context):
context.version = 19
context.user_version._value = 8340


def is_pz16(context):
if context.version == 20 and context.user_version in (8340, 8724, 8212):
return True


def set_pz16(context):
context.version = 20
context.user_version._value = 8340


def is_ztuac(context):
if context.version == 17:
return True


def set_ztuac(context):
context.version = 17


games = Enum('Games', [('DISNEYLAND_ADVENTURES', 'Disneyland Adventures'), ('JURASSIC_WORLD_EVOLUTION', 'Jurassic World Evolution'), ('JURASSIC_WORLD_EVOLUTION_2', 'Jurassic World Evolution 2'), ('JURASSIC_WORLD_EVOLUTION_2_DEV', 'Jurassic World Evolution 2 Dev'), ('PLANET_COASTER', 'Planet Coaster'), ('PLANET_ZOO', 'Planet Zoo'), ('PLANET_ZOO_PRE_1_6', 'Planet Zoo pre-1.6'), ('ZOO_TYCOON_ULTIMATE_ANIMAL_COLLECTION', 'Zoo Tycoon Ultimate Animal Collection'), ('UNKNOWN', 'Unknown Game')])


def get_game(context):
if is_dla(context):
return [games.DISNEYLAND_ADVENTURES]
if is_jwe(context):
return [games.JURASSIC_WORLD_EVOLUTION]
if is_jwe2(context):
return [games.JURASSIC_WORLD_EVOLUTION_2]
if is_jwe2dev(context):
return [games.JURASSIC_WORLD_EVOLUTION_2_DEV]
if is_pc(context):
return [games.PLANET_COASTER]
if is_pz(context):
return [games.PLANET_ZOO_PRE_1_6]
if is_pz16(context):
return [games.PLANET_ZOO]
if is_ztuac(context):
return [games.ZOO_TYCOON_ULTIMATE_ANIMAL_COLLECTION]
return [games.UNKNOWN]


def set_game(context, game):
if isinstance(game, str):
game = games(game)
if game in {games.DISNEYLAND_ADVENTURES}:
return set_dla(context)
if game in {games.JURASSIC_WORLD_EVOLUTION}:
return set_jwe(context)
if game in {games.JURASSIC_WORLD_EVOLUTION_2}:
return set_jwe2(context)
if game in {games.JURASSIC_WORLD_EVOLUTION_2_DEV}:
return set_jwe2dev(context)
if game in {games.PLANET_COASTER}:
return set_pc(context)
if game in {games.PLANET_ZOO_PRE_1_6}:
return set_pz(context)
if game in {games.PLANET_ZOO}:
return set_pz16(context)
if game in {games.ZOO_TYCOON_ULTIMATE_ANIMAL_COLLECTION}:
return set_ztuac(context)


class PhysmatVersion(VersionBase):

_file_format = 'physmat'
_verattrs = ('version', 'user_version', 'version_flag')

def __init__(self, *args, version=(), user_version=(), version_flag=(), **kwargs):
super().__init__(*args, **kwargs)
self.version = self._force_tuple(version)
self.user_version = self._force_tuple(user_version)
self.version_flag = self._force_tuple(version_flag)


dla = PhysmatVersion(id='DLA', version=(15,), primary_games=[], all_games=[games.DISNEYLAND_ADVENTURES])
jwe = PhysmatVersion(id='JWE', version=(19,), user_version=(VersionInfo.from_value(24724), VersionInfo.from_value(25108), VersionInfo.from_value(24596),), primary_games=[], all_games=[games.JURASSIC_WORLD_EVOLUTION])
jwe2 = PhysmatVersion(id='JWE2', version=(20,), user_version=(VersionInfo.from_value(24724), VersionInfo.from_value(25108), VersionInfo.from_value(24596),), primary_games=[], all_games=[games.JURASSIC_WORLD_EVOLUTION_2])
jwe2dev = PhysmatVersion(id='JWE2DEV', version=(20,), user_version=(VersionInfo.from_value(24724), VersionInfo.from_value(25108), VersionInfo.from_value(24596),), primary_games=[], all_games=[games.JURASSIC_WORLD_EVOLUTION_2_DEV])
pc = PhysmatVersion(id='PC', version=(18,), user_version=(VersionInfo.from_value(8340), VersionInfo.from_value(8724), VersionInfo.from_value(8212),), version_flag=(8,), primary_games=[], all_games=[games.PLANET_COASTER])
pz = PhysmatVersion(id='PZ', version=(19,), user_version=(VersionInfo.from_value(8340), VersionInfo.from_value(8724), VersionInfo.from_value(8212),), primary_games=[], all_games=[games.PLANET_ZOO_PRE_1_6])
pz16 = PhysmatVersion(id='PZ16', version=(20,), user_version=(VersionInfo.from_value(8340), VersionInfo.from_value(8724), VersionInfo.from_value(8212),), primary_games=[], all_games=[games.PLANET_ZOO])
ztuac = PhysmatVersion(id='ZTUAC', version=(17,), primary_games=[], all_games=[games.ZOO_TYCOON_ULTIMATE_ANIMAL_COLLECTION])

available_versions = [dla, jwe, jwe2, jwe2dev, pc, pz, pz16, ztuac]
7 changes: 7 additions & 0 deletions modules/formats/PHYSMAT.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from generated.formats.physmat.compounds.PhysmatRoot import PhysmatRoot
from modules.formats.BaseFormat import MemStructLoader


class PhysmatLoader(MemStructLoader):
target_class = PhysmatRoot
extension = ".physmat"
Loading

0 comments on commit c78b349

Please sign in to comment.