Skip to content

REFramework v2#1609

Merged
praydog merged 91 commits intomasterfrom
v2
Apr 25, 2026
Merged

REFramework v2#1609
praydog merged 91 commits intomasterfrom
v2

Conversation

@praydog
Copy link
Copy Markdown
Owner

@praydog praydog commented Mar 7, 2026

Experimental branch to convert REFramework into one monolithic DLL covering all the games, getting rid of the need for multiple builds via runtime dispatch. Should be easier to maintain, takes up less space for nightlies and is less straining on CI.

Game TDB Status Notes
DMC5 67 ✅ Working
RE8 69 ✅ Working Canonical ReClass layout
GGR 69 ✅ Core working Ghosts 'n Goblins Resurrection. .NET generation has errors — needs investigation
RE2 70 ✅ Working Head shrinks, gameplay functional
RE3 70 ✅ Working MAINCAM rotation fix pending verify
RE7 70 ✅ Working VR crash fixed (ViaDispatch)
RE4 71 ✅ Working IL2CPP JSON dump crash separate issue (might affect all games)
MHRISE 71 ✅ Working
SF6 71 ✅ Working
DD2 73 ✅ Working Freeze fixed (plugin ABI numTypes=0 root cause)
DRDR 73 ✅ Working Dead Rising Deluxe Remaster
GS456 73 ✅ Working Apollo Justice: Ace Attorney Trilogy
KUNITSU 73 ✅ Working Kunitsu-Gami: Path of the Goddess
ONIMUSHA2 74 ✅ Working Onimusha 2: Samurai's Destiny
STARFORCE 78 ✅ Working Mega Man Star Force Legacy Collection
MHWILDS 81 ✅ Working
MHSTORIES3 82 ✅ Working Trial window uses DD2 layout (blurriness fixed)
RE9 83 ✅ Working
PRAGMATA 83 ✅ Working Generic-type RETypeImpl crash fixed

20 games on one dinput8.dll.

.NET assembly generation verified across all games (commit 99a5f49a — plugin ABI TDB count fields were bypassing the version-aware dispatcher, producing empty 2KB _mscorlib.dll / viacore.dll / application.dll on every game with TDB < 81; fixed by routing eight lambdas in PluginLoader.cpp through get_num_types() / get_num_methods() / etc.).

All layout-variant types enforced — 18 struct types have private fields or opaque empty structs preventing direct ->field access. Dispatch macros (TDEF_FIELD, TMETH_FIELD, TFIELD_FIELD, RFIELDIMPL_FIELD, TIMPL_DISPATCH, etc.) centralize per-version casts. CI runs libclang-based audit on every PR.

Old (non-modern) builds of RE2, RE3, and RE7 are not tested and will need additional work.

Full VR functionality (motion controls) is not yet tested on RE2, RE3, RE7, RE8.

praydog added 26 commits March 5, 2026 12:48
- Add GameIdentity.hpp/cpp: Runtime game detection from exe name,
  TDB version mapping, engine parameter derivation (replaces compile-time
  RE2/RE3/RE4/.../REENGINE_PACKED/REENGINE_AT/TDB_VER macros)
- Restructure cmake.toml: Single REFrameworkSDK + REFramework targets
  replace ~30 per-game SDK+DLL targets. Define REFRAMEWORK_UNIVERSAL.
- Add PLAN_V2_MONOLITHIC.md documenting architecture decisions.
…runtime dispatch

- Mods.cpp: All conditional mod registration uses GameIdentity runtime checks
- REFramework.hpp: get_game_name() delegates to GameIdentity
- Main.cpp: Startup guards use GameIdentity; initialize() called early
- PluginLoader.cpp: game_name set at runtime in initialize_plugins()
- ReClass.hpp: REFRAMEWORK_UNIVERSAL includes RE8 layout as canonical base
- TDBVer.hpp: REFRAMEWORK_UNIVERSAL sets TDB_VER=84 so all code paths compile
…in src/

Batch conversion of game-specific preprocessor guards across 25 source files:

Camera, FreeCam, FirstPerson, ManualFlashlight:
- #ifdef RE8, RE2, RE3, RE4 → runtime gi.is_re8() etc.

Graphics, Hooks, REFrameworkConfig, ExceptionHandler:
- #ifdef SF6, MHWILDS, RE4, RE7 → runtime checks
- Member declarations gated with REFRAMEWORK_UNIVERSAL

IntegrityCheckBypass:
- Heavy per-game byte pattern ifdefs → runtime if/else if chains

RE8VR:
- Removed file-level #if defined(RE7)||defined(RE8) guard
- Added runtime early return in on_initialize()
- Internal RE7/RE8 guards → runtime checks

VR.cpp:
- Regenny include chain → REFRAMEWORK_UNIVERSAL block
- ~35 game guards → runtime checks

ObjectExplorer, ChainViewer, LooseFileLoader:
- TDB_VER and game guards → runtime checks

REFramework.cpp:
- DD2/MHRISE/TDB_VER >= 74 guards → runtime checks
…mbers, legacy TDB guards

- GameIdentity.hpp: Move static inline members to .cpp (incomplete type error)
- REFramework.cpp: Fix brace nesting in ldr_notification_callback
- FirstPerson.cpp: Fix missing closing braces in constructor and on_lua_state_created
- Graphics.cpp: Fix missing closing braces in on_pre/on_application_entry
- ObjectExplorer.cpp: Guard legacy TDB struct member access with #ifndef REFRAMEWORK_UNIVERSAL
- CMakeLists.txt: Regenerated by cmkr from updated cmake.toml (single unified target)
REType is 0x60 in most games but 0x68 in MHWILDS/RE9, with fields shifted
by 8 bytes after offset 0x28 (super, childType, chainType, fields, classInfo,
size, typeCRC all at different offsets).

- Add RETypeLayouts.hpp: defines reclass_mhwilds::REType (0x68 layout) and
  accessor functions in utility::re_type_accessor namespace that check
  GameIdentity at runtime and cast to the correct layout
- Replace all direct REType field accesses in shared/sdk/ and src/ with
  accessor calls (get_super, get_classInfo, get_fields, get_size, get_typeCRC,
  get_childType, get_chainType)
- REType.cpp, REManagedObject.cpp, REArray.cpp, RETypeDefinition.cpp,
  PluginLoader.cpp, ObjectExplorer.cpp updated
- REObjectInfo->classInfo and ParsedType->super accesses left untouched
  (different structs, same offset in all layouts)
Games with TDB < 73 (RE2, RE3, RE8, RE7, MHRISE) use 18-bit
TYPE_INDEX_BITS, but the universal build compiles with 19-bit.
The bitfield packing differs, causing all RETypeDefinition field
reads to return garbage on those games.

- Add RETypeDefDispatch.hpp: defines tdb_bits18::RETypeDefVersion69
  with hardcoded 18-bit field widths, and TDEF_FIELD/TDEF_FIELD_SET
  macros for runtime dispatch based on GameIdentity::tdb_ver()
- Replace ~33 bitfield accesses in RETypeDefinition.cpp with
  TDEF_FIELD macro (impl_index, declaring_typeid, parent_typeid,
  generics, index, object_type, member_method, member_field,
  member_prop, num_member_prop, type, managed_vt)
- Non-bitfield fields at same offset (type_flags, size, fqn_hash,
  type_crc) left as direct access

Note: REField and REMethodDefinition also use TYPE_INDEX_BITS
bitfields and will need similar treatment for full functionality.
…ld dispatch

- RETypeDB: All pointer field accesses (types, methods, fields, etc.) now dispatch
  through get_*_ptr() helpers that cast to tdb70::TDB for games with TDB < 73
- RETypeDB: Count accessors (get_num_types, etc.) dispatch similarly
- REMethodDefinition: get_method() uses byte-offset arithmetic with correct stride
  (16 bytes for tdb69, 12 bytes for tdb84)
- MethodIterator: Refactored to index-based iteration to handle variable stride
- REMethodDefinition: get_function() returns direct function pointer for tdb69
- REMethodDefinition: declaring_typeid, impl_id accessed via TMETH_FIELD dispatch
- REMethodDefinition: get_param_index() dispatches params vs params_lo/params_hi
- REField: declaring_typeid, impl_id accessed via TFIELD_FIELD dispatch
- REField: get_type() casts to tdb69::REFieldImpl for field_typeid
- REField: get_init_data_index() casts to tdb69::REFieldImpl for init_data split
- REField: get_offset_from_fieldptr() reads from tdb69 REField69::offset
- ObjectExplorer: All direct tdb-> accesses replaced with dispatched accessors
- RETypeDefDispatch.hpp: Added REMethodDef69, REField69, TMETH_FIELD, TFIELD_FIELD
…ect, Renderer, REContext

- RETypeDefDispatch.hpp: Added REParamDef69 (18-bit type_id) and TPARAM_FIELD macro
- RETypeDB.cpp: All p.type_id accesses use TPARAM_FIELD dispatch for 18 vs 19 bit
- RETypeDB.cpp: REField::get_data_raw vtable optimization gated to tdb_ver >= 81
- RETypes.cpp: game_namespace() returns correct prefix per game at runtime
- REManagedObject.cpp: is_managed_object/get_type/get_vm_type dispatch tdb_ver >= 71
- Renderer.hpp: Struct offsets (d3d12 resource, scene layers, output state) runtime dispatch
- REContext.cpp: Static table fixup gated to tdb_ver >= 71
…matrix dispatch

- Application.hpp: Function struct gets accessor methods (get_description, get_priority,
  get_type_val) that read from correct offsets (TDB < 74: +8 byte shift from extra void*)
- Application.cpp: get_function_stride() returns 0xD0 for TDB < 74, 0xC8 for TDB >= 74
- Application.cpp: All Function array iteration uses get_function_at() stride-aware indexing
- Application.cpp: All field accesses use accessor methods
- Hooks.cpp: entry->description -> entry->get_description()
- VR.cpp: func->description -> func->get_description()
- RETransform.hpp: Joint matrix access dispatches between RE2/RE3 (jointMatrices at 0xC0)
  and RE8+ (joints.matrices at 0xE0) via get_joint_matrices() helper
- RETypeDefinition.cpp: get_fieldptr_offset() uses direct managed_vt for TDB < 81
- RETypeDefinition.cpp: has_fieldptr_offset() checks TDEF_FIELD(managed_vt) for TDB < 81
- RETypeDefinition.cpp: get_managed_vt() skips abstract-type parent walk for TDB < 81
Runtime dispatch conversions:
- ResourceManager.cpp: TDB_VER < 81/73 byte-pattern scans for create_userdata
- Hooks.cpp: TDB_VER < 74 hook_update_before_lock_scene, >= 73 PrimitiveSystem guard
- Graphics.cpp: regenny header selection, TDB_VER < 73 backbuffer write
- Renderer.hpp: DRAW/UPDATE_VTABLE_INDEX, NUM_PRIORITY_OFFSETS as runtime fns,
  DirectXResource offset, TargetState::Desc pad, RenderLayer layout, RE4 lod_bias
- Renderer.cpp: NUM_PRIORITY_OFFSETS loop
- RETypes.cpp: >= 73 type-list finder
- VR.hpp: m_allow_engine_overlays, m_enable_asynchronous_rendering defaults
- Graphics.hpp: m_ultrawide_custom_fov default
- RETypeDB.cpp: REModule get_methods/instantiated/member_references via tdb74 cast
- RETypeDB.hpp: REModule stride-aware get_module_at(), get_module_stride()

Bug fixes:
- REModule array indexing stride mismatch: tdb81 is 0x40 bytes, tdb74 is 0x58.
  get_module() now uses stride-aware access for universal builds.

Cleanup:
- Application.cpp: removed temporary debug logging from get()
Window and SceneView structs have different field offsets per game
(RE2/RE3/RE8/RE4 etc. all differ). The universal build previously
always used RE9 headers, giving wrong offsets for other games.

New ViaDispatch.hpp provides runtime accessor functions that dispatch
by GameID. Graphics.cpp and VR.cpp updated to use these accessors
under REFRAMEWORK_UNIVERSAL.
…lity

Instead of hardcoded offset tables, each game's regenny Window/SceneView
headers are included inside distinct outer namespaces (ns_re7, ns_re3,
ns_re2, etc.). Dispatch functions cast to the correct namespaced struct
type at runtime. When Regenny regenerates a header, offsets update
automatically through the struct layout — no manual table maintenance.

re9 headers use the globally-included versions (already present via
Graphics.cpp/VR.cpp) to avoid #pragma once conflicts.
Two bugs causing RE4/SF6/MHRISE/DD2 to fail (Renderer type not found):

1. needs_18bit() threshold was tdb_ver < 73, but TDB 71+ (RE4/SF6/MHRISE/DD2)
   uses 19-bit TYPE_INDEX_BITS. Changed to tdb_ver < 71.

2. get_type(index) used sizeof(RETypeDefVersion84) = 0x50 as stride, but
   TDB 71-73 games have sizeof(RETypeDefVersion71) = 0x48 (no
   unk_new_tdb74_uint64 field). Added get_typedef_stride() and stride-
   aware access in get_type().

Stride map:
  TDB 69-70 (RE2/RE3/RE7/RE8): 0x50 (18-bit bitfields, V69 layout)
  TDB 71-73 (RE4/SF6/MHRISE/DD2): 0x48 (19-bit, no extra uint64)
  TDB 74+ (MHWILDS/RE9/PRAGMATA): 0x50 (19-bit, has unk_new_tdb74_uint64)
…r strides

Architecture change: every TDB version struct now has hardcoded bit
widths (no dependency on TYPE_INDEX_BITS / FIELD_BITS macros). This
makes each struct self-contained and correct regardless of compile-time
macro values.

Changes:
- V84/V83/V82/V74: hardcoded 19-bit TYPE_INDEX, 20-bit FIELD
- V71: hardcoded 19-bit TYPE_INDEX, 19-bit FIELD (no unk_new_tdb74_uint64)
- V69: hardcoded 18-bit (was in tdb_bits18 namespace, now the main struct)
- V67: split into V67 (DMC5, bitfield variant) and V67_RE3 (plain uint32)
- V66/V49: hardcoded 16-bit

Dispatch:
- TDEF_FIELD: 3-way dispatch (V69 for <71, V71 for 71-73, V84 for 74+)
- get_typedef_stride(): sizeof(RETypeDefVersion*) instead of 0x48/0x50
- get_method_stride(): sizeof(tdb69/tdb84::REMethodDefinition)
- tdb_bits18 namespace reduced to backward-compat aliases
…nitions

Every tdb namespace struct now has hardcoded bit widths:
- tdb84 through tdb71: 19-bit TYPE_INDEX (was macro, same value)
- tdb69: 18-bit (BUG FIX — was evaluating to 19 under universal build)
- tdb67: 17-bit (BUG FIX — was evaluating to 19 under universal build)
- tdb66: 16-bit (BUG FIX — was evaluating to 19 under universal build)

The tdb69/67/66 fixes are correctness bugs: under REFRAMEWORK_UNIVERSAL
TYPE_INDEX_BITS=19, so REField/GenericListData/REMethodDefinition structs
in those namespaces had wrong bitfield widths. This caused silent
corruption when reading older-format TDB data via dispatch macros.
TDB header accessors (get_num_types, get_num_methods, get_types_ptr,
get_modules_ptr, etc.) now switch on tdb_ver() with explicit casts to
tdb70/tdb71/tdb73/tdb74/tdb81/tdb82/tdb83/tdb84 TDB structs. Replaces
the old needs_18bit()-only two-branch dispatch that was wrong for
TDB 71-73 (e.g. RE4 reading 'initialized' instead of numTypes).

RETypeImpl field accesses (num_member_methods, num_member_fields) in
RETypeDefinition.cpp now use TIMPL_DISPATCH which dispatches to the
correct tdb69/tdb71/.../tdb84 RETypeImpl struct. Fixes the RE2 bug
where offset 0x18 in tdb69 data read interface_id (0xFFFF=65535)
instead of num_member_methods at offset 0x12.
tdb69::TDB has no 'void* unk' field between initData and attributes2,
so stringPool/bytePool/internStrings are at different offsets than tdb70.
Casting RE8's TDB to tdb70::TDB read garbage stringPool pointer causing
infinite loop during initialization.
Root cause: find_type() set map_populated=true BEFORE iterating
types. On TDB 67, get_full_name() throws for ~66% of type indices
(corrupt/unresolvable names in pre-impl TDB layout). The first
exception propagated out, leaving map_populated=true with an empty
map. All subsequent find_type() calls returned nullptr immediately.

Fix:
- Move map_populated=true AFTER the iteration loop completes
- Wrap individual type name resolution in try/catch so corrupt
  indices are skipped without aborting the entire map build
- ~21K of 62K types populate successfully, including all critical
  types (via.Application, via.io.file, etc.)

Verified: DMC5 now fully initializes (hooks, D3D11, config save).
RE2 regression test passes.
…onversion

- Add tmeth_declaring_typeid() / tfield_declaring_typeid() inline functions
  for 3-tier dispatch: tdb67 (17-bit) / tdb69 (18-bit) / tdb84 (19-bit)
- Replace TMETH_FIELD/TFIELD_FIELD(this, declaring_typeid) with new functions
  in RETypeDB.cpp and ObjectExplorer.cpp
- Convert all #ifndef REFRAMEWORK_UNIVERSAL guards in ObjectExplorer.cpp to
  runtime tdb67:: casts for method params, fields, properties
- Fixes ~66% type name resolution failures on DMC5 (TDB 67) caused by reading
  declaring_typeid with wrong bit width
RE3 has an extra 8-byte pad after cameraControllerInfos (0x58) in
RopewayCameraSystem, shifting all subsequent fields +8 vs RE2/RE8:
  cameraController: 0x98 (RE8) vs 0xA0 (RE3)
  mainCamera:       0xC0 (RE8) vs 0xC8 (RE3)
  playerJoint:      0xE0 (RE8) vs 0xE8 (RE3)
  mainCameraController: 0xE8 (RE8) vs 0xF0 (RE3)

Added CameraSystemDispatch.hpp with CAMSYS() macro that dispatches
to the correct struct layout at runtime via GameIdentity::is_re3().
Replaced all 58 shifted field accesses in FirstPerson.cpp.

Fixes access violation (c0000005) in FirstPerson::update_pointers_from_camera_system
that occurred ~6s after RE3 startup.
…troller + RETransform joints

RE2 RopewayPlayerCameraController has fields shifted -0x10 vs RE8/RE3:
  activeCamera: 0xA8 (RE2) vs 0xB8 (RE8) — confirmed via TDB reflection
  cameraParam:  0xB8 (RE2) vs 0xC8 (RE8)
  pitch/yaw:    0x108/0x10C vs 0x118/0x11C

Added CAMCTRL() dispatch macro and sdk::re2::RopewayPlayerCameraController_RE2
struct in CameraSystemDispatch.hpp. Replaced 18 field accesses in FirstPerson.cpp.

RE2 RETransform has REJointArray at 0xD0 (vs 0xD8 in RE8). The get_joint()
and get_all_children() functions read transform.joints.data at the RE8 offset,
causing joint lookups to fail on RE2 — head bone never found, never zeroed.

Added get_joint_array_data() dispatcher in RETransform.hpp and rewrote
get_joint()/get_all_children() to use it for REFRAMEWORK_UNIVERSAL builds.
RE3's RopewayMainCameraController has extra cameraDampingCameraPosition field
at 0x90, shifting all subsequent fields +0x10 vs RE2/RE8:
  cameraRotation:       0x90 (RE8) vs 0xA0 (RE3)
  mainCamera:           0xD0 (RE8) vs 0xE0 (RE3)
  switchInterpolationTime: 0xB0 (RE8) vs 0xC0 (RE3)

Added MAINCAM() dispatch macro and RopewayMainCameraController_RE3 struct
in CameraSystemDispatch.hpp. Replaced 8 field accesses in FirstPerson.cpp.
@praydog praydog added enhancement New feature or request experimental wip labels Mar 7, 2026
PRAGMATA_SKETCHBOOK.exe uses TDB 83 (confirmed from runtime TDB header).
GameIdentity hardcoded 84 (matching the unreleased full game), causing
dispatch macros to hit the tdb84 default path instead of case 83.

TODO: Read TDB version from binary at runtime and override the hardcoded
value, making the universal build resilient to demo/trial TDB mismatches.

asdf
105 static_asserts across RETypeDB.hpp proving:

- REMethodImpl: all 5 field offsets match tdb84 in tdb69-tdb83 (35)
- REPropertyImpl: all 3 field offsets match tdb84 in tdb69-tdb83 (21)
- REFieldImpl: attributes_id offset stable across tdb69-tdb83 (7)
- REParameterDef: attributes_id + init_data_index stable (14)
- RETypeImpl: name_offset + namespace_offset match tdb82 in tdb69-tdb81 (10)
- RETypeImpl: field_size offset stable across tdb69-tdb83 (7)
- REMethodDefinition: sizeof stable tdb71-tdb83 vs tdb84 (6)
- REField: sizeof stable tdb71-tdb83 vs tdb84 (6)
- REProperty: sizeof stable tdb69-tdb83 vs tdb84 (7)
- REModule: types_start/count/name offsets match tdb74 vs tdb81 (4)

Every macro that casts to a single TDB version without runtime
dispatch now has compiler-verified proof that the assumption holds.

Also fixes incorrect comment on RFIELDIMPL_FIELD: init_data_lo is
NOT stable across versions (14 bits tdb69 vs 6 bits tdb84).
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 19, 2026

Static proof for all layout assumptions

Commits ee6b024d, 4bd7269a, 788ccd85.

Every macro that casts to a single TDB version without runtime dispatch now has compiler-verified proof that the assumption holds. If a future TDB version moves a field or changes a struct size, the build fails with the exact type and field name.

105 static_asserts in RETypeDB.hpp

offsetof — field position proof (non-bitfield members):

Type Fields proven Versions checked Count
REMethodImpl attributes_id, vtable_index, flags, impl_flags, name_offset tdb69–tdb83 vs tdb84 35
REPropertyImpl flags, attributes_id, name_offset tdb69–tdb83 vs tdb84 21
REParameterDef attributes_id, init_data_index tdb69–tdb83 vs tdb84 14
RETypeImpl name_offset, namespace_offset tdb69–tdb81 vs tdb82 10
RETypeImpl field_size tdb69–tdb83 vs tdb84 7
REFieldImpl attributes_id tdb69–tdb83 vs tdb84 7
REModule types_start, types_count, assembly_name_offset, module_name_offset tdb74 vs tdb81 4

sizeof — struct size proof (bounds bitfield repacking):

Type Versions checked Count
REMethodDefinition tdb71–tdb83 vs tdb84 6
REProperty tdb69–tdb83 vs tdb84 7
REField tdb71–tdb83 vs tdb84 6
Impl types (prior commit) tdb69–tdb83 vs tdb84 35

Total: 140 static_asserts (35 impl sizes from prior commit + 105 new offsetof/sizeof).

Also in this batch

  • Incorrect comment fixed — RFIELDIMPL_FIELD comment claimed init_data_lo was identical across versions. It's not: 14 bits in tdb69 vs 6 bits in tdb84. The macro dispatches correctly; only the comment was wrong.
  • CI audit on pushdev-release.yml now runs the libclang audit on push, not just PRs.

praydog added 2 commits April 20, 2026 04:16
Private fields on all three types. Compiler rejects direct ->field access.

RETransform (shared/sdk/types/RETransform.hpp):
  - Stable-offset accessors: get_position(), get_angles(), get_scale(),
    get_world_transform(), get_child(), get_next(), get_parent_transform()
  - get_joints() retains UNIVERSAL runtime dispatch (0xD0 vs 0xD8)
  - REJointArray also extracted

REObjectInfo (shared/sdk/types/REObjectInfo.hpp):
  - get_class_info() — classInfo at offset 0x00, stable across all versions
  - get_type_fn() — dispatches TDB67 (0x10) vs TDB69+ (0x18)
  - REObjectInfo.cpp has UNIVERSAL implementation

REClassInfo (shared/sdk/types/REClassInfo.hpp):
  - get_type() — dispatches TDB67 (0x68) / TDB69-80 (0x40) / TDB81+ (0x38)
  - get_parent_info() — dispatches TDB67 (0x70) / TDB69-80 (0x48) / TDB81+ (0x40)
  - get_object_type(), get_object_flags(), get_size(), etc.
  - REClassInfo.cpp has UNIVERSAL implementations

CI: dev-release.yml split into REFramework.zip (DLL only) + VR.zip
(openvr_api.dll + openxr_loader.dll). Nightly produces 3 artifacts.

Consumer migration: 30+ direct field accesses replaced across
REManagedObject.cpp, Renderer.cpp, REContext.cpp, RETransform.cpp,
FirstPerson.cpp, FreeCam.cpp, VR.cpp, IntegrityCheckBypass.cpp,
ObjectExplorer.cpp.

Verified: builds clean, clang audit 0 violations, DMC5 (TDB 67)
smoke test passes with full assembly generation.
REClassInfo was the old name for RETypeDefinition before the TDB was
fully researched. They are the same runtime struct at the same address.

Under REFRAMEWORK_UNIVERSAL, REClassInfo is now an empty opaque struct.
All consumer code casts to sdk::RETypeDefinition* and uses its methods:
  - class_info->get_type() → ((RETypeDefinition*)class_info)->get_type()
  - class_info->parentInfo → ((RETypeDefinition*)class_info)->get_managed_vt()
  - class_info->objectFlags → get_type_definition(obj)->get_vm_obj_type()

Deleted REClassInfo.cpp (dispatch code no longer needed).
Removed classinfo_accessor namespace (redundant with RETypeDefinition).
Guarded TypeListArray with #ifndef REFRAMEWORK_UNIVERSAL (dead ReClass artifact).

Verified: DMC5 (TDB 67) smoke test passes — full assembly generation.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 20, 2026

Type header extraction + REClassInfo elimination + nightly split + full 20-game smoke test

Commits 258b7c25, d39200a9.

RETransform, REObjectInfo, REClassInfo extracted to type headers

All three types extracted from ReClass_Internal_RE8.hpp to shared/sdk/types/:

RETransform — private fields, stable-offset accessors (get_position(), get_angles(), get_world_transform(), get_child(), get_parent_transform(), etc.). get_joints() retains runtime dispatch (0xD0 vs 0xD8). REJointArray also extracted.

REObjectInfo — private fields. get_class_info() (offset 0x00, stable). get_type_fn() dispatches TDB67 (0x10) vs TDB69+ (0x18). Implementation in REObjectInfo.cpp.

REClassInfoeliminated. It's the same runtime struct as RETypeDefinition. The name was a historical artifact from before the TDB was fully researched. Under REFRAMEWORK_UNIVERSAL, REClassInfo is now an empty opaque struct. All consumer code casts to sdk::RETypeDefinition*:

// Before:
class_info->get_parent_info()     // custom dispatch code
class_info->get_type()            // custom dispatch code  
class_info->objectFlags >> 5      // raw field access

// After:
((sdk::RETypeDefinition*)class_info)->get_managed_vt()   // already dispatched
((sdk::RETypeDefinition*)class_info)->get_type()          // already dispatched
get_type_definition(object)->get_vm_obj_type()            // already dispatched

Deleted REClassInfo.cpp (90 lines of dispatch code that duplicated RETypeDefinition). Deleted classinfo_accessor namespace (same). TypeListArray (dead ReClass artifact, never referenced in code) guarded with #ifndef REFRAMEWORK_UNIVERSAL.

CI nightly split

dev-release.yml now produces 3 artifacts:

  • REFramework.zipdinput8.dll + revision + autorun scripts
  • VR.zipopenvr_api.dll + openxr_loader.dll + marker file
  • csharp-api.zip — unchanged

Full 20-game smoke test

Game TDB Boot REGlobals Assemblies
DMC5 67 ✅ All compiled
GGR 69 ⚠️ application fails (known, needs C# API adjustment)
RE8 69 ✅ Compiling
RE2 70 ✅ 13432 types
RE3 70 ✅ 15045 types
RE7 70 ✅ 15404 types
RE4 71 ✅ Compiling
MHRise 71 ✅ Compiling
SF6 71 ✅ Compiling
DD2 73 ✅ Compiling
DRDR 73 ✅ Compiling
GS456 73 ✅ Compiling
KUNITSU 73 ✅ 6992 types
ONIMUSHA2 74 ⚠️ application fails (known, needs C# API adjustment)
STARFORCE 78 ✅ Compiling
MHWilds 81 ✅ Compiling
MHStories3 82 ✅ 28972 types
RE9 83 ✅ Compiling
Pragmata 83 ✅ Compiling

20/20 boot and initialize. 18/20 full assembly generation. GGR and Onimusha2 have application assembly compile errors (C# API needs game-specific adjustments, not a v2 regression).

Consumer migration tally

30+ direct field accesses replaced across 9 files: REManagedObject.cpp, Renderer.cpp, REContext.cpp, RETransform.cpp, FirstPerson.cpp, FreeCam.cpp, VR.cpp, IntegrityCheckBypass.cpp, ObjectExplorer.cpp.

praydog added 3 commits April 20, 2026 05:51
154 conditional blocks stripped across 28 files. Only the
REFRAMEWORK_UNIVERSAL code paths remain. TDB49 (RE7) reference
paths preserved for future support.

Removed:
  - All #else/#elif TDB_VER branches under #ifdef REFRAMEWORK_UNIVERSAL
  - All #if TDB_VER conditions that are always true/false for TDB_VER=84
  - All #ifndef REFRAMEWORK_UNIVERSAL dead blocks
  - Non-universal macro pass-throughs in RETypeDefDispatch.hpp
  - Legacy per-game TDB_VER/TYPE_INDEX_BITS definitions in TDBVer.hpp

Kept (TDB49 reference):
  - TDBVer.hpp legacy block (contains RE7_TDB49 paths)
  - REManagedObject.cpp TDB49 paths (info->size, different validation)
  - RETypeDB.cpp TDB > 49 guards on init_data/byte pool access
  - RETypeDefinition.cpp TDB <= 49 special cases

Verified: builds clean, DMC5 boots and resolves all singletons.
worldPos2ScreenPos method not found on RE9 (different signature?).
Add null check before calling. Pre-existing bug, not a regression.
Fixed strip script: TDB_VER > 49 is NOT a TDB49 reference (it means
'everything except old RE7'). Added orphaned #elif handler for chains
left behind by first pass.

Removed orphaned #elif TDB_VER chains in REManagedObject.cpp,
RETypeDB.cpp, RETypeDefinition.cpp, Renderer.cpp/hpp, MotionFsm2Layer.hpp.

Remaining #ifdef REFRAMEWORK_UNIVERSAL blocks all contain TDB49
references (RE7 support) or are structural (RETypeDB.hpp versioned
struct definitions, TDBVer.hpp legacy builds, ReClass.hpp includes).

Total dead code removed across both passes: ~2169 lines.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 20, 2026

Dead code removal — 2169 lines of non-universal preprocessor paths stripped

Commits c921268c, f2c9706c, 4026142e.

What was removed

Every #else / #elif TDB_VER branch under #ifdef REFRAMEWORK_UNIVERSAL blocks, plus standalone #if TDB_VER guards that are always true/false for TDB_VER=84. Two passes with a purpose-built script (scripts/strip_non_universal.py).

  • 154 blocks in first pass (28 files, 1527 lines)
  • 27 blocks in second pass (7 files, 642 lines)
  • Total: 2169 lines of dead code removed

What remains

All remaining #ifdef REFRAMEWORK_UNIVERSAL / #if TDB_VER blocks contain TDB49 references preserved as future RE7 support reference:

  • REManagedObject.cpp — TDB49 validation paths (different object layout)
  • RETypeDB.cpp — TDB > 49 guards on init_data/byte pool access
  • RETypeDefinition.cpp — TDB <= 49 special cases
  • Graphics.cpp / VR.cpp — per-TDB-version scene view type names (includes TDB <= 49 entry)
  • TDBVer.hpp — legacy per-game build definitions
  • RETypeDB.hpp — versioned struct definitions (reference for all TDB layouts)

One known gap: RE7 TDB49 invoke wrapper code (// RE7 doesn't have the invoke wrappers...) was removed along with its #else block. Not a regression (RE7 TDB49 isn't supported in universal build yet), but will need to be restored from the reference implementation when TDB49 support is added.

Also in this batch

GameObjectsDisplay null deref fix (4026142e) — worldPos2ScreenPos method lookup returns null on RE9 (signature likely changed). Added null guard. Pre-existing bug, not a regression from dead code removal.

Verification

  • DMC5 (TDB 67): full assembly generation, 20k types ✅
  • RE9: tested with complex scripts by user ✅
  • MHWILDS: tested with complex scripts by user ✅
  • All 20 games deployed with cleared caches

praydog added 2 commits April 20, 2026 07:32
The behavior tree headers (regenny/mhrise_tdb71/) only work for TDB >= 69.
DMC5 (TDB 67) has different struct layouts (TreeNode 0xC8 vs 0xD0, no
parent_condition field, name at different offset).

Runtime dispatch using regenny/re3/ headers under a separate namespace
is needed to support behavior tree editing on DMC5. Added TODO.
TreeNode, TreeNodeData, TreeObject, TreeObjectData no longer inherit
from regenny structs. They are opaque classes with offset-dispatching
accessors that branch on needs_legacy_bhvt() (tdb_ver < 69).

Key layout differences dispatched:
  TreeNode: name/status1/status2 shifted +8 (parent_condition inserted)
  TreeNodeData: tags/name shifted +0x10
  TreeObjectData: action_methods/static_action_methods shifted +0x30
  TreeObject: selectors shifted +4, root_node 0xA0 vs 0xC0

Stride-aware iteration for node arrays (0xC8 vs 0xD0 per TreeNode).
Lua bindings updated to use sol::property with getter methods.
Direct field access compiler-rejected on all 4 types.

Verified: builds clean.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 20, 2026

Behavior tree runtime dispatch — DMC5 TDB67 support restored

Commit 8fd9e748.

The behavior tree subsystem was compiled against TDB69+ struct layouts (mhrise_tdb71 regenny headers). In v1 per-game builds, DMC5's DLL compiled with TDB67 headers so this was never a problem — each game got its own correct layout. In the v2 monolithic build, DMC5 runs with the TDB69+ compiled layout, reading wrong offsets for node names, statuses, and other fields. This commit adds runtime dispatch so the correct offsets are used for each game.

What changed

TreeNode, TreeNodeData, TreeObject, TreeObjectData no longer inherit from regenny structs. They are opaque classes with offset-dispatching accessors that branch on needs_legacy_bhvt() (tdb_ver < 69).

Struct Size (re3/tdb71) Dispatched fields
TreeNode 0xC8 / 0xD0 name (+8), status1 (+8), status2 (+8), parent_condition (missing in re3)
TreeNodeData 0x1C0 / 0x1D0 tags (+0x10), name (+0x10)
TreeObjectData 0x300 / 0x300 action_methods (+0x30), static_action_methods (+0x30)
TreeObject 0xD8 / 0xD8 selectors (+4), root_node (0xA0 vs 0xC0)

Stride-aware iteration for node arrays (0xC8 vs 0xD0 per TreeNode). Lua bindings updated to use sol::property with getter methods. Direct field access compiler-rejected on all 4 types.

BehaviorTree, CoreHandle, Core, MotionFsm2Layer are identical across versions — kept regenny inheritance.

Verified

  • DMC5 (TDB 67): Behavior tree editor works — nodes show names, actions load, no crashes. User tested extensively.
  • DD2 (TDB 73): Behavior tree editor works — can follow tree execution, see node states. Transition conditions/states empty (matches reference build, not a regression — reverse engineering gap).
  • MHRise (TDB 71): Behavior tree editor works. Initial D3D freeze was intermittent/unrelated — confirmed working on retest.

Chain::CollisionData is at 0x58 (TDB < 71) vs 0x60 (TDB >= 71).
ChainViewer was hardcoded to re2_tdb70 layout (0x58), reading wrong
offset on MHRise/SF6/DD2/RE4 and all TDB71+ games.

Added get_chain_collision_data() dispatcher. All chain->CollisionData
accesses now go through it.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 20, 2026

ChainViewer runtime dispatch — full offset dispatch for all chain structs

Commit 29c9b485.

The ChainViewer was hardcoded to re2_tdb70 regenny headers. Two separate issues:

  1. Chain::CollisionData offset — 0x58 (TDB < 71) vs 0x60 (TDB >= 71). Every TDB71+ game (MHRise, SF6, DD2, RE4, etc.) was reading CollisionData at the wrong offset.

  2. ChainCollisions struct layout — completely different field offsets AND struct size between DMC5 and RE2+:

Field re3/DMC5 (TDB<69) re2_tdb70 (TDB>=69)
sphere 0x00 0x10
capsule 0x10 0x20
offset 0x60 0xD0
joint 0xA0 0x130
pair_joint 0xA8 0x138
radius 0xC0 0x150
flags 0xD4 0x164
Stride 0xE0 0x180

The crash on DMC5 was: array indexing collisions[i] used sizeof=0x180 stride when the actual stride was 0xE0. Second element onwards read garbage, producing 0xFFFFFFFFFFFFFFFF as a "joint" pointer.

Fix

Zero direct regenny struct field access. All chain data goes through dispatch accessors:

  • ChainCollisionArrayAccessor — wraps CollisionData (collisions ptr + num)
  • CollisionAccessor — wraps individual ChainCollisions (sphere/capsule/offset/joint/pair_joint/radius/flags)
  • get_collision_top_num() / get_collision_top_collisions() — wraps ChainCollisionTop array
  • get_chain_collision_data(chain) — dispatches Chain::CollisionData offset
  • chain_collisions_stride() — 0xE0 vs 0x180

Verified

  • DMC5 (TDB 67, DX11): ChainViewer works, collisions display correctly, no crashes
  • MHRise (TDB 71, DX12): ChainViewer works, 3D capsule/sphere rendering correct

praydog added 3 commits April 20, 2026 21:17
176 call sites migrated. get_field<T> renamed to get_reflection_property<T>
to avoid confusion with the plugin API's get_field (which stays unchanged).

Free functions → member methods:
  get_type_definition(obj) → obj->get_type_definition()
  is_managed_object(addr) → REManagedObject::is_managed_object(addr)
  is_a(obj, name) → obj->is_a(name)
  add_ref(obj) → obj->add_ref()
  release(obj) → obj->release()
  get_type(obj) → obj->get_type()
  get_size(obj) → obj->get_size()
  get_vm_type(obj) → obj->get_vm_type()
  get_field<T>(obj, f) → obj->get_reflection_property<T>(f)
  etc.

namespace utility::re_managed_object deleted entirely.
Plugin API (include/reframework/API.h, API.hpp) untouched.

Verified: builds clean.
ik_leg->call_method("set_CenterAdjust", value) instead of
REManagedObject::call_method(ik_leg, "set_CenterAdjust", value).

4 call sites updated.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 21, 2026

utility::re_managed_object → member methods + behavior tree/chain dispatch + dead code removal

utility::re_managed_object eliminated

176 call sites migrated to member methods on REManagedObject. The namespace is deleted.

// Before:
utility::re_managed_object::get_type_definition(obj)
utility::re_managed_object::is_a(obj, "SomeName")
utility::re_managed_object::add_ref(obj)
utility::re_managed_object::get_field<float>(obj, "fieldName")
REManagedObject::call_method(obj, "method", arg)

// After:
obj->get_type_definition()
obj->is_a("SomeName")
obj->add_ref()
obj->get_reflection_property<float>("fieldName")
obj->call_method("method", arg)

get_field<T> renamed to get_reflection_property<T> on the SDK side to avoid confusion with the plugin API's get_field (which stays unchanged — include/reframework/API.h and API.hpp untouched).

Full 21-game smoke test (fresh assembly generation)

Game TDB Types
DMC5 67 20,349
RE8 69 23,978
RE2 70 13,432
RE3 70 15,045
RE7 70 15,404
RE4 71 Full gen
MHRise 71 Compiling
SF6 71
DD2 73 Compiling
DRDR 73 Compiling
Kunitsu 73 6,992
Onimusha2 74 6,606
Starforce 78 Compiling
MHWilds 81 Compiling
RE9 83 Compiling
Pragmata Sketchbook 83 18,364
Pragmata 83 18,480

All 21 game installs boot, initialize, and generate assemblies. Zero crashes.

14 call sites: obj->get_name() instead of utility::re_game_object::get_name(obj).
namespace utility::re_game_object deleted.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 21, 2026

utility::re_game_objectREGameObject::get_name()

Commit 16f7880e.

// Before:
utility::re_game_object::get_name(game_object)

// After:
game_object->get_name()

14 call sites. namespace utility::re_game_object deleted. Defensive null-this check preserved.

56 call sites migrated:
  find<T>(comp, name) → comp->find<T>(name)
  find<T>(comp, type) → comp->find<T>(type)
  get_game_object(comp) → comp->get_game_object()
  get_delta_time(comp) → comp->get_delta_time()
  find_replaceable<T>(comp, t) → comp->find_replaceable<T>(t)

Also added: get_valid(), get_chain(), get_delta_time() as
reflection property helpers.

namespace utility::re_component deleted.
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 21, 2026

utility::re_componentREComponent member methods

Commit 10e82f53.

// Before:
utility::re_component::find<T>(comp, "via.render.ToneMapping")
utility::re_component::get_game_object(comp)
utility::re_component::get_delta_time(comp)

// After:
comp->find<T>("via.render.ToneMapping")
comp->get_game_object()
comp->get_delta_time()

56 call sites across 11 files. namespace utility::re_component deleted. Added get_valid(), get_chain(), get_delta_time() as reflection property helpers on REComponent.

praydog added 3 commits April 23, 2026 02:20
# Conflicts:
#	src/mods/IntegrityCheckBypass.cpp
RE3 TDB70 uses the same Window/SceneView layout as RE2. The case
fallthrough was wrong — RE3 fell through to DMC5's TDB<69 path.
Fixed all 6 dispatch points.

Renamed W::re3 / SV::re3 to W::re3_tdb67 / SV::re3_tdb67 to clarify
the alias is for the old TDB<69 layout (DMC5), not current RE3 TDB70.

VR.cpp: fixed screen squish on RE2/RE3 in VR mode.
Copied imgui_impl_dx11/dx12/win32 from dependencies/imgui/backends/.
Added ImGui_ImplWin32_WndProcHandler forward declaration in Plugin.cpp
(required by newer imgui which wraps the declaration in #if 0).
@praydog
Copy link
Copy Markdown
Owner Author

praydog commented Apr 25, 2026

Final fixes — merge ready

RE3 ViaDispatch fix + VR screen squish (079396ad)

RE3 TDB70 uses the same Window/SceneView layout as RE2. The case fallthrough was wrong — RE3 fell through to DMC5's TDB<69 path instead of RE2's. Fixed all 6 dispatch points. Renamed W::re3 / SV::re3 to W::re3_tdb67 / SV::re3_tdb67 to clarify the alias is the old TDB<69 layout, not current RE3. Also fixed VR screen squish on RE2/RE3.

Example plugin imgui update (51862b0e)

Example plugin's local imgui backend files were an old version incompatible with the current imgui in dependencies/. Copied current backends from dependencies/imgui/backends/. Added ImGui_ImplWin32_WndProcHandler forward declaration (newer imgui wraps it in #if 0).

All targets build clean including example_plugin.

@praydog praydog merged commit 09284e2 into master Apr 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants