diff --git a/.gitignore b/.gitignore index aaaa588..e071d76 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,9 @@ nunit-*.xml [Rr]eleasePS/ dlldata.c +# Version Files +version.hpp + # Benchmark Results BenchmarkDotNet.Artifacts/ diff --git a/src/hyperlib/assets/textures.cpp b/src/hyperlib/assets/textures.cpp index 030368b..d4a02fb 100644 --- a/src/hyperlib/assets/textures.cpp +++ b/src/hyperlib/assets/textures.cpp @@ -26,43 +26,43 @@ namespace hyper switch (texture->blend_type) { case texture::alpha_blend_type::blend: - this->alpha_blend_src = D3DBLEND_SRCALPHA; - this->alpha_blend_dest = D3DBLEND_INVSRCALPHA; + this->alpha_blend_src = ::D3DBLEND_SRCALPHA; + this->alpha_blend_dest = ::D3DBLEND_INVSRCALPHA; break; case texture::alpha_blend_type::additive: - this->alpha_blend_src = D3DBLEND_SRCALPHA; - this->alpha_blend_dest = D3DBLEND_ONE; + this->alpha_blend_src = ::D3DBLEND_SRCALPHA; + this->alpha_blend_dest = ::D3DBLEND_ONE; this->is_additive_blend = true; this->colour_write_alpha = true; break; case texture::alpha_blend_type::subtractive: - this->alpha_blend_src = D3DBLEND_ZERO; - this->alpha_blend_dest = D3DBLEND_INVSRCCOLOR; + this->alpha_blend_src = ::D3DBLEND_ZERO; + this->alpha_blend_dest = ::D3DBLEND_INVSRCCOLOR; break; case texture::alpha_blend_type::overbright: - this->alpha_blend_src = D3DBLEND_SRCALPHA; - this->alpha_blend_dest = D3DBLEND_INVSRCALPHA; + this->alpha_blend_src = ::D3DBLEND_SRCALPHA; + this->alpha_blend_dest = ::D3DBLEND_INVSRCALPHA; break; case texture::alpha_blend_type::dest_blend: - this->alpha_blend_src = D3DBLEND_DESTALPHA; - this->alpha_blend_dest = D3DBLEND_INVDESTALPHA; + this->alpha_blend_src = ::D3DBLEND_DESTALPHA; + this->alpha_blend_dest = ::D3DBLEND_INVDESTALPHA; break; case texture::alpha_blend_type::dest_additive: - this->alpha_blend_src = D3DBLEND_DESTALPHA; - this->alpha_blend_dest = D3DBLEND_ONE; + this->alpha_blend_src = ::D3DBLEND_DESTALPHA; + this->alpha_blend_dest = ::D3DBLEND_ONE; break; } } else { this->z_write_enabled = true; - this->alpha_blend_src = D3DBLEND_ONE; - this->alpha_blend_dest = D3DBLEND_ZERO; + this->alpha_blend_src = ::D3DBLEND_ONE; + this->alpha_blend_dest = ::D3DBLEND_ZERO; if (!this->alpha_test_enabled && (texture->flags & texture::bit_flags::disable_culling) != texture::bit_flags::disable_culling) { @@ -72,24 +72,28 @@ namespace hyper if ((texture->tilable_uv & texture::tileable_type::u_mirror) == texture::tileable_type::u_mirror) { - this->texture_address_u = D3DTADDRESS_MIRROR; + this->texture_address_u = ::D3DTADDRESS_MIRROR; } else { - this->texture_address_u = (texture->tilable_uv & texture::tileable_type::u_repeat) == texture::tileable_type::u_repeat ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + this->texture_address_u = (texture->tilable_uv & texture::tileable_type::u_repeat) == texture::tileable_type::u_repeat + ? ::D3DTADDRESS_WRAP + : ::D3DTADDRESS_CLAMP; } if ((texture->tilable_uv & texture::tileable_type::v_mirror) == texture::tileable_type::v_mirror) { - this->texture_address_v = D3DTADDRESS_MIRROR; + this->texture_address_v = ::D3DTADDRESS_MIRROR; } else { - this->texture_address_v = (texture->tilable_uv & texture::tileable_type::v_repeat) == texture::tileable_type::v_repeat ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + this->texture_address_v = (texture->tilable_uv & texture::tileable_type::v_repeat) == texture::tileable_type::v_repeat + ? ::D3DTADDRESS_WRAP + : ::D3DTADDRESS_CLAMP; } this->bias_level = texture->bias_level & 3; - this->alpha_test_ref = 11u; // #TODO + this->alpha_test_ref = 11u; // #TODO ? if (class_key == hashing::bin_const("Tree Leaves") || class_key == hashing::bin_const("Tree Cards") || class_key == hashing::bin_const("MultiPass Blend")) { @@ -99,7 +103,7 @@ namespace hyper bool is_barrier = class_key == hashing::bin_const("Barrier Mask") #if defined(CHECK_BARRIER_STRINGS) - || ::strncmp(reinterpret_cast(texture->name), "SFX_TRACKBARRIER", 16u) + || !::strncmp(reinterpret_cast(texture->name), "SFX_TRACKBARRIER", 16u) #endif ; diff --git a/src/hyperlib/renderer/flare_pool.cpp b/src/hyperlib/renderer/flare_pool.cpp index 9633089..7992f78 100644 --- a/src/hyperlib/renderer/flare_pool.cpp +++ b/src/hyperlib/renderer/flare_pool.cpp @@ -117,7 +117,7 @@ namespace hyper void flare_pool::ctor(flare_pool* pool) { - new (pool) flare_pool(0x80u); // by default, flare pool is initialized to 0x80 flares + new (pool) flare_pool(0x200u); } void flare_pool::dtor(flare_pool* pool) diff --git a/src/hyperlib/streamer/sections.cpp b/src/hyperlib/streamer/sections.cpp index f0dc495..07492b2 100644 --- a/src/hyperlib/streamer/sections.cpp +++ b/src/hyperlib/streamer/sections.cpp @@ -306,6 +306,11 @@ namespace hyper } } + void visible_section::manager::disable_all_groups() + { + ::memset(this->enabled_groups, 0, sizeof(this->enabled_groups)); + } + bool visible_section::manager::loader(chunk* block) { if (block->id() == block_id::visible_section_manager) @@ -488,4 +493,23 @@ namespace hyper return extra_width; } + + auto visible_section::manager::get_group_info(const char* group_name) -> const group_info* + { + size_t length = string::length(group_name); + + for (size_t i = 0u; i < visible_section::manager::group_info_table.length(); ++i) + { + const group_info& info = visible_section::manager::group_info_table[i]; + + size_t namesz = string::length(info.selection_set_name); + + if (namesz <= length && !::_strnicmp(info.selection_set_name, group_name, namesz)) + { + return &info; + } + } + + return nullptr; + } } diff --git a/src/hyperlib/streamer/sections.hpp b/src/hyperlib/streamer/sections.hpp index cdb9227..442b996 100644 --- a/src/hyperlib/streamer/sections.hpp +++ b/src/hyperlib/streamer/sections.hpp @@ -325,6 +325,8 @@ namespace hyper void disable_group(std::uint32_t key); + void disable_all_groups(); + bool loader(chunk* block); bool unloader(chunk* block); @@ -337,6 +339,8 @@ namespace hyper public: static auto get_distance_outside(const boundary* bound, const vector2& position, float extra_width) -> float; + static auto get_group_info(const char* group_name) -> const group_info*; + public: linked_list drivable_boundary_list; linked_list non_drivable_boundary_list; @@ -370,6 +374,8 @@ namespace hyper static inline std::uint32_t& current_zone_number = *reinterpret_cast(0x00A71C1C); static inline geometry::model*& zone_boundary_model = *reinterpret_cast(0x00B69BE8); + + static inline array group_info_table = array(0x00A72C30); }; }; diff --git a/src/hyperlib/streamer/track_path.cpp b/src/hyperlib/streamer/track_path.cpp index 01a41ff..b9c80e7 100644 --- a/src/hyperlib/streamer/track_path.cpp +++ b/src/hyperlib/streamer/track_path.cpp @@ -2,6 +2,19 @@ namespace hyper { + void track_path::manager::disable_all_barriers() + { + for (std::uint32_t i = 0u; i < this->barrier_count; ++i) + { + this->barriers[i].enabled = false; + } + } + + void track_path::manager::enable_barriers(const char* barrier_name) + { + call_function(0x007A2390)(this, barrier_name); + } + auto track_path::manager::find_zone(const vector2* position, zone::type type, const zone* prev) -> zone* { if (position == nullptr) diff --git a/src/hyperlib/streamer/track_path.hpp b/src/hyperlib/streamer/track_path.hpp index 40c7b10..cc6f94c 100644 --- a/src/hyperlib/streamer/track_path.hpp +++ b/src/hyperlib/streamer/track_path.hpp @@ -76,6 +76,10 @@ namespace hyper struct manager { public: + void disable_all_barriers(); + + void enable_barriers(const char* barrier_name); + auto find_zone(const vector2* position, zone::type type, const zone* prev) -> zone*; public: diff --git a/src/hyperlib/version.hpp b/src/hyperlib/version.hpp deleted file mode 100644 index 8ba4bf9..0000000 --- a/src/hyperlib/version.hpp +++ /dev/null @@ -1 +0,0 @@ -#define __VERSION__ 64 diff --git a/src/hyperlib/world/world.cpp b/src/hyperlib/world/world.cpp index af19225..0d46213 100644 --- a/src/hyperlib/world/world.cpp +++ b/src/hyperlib/world/world.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #include namespace hyper @@ -19,4 +22,53 @@ namespace hyper { call_function(0x007AF8F0)(); } + + void world::enable_barrier_scenery_group(const char* name, bool flip_artwork) + { + if (visible_section::manager::get_group_info(name) != nullptr) + { + std::uint32_t key = hashing::bin(name); + + visible_section::manager::instance.enable_group(key); + + scenery::group::enable(key, flip_artwork); + + track_path::manager::instance.enable_barriers(name); + } + } + + void world::disable_all_scenery_groups() + { + for (const scenery::group* i = scenery::group::list.begin(); i != scenery::group::list.end(); i = i->next()) + { + if (scenery::group::enabled_table[i->group_number]) + { + i->disable_rendering(); + + scenery::group::enabled_table[i->group_number] = 0; + } + } + } + + void world::init_topology_and_scenery_groups() + { + for (const char* group : world::permanent_scenery_groups) + { + if (scenery::group::find(hashing::bin(group)) != nullptr) + { + world::enable_barrier_scenery_group(group, false); + } + } + } + + void world::redo_topology_and_scenery_groups() + { + track_path::manager::instance.disable_all_barriers(); + + visible_section::manager::instance.disable_all_groups(); + + world::disable_all_scenery_groups(); + + world::init_topology_and_scenery_groups(); + } } diff --git a/src/hyperlib/world/world.hpp b/src/hyperlib/world/world.hpp index 148e9af..d29bceb 100644 --- a/src/hyperlib/world/world.hpp +++ b/src/hyperlib/world/world.hpp @@ -13,5 +13,21 @@ namespace hyper static void init_visible_zones(geometry::model*& boundary_model); static void notify_sky_loader(); + + static void enable_barrier_scenery_group(const char* name, bool flip_artwork); + + static void disable_all_scenery_groups(); + + static void init_topology_and_scenery_groups(); + + static void redo_topology_and_scenery_groups(); + + private: + static inline const char* permanent_scenery_groups[] = + { + "SCENERY_GROUP_DOOR", + "SCENERY_GROUP_CHRISTMAS", + "SCENERY_GROUP_HALLOWEEN_DISABLE", + }; }; } diff --git a/src/hyperlinked/dllmain.cpp b/src/hyperlinked/dllmain.cpp index cf1c237..1a5c32e 100644 --- a/src/hyperlinked/dllmain.cpp +++ b/src/hyperlinked/dllmain.cpp @@ -8,8 +8,10 @@ #pragma warning (disable : 6031) -#undef CONSOLEON -#undef RUN_TESTS +#if defined(_DEBUG) && !defined(ABOMINATOR) +#define CONSOLEON +#define RUN_TESTS +#endif #if defined(RUN_TESTS) #include diff --git a/src/hyperlinked/patches.cpp b/src/hyperlinked/patches.cpp index 2683f2c..3d56a1d 100644 --- a/src/hyperlinked/patches.cpp +++ b/src/hyperlinked/patches.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -21,6 +22,7 @@ #include #include +#include namespace hyper { @@ -32,6 +34,7 @@ namespace hyper loader_patches::init(); scenery_patches::init(); + texture_patches::init(); world_anim_patches::init(); // camera_patches::init(); @@ -47,5 +50,6 @@ namespace hyper streamer_patches::init(); collision_patches::init(); + world_patches::init(); } } diff --git a/src/hyperlinked/patches/assets/textures.cpp b/src/hyperlinked/patches/assets/textures.cpp new file mode 100644 index 0000000..e008608 --- /dev/null +++ b/src/hyperlinked/patches/assets/textures.cpp @@ -0,0 +1,46 @@ +#include +#include + +namespace hyper +{ + __declspec(naked) void detour_render_state_init() + { + __asm + { + // [esp + 0x00] is 'return address' + // [esp + 0x04] is 'texture' + // ecx contains pointer to texture::render_state + + // esp is auto-managed, non-incremental + // ebp is auto-managed, restored on function return + + push eax; // 'texture' is now at [esp + 0x08] + push ebx; // 'texture' is now at [esp + 0x0C] + push ecx; // 'texture' is now at [esp + 0x10] + push edx; // 'texture' is now at [esp + 0x14] + push esi; // 'texture' is now at [esp + 0x18] + push edi; // 'texture' is now at [esp + 0x1C] + + push [esp + 0x1C]; // repush 'texture' + + call texture::render_state::initialize; // call custom initialize + + // no need to restore esp since 'initialize' is a __thiscall + + pop edi; // restore saved register + pop esi; // restore saved register + pop edx; // restore saved register + pop ecx; // restore saved register + pop ebx; // restore saved register + pop eax; // restore saved register + + retn 4; // return immediately to caller function, not back to RenderState::Init; note that this is a __thiscall + } + } + + void texture_patches::init() + { + // RenderState::Init + hook::jump(0x0073B9E0, &detour_render_state_init); + } +} diff --git a/src/hyperlinked/patches/assets/textures.hpp b/src/hyperlinked/patches/assets/textures.hpp new file mode 100644 index 0000000..e0e7260 --- /dev/null +++ b/src/hyperlinked/patches/assets/textures.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace hyper +{ + class texture_patches final + { + public: + static void init(); + }; +} diff --git a/src/hyperlinked/patches/world/world.cpp b/src/hyperlinked/patches/world/world.cpp new file mode 100644 index 0000000..4e064ad --- /dev/null +++ b/src/hyperlinked/patches/world/world.cpp @@ -0,0 +1,104 @@ +#include +#include + +namespace hyper +{ + __declspec(naked) void detour_setup_topology_and_scenery() + { + __asm + { + // [esp + 0x00] is 'return address' + + // esp is auto-managed, non-incremental + // ebp is auto-managed, restored on function return + + push eax; // 'return address' is now at [esp + 0x04] + push ebx; // 'return address' is now at [esp + 0x08] + push ecx; // 'return address' is now at [esp + 0x0C] + push edx; // 'return address' is now at [esp + 0x10] + push esi; // 'return address' is now at [esp + 0x14] + push edi; // 'return address' is now at [esp + 0x18] + + call world::init_topology_and_scenery_groups; // call custom init_topology_and_scenery_groups + + pop edi; // restore saved register + pop esi; // restore saved register + pop edx; // restore saved register + pop ecx; // restore saved register + pop ebx; // restore saved register + pop eax; // restore saved register + + retn; // return immediately to caller function, not back to SetupTopologyAndScenery + } + } + + __declspec(naked) void detour_init_topology_and_scenery_groups() + { + __asm + { + // [esp + 0x00] is 'return address' + + // esp is auto-managed, non-incremental + // ebp is auto-managed, restored on function return + + push eax; // 'return address' is now at [esp + 0x04] + push ebx; // 'return address' is now at [esp + 0x08] + push ecx; // 'return address' is now at [esp + 0x0C] + push edx; // 'return address' is now at [esp + 0x10] + push esi; // 'return address' is now at [esp + 0x14] + push edi; // 'return address' is now at [esp + 0x18] + + call world::init_topology_and_scenery_groups; // call custom init_topology_and_scenery_groups + + pop edi; // restore saved register + pop esi; // restore saved register + pop edx; // restore saved register + pop ecx; // restore saved register + pop ebx; // restore saved register + pop eax; // restore saved register + + retn; // return immediately to caller function, not back to InitTopologyAndSceneryGroups + } + } + + __declspec(naked) void detour_redo_topology_and_scenery_groups() + { + __asm + { + // [esp + 0x00] is 'return address' + + // esp is auto-managed, non-incremental + // ebp is auto-managed, restored on function return + + push eax; // 'return address' is now at [esp + 0x04] + push ebx; // 'return address' is now at [esp + 0x08] + push ecx; // 'return address' is now at [esp + 0x0C] + push edx; // 'return address' is now at [esp + 0x10] + push esi; // 'return address' is now at [esp + 0x14] + push edi; // 'return address' is now at [esp + 0x18] + + call world::redo_topology_and_scenery_groups; // call custom redo_topology_and_scenery_groups + + pop edi; // restore saved register + pop esi; // restore saved register + pop edx; // restore saved register + pop ecx; // restore saved register + pop ebx; // restore saved register + pop eax; // restore saved register + + retn; // return immediately to caller function, not back to RedoTopologyAndSceneryGroups + } + } + + void world_patches::init() + { + // SetupTopologyAndScenery + hook::jump(0x007990A0, &detour_setup_topology_and_scenery); + + // InitTopologyAndSceneryGroups + hook::jump(0x006A8A80, &detour_init_topology_and_scenery_groups); + + // RedoTopologyAndSceneryGroups + hook::jump(0x006A8AD0, &detour_redo_topology_and_scenery_groups); + } +} diff --git a/src/hyperlinked/patches/world/world.hpp b/src/hyperlinked/patches/world/world.hpp new file mode 100644 index 0000000..7dd818f --- /dev/null +++ b/src/hyperlinked/patches/world/world.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace hyper +{ + class world_patches final + { + public: + static void init(); + }; +}