diff --git a/X-Cell-FO4.vcxproj b/X-Cell-FO4.vcxproj
index 88f864b..6f9d38d 100644
--- a/X-Cell-FO4.vcxproj
+++ b/X-Cell-FO4.vcxproj
@@ -227,7 +227,7 @@
false
StdCall
xc_common.h
- 4477;4996;6001;26495;28125;%(DisableSpecificWarnings)
+ 4477;4996;6001;6250;6333;26495;28125;28160;%(DisableSpecificWarnings)
Windows
diff --git a/include/xc_patch.h b/include/xc_patch.h
index a01d72d..4b18a34 100644
--- a/include/xc_patch.h
+++ b/include/xc_patch.h
@@ -4,10 +4,32 @@
#pragma once
+#include
+#include
#include
namespace xc
{
+ class scope_relocate_al
+ {
+ public:
+ inline scope_relocate_al(LPVOID address, SIZE_T size) : _protected(0), _address(address), _size(size)
+ {
+ _xc_assert_msg_fmt(VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_protected),
+ "Address: %p Size: %X", _address, _size);
+ }
+
+ inline ~scope_relocate_al()
+ {
+ // Ignore if this fails, the memory was copied either way
+ VirtualProtect(_address, _size, _protected, &_protected);
+ }
+ private:
+ LPVOID _address;
+ SIZE_T _size;
+ DWORD _protected;
+ };
+
class patch
{
public:
@@ -34,6 +56,8 @@ namespace xc
virtual uintptr_t detour_jump(uintptr_t target, uintptr_t func) const noexcept;
virtual uintptr_t detour_call(uintptr_t target, uintptr_t func) const noexcept;
virtual uint32_t calc_rva(uintptr_t from, uintptr_t target, uint32_t opcode_offset) const noexcept;
+ virtual uintptr_t find_pattern(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept;
+ virtual std::vector find_patterns(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept;
private:
bool start_impl() const;
};
diff --git a/include/xc_patch_archive_limit.h b/include/xc_patch_archive_limit.h
index 27ae2e0..828155b 100644
--- a/include/xc_patch_archive_limit.h
+++ b/include/xc_patch_archive_limit.h
@@ -49,6 +49,7 @@ namespace xc
virtual bool run() const;
private:
static uint32_t impl_memcpy_hash_from_archive_table(void* archive, void* archive_hash, file_hash_t* hash, size_t read_size);
- static void impl_set_index_archive_to_hash();
+ static void impl_set_index_archive_to_hash_og();
+ static void impl_set_index_archive_to_hash_ng();
};
}
\ No newline at end of file
diff --git a/source/xc_patch.cpp b/source/xc_patch.cpp
index 46104d4..21abba7 100644
--- a/source/xc_patch.cpp
+++ b/source/xc_patch.cpp
@@ -97,6 +97,79 @@ namespace xc
return (uint32_t)delta;
}
+ uintptr_t patch::find_pattern(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept
+ {
+ std::vector> pattern;
+
+ for (size_t i = 0; i < strlen(mask);)
+ {
+ if (mask[i] != '?')
+ {
+ pattern.emplace_back((uint8_t)strtoul(&mask[i], nullptr, 16), false);
+ i += 3;
+ }
+ else
+ {
+ pattern.emplace_back(0x00, true);
+ i += 2;
+ }
+ }
+
+ const uint8_t* dataStart = (uint8_t*)start_address;
+ const uint8_t* dataEnd = (uint8_t*)start_address + max_size + 1;
+
+ auto ret = std::search(dataStart, dataEnd, pattern.begin(), pattern.end(),
+ [](uint8_t CurrentByte, std::pair& Pattern) {
+ return Pattern.second || (CurrentByte == Pattern.first);
+ });
+
+ if (ret == dataEnd)
+ return 0;
+
+ return std::distance(dataStart, ret) + start_address;
+ }
+
+ std::vector patch::find_patterns(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept
+ {
+ std::vector results;
+ std::vector> pattern;
+
+ for (size_t i = 0; i < strlen(mask);)
+ {
+ if (mask[i] != '?')
+ {
+ pattern.emplace_back((uint8_t)strtoul(&mask[i], nullptr, 16), false);
+ i += 3;
+ }
+ else
+ {
+ pattern.emplace_back(0x00, true);
+ i += 2;
+ }
+ }
+
+ const uint8_t* dataStart = (uint8_t*)start_address;
+ const uint8_t* dataEnd = (uint8_t*)start_address + max_size + 1;
+
+ for (const uint8_t* i = dataStart;;)
+ {
+ auto ret = std::search(i, dataEnd, pattern.begin(), pattern.end(),
+ [](uint8_t CurrentByte, std::pair& Pattern) {
+ return Pattern.second || (CurrentByte == Pattern.first);
+ });
+
+ if (ret == dataEnd)
+ break;
+
+ uintptr_t addr = std::distance(dataStart, ret) + start_address;
+ results.push_back(addr);
+
+ i = (uint8_t*)(addr + 1);
+ }
+
+ return results;
+ }
+
bool patch::start_impl() const
{
auto name_patch = get_name();
diff --git a/source/xc_patch_archive_limit.cpp b/source/xc_patch_archive_limit.cpp
index 9d0d1bf..2527a2c 100644
--- a/source/xc_patch_archive_limit.cpp
+++ b/source/xc_patch_archive_limit.cpp
@@ -4,7 +4,6 @@
#include
#include
-#include
#include
#include
@@ -34,26 +33,6 @@ namespace xc
tree_db_general_t g_tree_db_general;
- class scope_relocate_al
- {
- public:
- scope_relocate_al(LPVOID address, SIZE_T size) : _protected(0), _address(address), _size(size)
- {
- _xc_assert_msg_fmt(VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_protected),
- "Address: %p Size: %X", _address, _size);
- }
-
- ~scope_relocate_al()
- {
- // Ignore if this fails, the memory was copied either way
- VirtualProtect(_address, _size, _protected, &_protected);
- }
- private:
- LPVOID _address;
- SIZE_T _size;
- DWORD _protected;
- };
-
const char* patch_archive_limit::get_name() const noexcept
{
return "archive_limit";
@@ -646,22 +625,12 @@ namespace xc
// supported 8 version archive
patch_mem_nop(g_plugin->get_base() + 0x1B6FA9F, { 0x8 });
-
-
-
- //detour_call(g_plugin->get_base() + 0x1B76AC9, (uintptr_t)&impl_memcpy_hash_from_archive_table);
- //memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1B78970;
-
- //detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash);
-
- //offset = g_plugin->get_base() + 1587095;
- //// Remove useless stuff.
- //
- //// mov eax, dword ptr ds:[rsi+0xC]
- //// mov dword ptr ds:[rdi+0xC], eax
- //patch_mem(offset, { 0x8B, 0x46, 0x0C, 0x89, 0x47, 0x0C });
+#if 0
+ detour_call(g_plugin->get_base() + 0x1B76AC9, (uintptr_t)&impl_memcpy_hash_from_archive_table);
+ memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1B78970;
- Sleep(20000);
+ detour_call(g_plugin->get_base() + 0x1B76AF7, (uintptr_t)&impl_set_index_archive_to_hash_og);
+#endif
}
else if (g_plugin->get_runtime_version() == RUNTIME_VERSION_1_10_984)
{
@@ -1160,7 +1129,7 @@ namespace xc
detour_call(g_plugin->get_base() + 0x158646F, (uintptr_t)&impl_memcpy_hash_from_archive_table);
memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1587BA0;
- detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash);
+ detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash_ng);
offset = g_plugin->get_base() + 1587095;
// Remove useless stuff.
@@ -1186,11 +1155,19 @@ namespace xc
return result; // 0 - OK
}
- void patch_archive_limit::impl_set_index_archive_to_hash()
+ void patch_archive_limit::impl_set_index_archive_to_hash_og()
+ {
+ // It is necessary to get the stack of the calling function.
+ auto rsp = (uintptr_t)_AddressOfReturnAddress() + 8;
+ // Set archive index from stack
+ *((uint16_t*)(rsp + 0x4C)) = *((uint16_t*)(rsp + 0x250));
+ }
+
+ void patch_archive_limit::impl_set_index_archive_to_hash_ng()
{
// It is necessary to get the stack of the calling function.
auto rsp = (uintptr_t)_AddressOfReturnAddress() + 8;
// Set archive index from stack
- *((uint16_t*)(rsp + 0x3C)) = *((uint16_t*)(rsp + 0x1E8));//min(, (uint16_t)255);
+ *((uint16_t*)(rsp + 0x3C)) = *((uint16_t*)(rsp + 0x1E8));
}
}
\ No newline at end of file
diff --git a/source/xc_patch_memory.cpp b/source/xc_patch_memory.cpp
index b487995..f5ab306 100644
--- a/source/xc_patch_memory.cpp
+++ b/source/xc_patch_memory.cpp
@@ -207,6 +207,38 @@ namespace xc
return nullptr;
}
};
+
+ class BSScaleformSysMemMapper
+ {
+ public:
+ constexpr static UInt32 PAGE_SIZE = (size_t)256 * 1024; // 256 Kb
+ constexpr static UInt32 HEAP_SIZE = (size_t)512 * 1024 * 1024; // 512 Mb
+
+ static uint32_t get_page_size(BSScaleformSysMemMapper* _this)
+ {
+ return (uint32_t)PAGE_SIZE;
+ }
+
+ static void* init(BSScaleformSysMemMapper* _this, size_t size)
+ {
+ return VirtualAlloc(NULL, (SIZE_T)size, MEM_RESERVE, PAGE_READWRITE);
+ }
+
+ static bool release(BSScaleformSysMemMapper* _this, void* address)
+ {
+ return VirtualFree((LPVOID)address, (SIZE_T)HEAP_SIZE, MEM_RELEASE);
+ }
+
+ static void* alloc(BSScaleformSysMemMapper* _this, void* address, size_t size)
+ {
+ return VirtualAlloc((LPVOID)address, (SIZE_T)size, MEM_COMMIT, PAGE_READWRITE);
+ }
+
+ static bool free(BSScaleformSysMemMapper* _this, void* address, size_t size)
+ {
+ return VirtualFree((LPVOID)address, (SIZE_T)size, MEM_DECOMMIT);
+ }
+ };
}
const char* patch_memory::get_name() const noexcept
@@ -269,6 +301,20 @@ namespace xc
detour_jump((g_plugin->get_base() + 0x1B13F70), (uintptr_t)&detail::BGSScrapHeap::alloc);
detour_jump((g_plugin->get_base() + 0x1B14580), (uintptr_t)&detail::BGSScrapHeap::dealloc);
detour_jump((g_plugin->get_base() + 0x1E21B10), (uintptr_t)&detail::bhkThreadMemorySource::__ctor__); // bhkThreadMemorySource init
+
+ // BSScaleformSysMemMapper
+ {
+ auto vtable = (uintptr_t*)(g_plugin->get_base() + 0x2EB92C8);
+ scope_relocate_al lock((LPVOID)vtable, 0x40);
+ vtable[0] = (uintptr_t)detail::BSScaleformSysMemMapper::get_page_size;
+ vtable[1] = (uintptr_t)detail::BSScaleformSysMemMapper::init;
+ vtable[2] = (uintptr_t)detail::BSScaleformSysMemMapper::release;
+ vtable[3] = (uintptr_t)detail::BSScaleformSysMemMapper::alloc;
+ vtable[4] = (uintptr_t)detail::BSScaleformSysMemMapper::free;
+
+ patch_mem((g_plugin->get_base() + 0x211214B), (UInt8*)&detail::BSScaleformSysMemMapper::PAGE_SIZE, 4);
+ patch_mem((g_plugin->get_base() + 0x2112151), (UInt8*)&detail::BSScaleformSysMemMapper::HEAP_SIZE, 4);
+ }
// So that it is never called
patch_mem((g_plugin->get_base() + 0xD0C160), { 0xC3, 0x90 }); // MemoryManager - Default/Static/File heaps init
@@ -287,6 +333,20 @@ namespace xc
detour_jump((g_plugin->get_base() + 0x15425E0), (uintptr_t)&detail::BGSScrapHeap::dealloc);
detour_jump((g_plugin->get_base() + 0x17D9DF0), (uintptr_t)&detail::bhkThreadMemorySource::__ctor__); // bhkThreadMemorySource init
+ // BSScaleformSysMemMapper
+ {
+ auto vtable = (uintptr_t*)(g_plugin->get_base() + 0x25131D8);
+ scope_relocate_al lock((LPVOID)vtable, 0x40);
+ vtable[0] = (uintptr_t)detail::BSScaleformSysMemMapper::get_page_size;
+ vtable[1] = (uintptr_t)detail::BSScaleformSysMemMapper::init;
+ vtable[2] = (uintptr_t)detail::BSScaleformSysMemMapper::release;
+ vtable[3] = (uintptr_t)detail::BSScaleformSysMemMapper::alloc;
+ vtable[4] = (uintptr_t)detail::BSScaleformSysMemMapper::free;
+
+ patch_mem((g_plugin->get_base() + 0x19FF5D9), (UInt8*)&detail::BSScaleformSysMemMapper::PAGE_SIZE, 4);
+ patch_mem((g_plugin->get_base() + 0x19FF5E4), (UInt8*)&detail::BSScaleformSysMemMapper::HEAP_SIZE, 4);
+ }
+
// So that it is never called
patch_mem((g_plugin->get_base() + 0xB8DC50), { 0xC3, 0x90 }); // MemoryManager - Default/Static/File heaps init
patch_mem((g_plugin->get_base() + 0x153D5D0), { 0xC3, 0x90 }); // BSSmallBlockAllocator init
@@ -295,7 +355,7 @@ namespace xc
}
else
_ERROR("The patch has not been fully installed, as the mod does not know the game");
-
+
return true;
}
diff --git a/version/build_version.txt b/version/build_version.txt
index 9d097b3..8c30d92 100644
Binary files a/version/build_version.txt and b/version/build_version.txt differ
diff --git a/version/resource_version2.h b/version/resource_version2.h
index 87d445d..6e8cb23 100644
Binary files a/version/resource_version2.h and b/version/resource_version2.h differ
diff --git a/x-cell.ini b/x-cell.ini
index f9c80cc..6fb0975 100644
--- a/x-cell.ini
+++ b/x-cell.ini
@@ -17,7 +17,7 @@ facegen=true
; - Use OS file cache for less disk access.
io=true
; - Replace old zlib decompression code with optimized libdeflate.
-libdeflate=false
+libdeflate=true
; - Replacing functions WritePrivateProfileStringA, GetPrivateProfileStringA, GetPrivateProfileIntA
; They are outdated and constantly open and parsing the ini file. Complements Buffout 4, Buffout 4 NG.
; Incompatible with the mod https://www.nexusmods.com/fallout4/mods/33947 PrivateProfileRedirector.