Bphsh is a "shape" file format. Responsible for storing the underlying physics engine's collision mesh data as well as relevant phive specific data. This page is focused on the version found in Nintendo Switch Online: Playtest Program (021), and Havok 2023.2.
File Structure
- Header
- Havok Tag File
- Material Array
- Unknown Array
Structures (phive)
Common phive header for shape. The sections consist of the Havok tagfile containing an hknpMeshShape, an array of phive materials, and a currently unknown section.
Material Array
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x4
|
u32
|
Material Id. The PhiveConfig byaml stores an application's materials under MaterialCollection.
|
| 0x4
|
0x4
|
u32
|
Sub Material. The PhiveConfig byaml stores an application's sub materials under SubMaterialCollection.
|
| 0x8
|
0x8
|
u64
|
User Shape Tag Mask. Up to 64 tags can be present, each bit denotes whether a tag exists. The PhiveConfig byaml stores an application's tags under UserShapeTagCollection.
|
Unknown
0x10 sized per structure.
Structures (Havok Physics)
Common
hkEnum<T,B>, hkFlags<T,B>
Enum of type T, with underlying storage of type B.
hkRelPtr<T>
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x8
|
hkInt64
|
m_offset; Offset relative to the base address of this object to the template type T.
|
hkRelArrayView<T,B>
B is an integer type.
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
sizeof(B)
|
B
|
m_offset; Offset relative to the base address of this object to the array of template type T.
|
| sizeof(B)
|
sizeof(B)
|
B
|
m_size; Count of elements in the array
|
hkRelArray<T>
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x8
|
hkInt64
|
m_offset; Offset relative to the base address of this object to the array of template type T.
|
| 0x8
|
0x4
|
int
|
m_size; Count of elements in the array
|
| 0xc
|
0x4
|
int
|
m_capacityAndFlags; Max capacity of elements the array can store, also flags.
|
hknpMeshShape
Stores a collision mesh geometry and acceleration structures.
Note; hkBaseObject has an alignment of 8, but hknpMeshShape promotes the alignment to 0x10 due to containing an hkVector4. Unmarked space is padding.
hkBaseObject
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
u64
|
0x8
|
_vft_reserve; Vtable pointer, resolved at runtime.
|
hkReferencedObject
| Offset
|
Size
|
Type
|
Description
|
| 0x8
|
0x8
|
hkUlong
|
m_sizeAndFlags
|
| 0x10
|
0x8
|
hkUlong
|
m_refCount
|
hknpShape : hkReferencedObject
| Offset
|
Size
|
Type
|
Description
|
| 0x18
|
0x1
|
hkEnum<hknpShapeType::Enum, hkUint8>
|
m_type; Should always be "MESH" (0x8) for an hknpMeshShape.
|
| 0x19
|
0x1
|
hkEnum<hknpCollisionDispatchType::Enum, hkUint8>
|
m_dispatchType
|
| 0x1a
|
0x2
|
hkFlags<hknpShape::FlagsEnum, hkUint16>
|
m_flags
|
| 0x1c
|
0x1
|
hkUint8
|
m_numShapeKeyBits
|
| 0x1d
|
0x3
|
|
|
| 0x20
|
0x4
|
hkReal
|
m_convexRadius
|
| 0x24
|
0x4
|
|
|
| 0x28
|
0x8
|
hkUint64
|
m_userData, this is set at runtime to a phive structure containing references to the material and unknown array.
|
| 0x30
|
0x10
|
hknpShapeProperties
|
m_properties
|
hknpCompositeShape : hknpShape
| Offset
|
Size
|
Type
|
Description
|
| 0x40
|
0x4
|
hkUint32
|
m_shapeTagCodecInfo
|
| 0x44
|
0x4
|
|
|
hknpMeshShape : hknpCompositeShape
| Offset
|
Size
|
Type
|
Description
|
| 0x48
|
0x8
|
|
|
| 0x50
|
0x20
|
hknpMeshShapeVertexConversionUtil
|
m_vertexConversionUtil
|
| 0x70
|
0x8
|
hkRelArrayView<hknpMeshShape::ShapeTagTableEntry, int>
|
m_shapeTagTable
|
| 0x78
|
0x18
|
hkcdSimdTreeNamespace::hkcdSimdTree<hkcdSimdTreeNamespace::RelArrayStorage<hkcdSimdTreeNamespace::Node>>
|
m_topLevelTree
|
| 0x90
|
0x8
|
hkRelArrayView<hknpMeshShape::GeometrySection, int>
|
m_geometrySections; Appears to be a convex decomposition, or at least partitioning, of the mesh shape.
|
| 0x98
|
0x8
|
hkRelPtr<hknpMeshShapePrimitiveMapping>
|
m_primitiveMapping
|
hknpShapeType::Enum
| Name
|
Value
|
Description
|
| CONVEX
|
0x0
|
|
| SPHERE
|
0x1
|
|
| CAPSULE
|
0x2
|
|
| CYLINDER
|
0x3
|
|
| TRIANGLE
|
0x4
|
|
| BOX
|
0x5
|
|
| COMPOSITE
|
0x6
|
|
| MESH
|
0x7
|
|
| EXTERN_MESH
|
0x8
|
|
| COMPOUND
|
0x9
|
|
| DISTANCE_FIELD_BASE
|
0xa
|
|
| HEIGHT_FIELD
|
0xb
|
|
| DISTANCE_FIELD
|
0xc
|
|
| PARTICLE_SYSTEM
|
0xd
|
|
| TRANSFORMED
|
0xe
|
|
| MASKED
|
0xf
|
|
| MASKED_COMPOUND
|
0x10
|
|
| BREAKABLE_COMPOUND
|
0x11
|
|
| LOD
|
0x12
|
|
| DUMMY
|
0x13
|
|
| LEGACY_COMPRESSED_MESH
|
0x14
|
|
| USER_0
|
0x15
|
|
| USER_1
|
0x16
|
|
| USER_2
|
0x17
|
|
| USER_3
|
0x18
|
|
| USER_4
|
0x19
|
|
| USER_5
|
0x1b
|
|
| USER_6
|
0x1b
|
|
| USER_7
|
0x1c
|
|
| NUM_SHAPE_TYPES
|
0x1d
|
|
| INVALID
|
0x1e
|
|
hknpCollisionDispatchType::Enum
| Name
|
Value
|
Description
|
| NONE
|
0x0
|
|
| CONVEX
|
0x1
|
|
| COMPOSITE
|
0x2
|
|
| DISTANCE_FIELD
|
0x3
|
|
| USER_0
|
0x4
|
|
| USER_1
|
0x5
|
|
| USER_2
|
0x6
|
|
| USER_3
|
0x7
|
|
| USER_4
|
0x8
|
|
| USER_5
|
0x9
|
|
| USER_6
|
0xa
|
|
| USER_7
|
0xb
|
|
| NUM_TYPES
|
0xc
|
|
hknpShape::FlagsEnum
| Name
|
Value
|
Description
|
| IS_CONVEX_SHAPE
|
0x1
|
|
| IS_CONVEX_POLYTOPE_SHAPE
|
0x2
|
|
| IS_COMPOSITE_SHAPE
|
0x4
|
|
| IS_HEIGHT_FIELD_SHAPE
|
0x8
|
|
| USE_SINGLE_POINT_MANIFOLD
|
0x10
|
|
| IS_INTERIOR_TRIANGLE
|
0x20
|
|
| SUPPORTS_COLLISIONS_WITH_INTERIOR_TRIANGLES
|
0x40
|
|
| USE_NORMAL_TO_FIND_SUPPORT_PLANE
|
0x80
|
|
| IS_TRIANGLE_OR_QUAD_SHAPE
|
0x100
|
|
| IS_QUAD_SHAPE
|
0x200
|
|
| IS_SDF_EDGE_COLLISION_ENABLED
|
0x400
|
|
| HAS_SURFACE_VELOCITY
|
0x800
|
|
| USER_FLAG_0
|
0x1000
|
|
| USER_FLAG_1
|
0x2000
|
|
| USER_FLAG_2
|
0x4000
|
|
hknpShapeProperties
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x10
|
hkRelArray<hknpShapeProperties::Entry>
|
Optional shape properties.
|
hknpShapeProperties::Entry
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x8
|
hkRelPtr<hknpShapePropertyBase>
|
Pointer to shape property. If present, likely a derived class such as hknpShapeConnectivityGraph, hknpRefDragProperties, hknpShapeMassProperties, hknpShapeMassPropertiesTree, hknpShapeMassConfigProperty, or hknpMaterialPalette.
|
hknpShapePropertyBase
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x2
|
hkUint16
|
m_propertyKey; Appears to be a derived class unique identifier.
|
hknpMeshShapeVertexConversionUtil
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x10
|
hkVector4
|
m_bitScale16; Appears to be vertex compression parameters.
|
| 0x10
|
0x10
|
hkVector4
|
m_bitScale16Inv
|
hknpMeshShape::ShapeTagTableEntry
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x4
|
hkUint32
|
m_meshPrimitiveKey
|
| 0x4
|
0x2
|
hkUint16
|
m_shapeTag
|
| 0x6
|
0x2
|
|
|
hkcdSimdTreeNamespace::hkcdSimdTree<hkcdSimdTreeNamespace::RelArrayStorage<hkcdSimdTreeNamespace::Node>>
hkcdSimdTreeNamespace::RelArrayStorage<hkcdSimdTreeNamespace::Node>
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x10
|
hkRelArray<hkcdSimdTreeNamespace::Node>
|
m_nodes
|
hkcdSimdTreeNamespace::hkcdSimdTree : hkcdSimdTreeNamespace::RelArrayStorage<hkcdSimdTreeNamespace::Node>
| Offset
|
Size
|
Type
|
Description
|
| 0x10
|
0x4
|
hkUint32
|
m_firstFreeIndex
|
| 0x14
|
0x1
|
bool
|
m_isCompact
|
| 0x15
|
0x3
|
|
|
hkcdSimdTreeNamespace::Node
hkcdFourAabb
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x10
|
hkVector4
|
m_lx
|
| 0x10
|
0x10
|
hkVector4
|
m_hx
|
| 0x20
|
0x10
|
hkVector4
|
m_ly
|
| 0x30
|
0x10
|
hkVector4
|
m_hy
|
| 0x40
|
0x10
|
hkVector4
|
m_lz
|
| 0x50
|
0x10
|
hkVector4
|
m_hz
|
hkcdSimdTreeNamespace::Node : hkcdFourAabb
| Offset
|
Size
|
Type
|
Description
|
| 0x60
|
0x10
|
hkUint32[4]
|
m_data
|
| 0x70
|
0x4
|
hkUint8[4]
|
m_filterMasks
|
| 0x74
|
0x1
|
hkFlags<hkcdSimdTreeNamespace::Node::FlagsEnum, unsigned char>
|
m_flags
|
| 0x75
|
0x1
|
hkUint8
|
m_maxDepth
|
| 0x76
|
0x1
|
hkUint8
|
m_splittingAxisCache
|
| 0x77
|
0x1
|
hkUint8
|
m_numAddRemoveOperationsSinceLastRebalance
|
| 0x78
|
0x4
|
hkUint32
|
m_parent
|
| 0x7c
|
0x4
|
hkUint32
|
m_numLeaves
|
hkcdSimdTreeNamespace::Node::FlagsEnum
| Name
|
Value
|
Description
|
| NODE_IS_LEAF
|
0x1
|
|
| NODE_IS_FREE
|
0x2
|
|
| INCREMENTAL_OPTIMIZER_NODES_ARE_REBALANCED
|
0x4
|
|
| INCREMENTAL_OPTIMIZER_REINSERT_PASS_DID_NOP
|
0x8
|
|
| INCREMENTAL_OPTIMIZER_LEAVES_ARE_REBALANCED
|
0x10
|
|
| USER_FLAG_0
|
0x20
|
|
| USER_FLAG_1
|
0x40
|
|
| USER_FLAG_2
|
0x80
|
|
hknpMeshShape::GeometrySection
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x8
|
hkRelArrayView<hknpAabb8TreeNode, int>
|
m_sectionBvh
|
| 0x8
|
0x8
|
hkRelArrayView<hknpMeshShape::GeometrySection::Primitive, int>
|
m_primitives
|
| 0x10
|
0x8
|
hkRelArrayView<hkUint8, int>
|
m_vertexBuffer
|
| 0x18
|
0x8
|
hkRelArrayView<hkUint8, int>
|
m_interiorPrimitiveBitField
|
| 0x20
|
0xc
|
hkUint32[3]
|
m_sectionOffset
|
| 0x2c
|
0xc
|
hkFloat3
|
m_bitScale8Inv
|
| 0x38
|
0x6
|
hkInt16[3]
|
m_bitOffset
|
| 0x3e
|
0x2
|
|
|
hknpAabb8TreeNode
hknpTransposedFourAabbs8
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x4
|
hkUint32
|
m_lx
|
| 0x4
|
0x4
|
hkUint32
|
m_hx
|
| 0x8
|
0x4
|
hkUint32
|
m_ly
|
| 0xc
|
0x4
|
hkUint32
|
m_hy
|
| 0x10
|
0x4
|
hkUint32
|
m_lz
|
| 0x14
|
0x4
|
hkUint32
|
m_hz
|
hknpAabb8TreeNode : hknpTransposedFourAabbs8
| Offset
|
Size
|
Type
|
Description
|
| 0x18
|
0x3
|
hkUint8[3]
|
m_data
|
| 0x1b
|
0x1
|
|
|
hknpMeshShape::GeometrySection::Primitive
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x1
|
hkUint8
|
m_aId
|
| 0x1
|
0x1
|
hkUint8
|
m_bId
|
| 0x2
|
0x1
|
hkUint8
|
m_cId
|
| 0x3
|
0x1
|
hkUint8
|
m_dId
|
hknpMeshShape::GeometrySection::Vertex16_3
While m_vertexBuffer is untyped in later versions, in previous version it assumed this vertex format struct, which still appears to be the case (u8 mainly forces the m_vertexBuffer.m_size to be in bytes)
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x2
|
hkUint16
|
m_x
|
| 0x2
|
0x2
|
hkUint16
|
m_y
|
| 0x4
|
0x2
|
hkUint16
|
m_z
|
hknpMeshShapePrimitiveMapping
hknpMeshShapePrimitiveMapping : hkReferencedObject
| Offset
|
Size
|
Type
|
Description
|
| 0x0
|
0x10
|
hkRelArray<hkUint32>
|
m_sectionStart
|
| 0x10
|
0x10
|
hkRelArray<unsigned int>
|
m_bitString
|
| 0x20
|
0x4
|
hkUint32
|
m_bitsPerEntry
|
| 0x24
|
0x4
|
hkUint32
|
m_triangleIndexBitMask
|