Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit e1432b5

Browse files
committed
Support Armored Core 6
Version bump to 2.1.0
1 parent b84f2ee commit e1432b5

20 files changed

+111
-20
lines changed

Diff for: CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
55
include(GetGitRevisionDescription)
66
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
77

8-
set(version "2.0.1")
8+
set(version "2.1.0")
99
set(VCPKG_TOOLS "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-windows")
1010

1111
# Detours currently has no CMake manifests: https://github.com/microsoft/Detours/pull/48.

Diff for: cmake/ModEngineInstaller.cmake

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
set(CPACK_PACKAGE_NAME "ModEngine")
22
set(CPACK_PACKAGE_VENDOR "https://github.com/soulsmods/modengine2")
33
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Mod Engine 2 - Mod companion framework for Souls games")
4-
set(CPACK_PACKAGE_VERSION "2.0.0.1")
4+
set(CPACK_PACKAGE_VERSION "2.1.0.0")
55
set(CPACK_PACKAGE_INSTALL_DIRECTORY "modengine2")
66
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/installer/resources/LICENSE.txt")
77
set(CPACK_WIX_UPGRADE_GUID "1bf93396-5829-4275-8e34-01e443d54a98")
@@ -71,8 +71,10 @@ install(FILES tools/scylla/InjectorCLIx64.exe
7171
install(FILES
7272
installer/dist/config_darksouls3.toml
7373
installer/dist/config_eldenring.toml
74+
installer/dist/config_armoredcore6.toml
7475
installer/dist/launchmod_darksouls3.bat
7576
installer/dist/launchmod_eldenring.bat
77+
installer/dist/launchmod_armoredcore6.bat
7678
installer/dist/README.txt
7779
DESTINATION .
7880
COMPONENT application)

Diff for: include/modengine/extension.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ class ModEngineExtension {
110110
}
111111

112112
template <typename T>
113-
void register_hook(GameType type, ScannedHook<T> *hook, const ScanPattern &signature, T detour, HookScanMode mode)
113+
void register_hook(GameType type, ScannedHook<T> *hook, const ScanPattern &signature, int64_t offset, T detour, HookScanMode mode)
114114
{
115115
hook->mode = mode;
116116
hook->pattern = signature;
117+
hook->offset = offset;
117118
hook->replacement = detour;
118119

119120
m_ext_connector->register_hook(type, (ScannedHook<GenericFunctionPointer>*) hook);

Diff for: include/modengine/game_type.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ enum GameType : std::uint32_t {
1010
DS3 = 1 << 2,
1111
SEKIRO = 1 << 3,
1212
ELDEN_RING = 1 << 4,
13+
ARMORED_CORE_6 = 1 << 5,
1314
ALL = 0xFFFFFFFF
1415
};
1516

Diff for: include/modengine/hook.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,18 @@ template <typename T>
5252
struct ScannedHook {
5353
ScannedHook()
5454
: mode(SCAN_FUNCTION)
55+
, pattern()
56+
, offset(0)
5557
, original(nullptr)
5658
, replacement(nullptr)
5759
, applied(false)
5860
{
5961
}
6062

61-
ScannedHook(HookScanMode _mode, ScanPattern _pattern, T _replacement)
63+
ScannedHook(HookScanMode _mode, ScanPattern _pattern, int64_t _offset, T _replacement)
6264
: mode(_mode)
6365
, pattern(_pattern)
66+
, offset(_offset)
6467
, original(nullptr)
6568
, replacement(_replacement)
6669
, applied(false)
@@ -75,6 +78,7 @@ struct ScannedHook {
7578
bool applied;
7679
HookScanMode mode;
7780
ScanPattern pattern;
81+
int64_t offset;
7882
T original;
7983
T replacement;
8084
};

Diff for: installer/dist/README.txt

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
Mod Engine 2 Preview release:
22

3-
This is a preview release of Mod Engine 2 for Elden Ring. Mod Engine 2 is a utility for injecting various code into the game
4-
for the use of mods. Among other things, Mod Engine 2 allows the usage of mods that modify the game files without having to
5-
go through the hassle of unpacking the game archives and patching the game exe. Mod Engine 2 does this by injecting code into
6-
the game's asset system, and redirecting the game to load a modded file inside your mod folder if one exists instead of loading
7-
the original file in the game's big archives.
3+
This is a preview release of Mod Engine 2 for Elden Ring and Armored Core 6. Mod Engine 2 is a utility for injecting various
4+
code into the game for the use of mods. Among other things, Mod Engine 2 allows the usage of mods that modify the game files
5+
without having to go through the hassle of unpacking the game archives and patching the game exe. Mod Engine 2 does this
6+
by injecting code into the game's asset system, and redirecting the game to load a modded file inside your mod folder if
7+
one exists instead of loading the original file in the game's big archives.
88

99
Mod Engine 2 is a ground up rewrite of Mod Engine and is designed to improve over the existing user experience while also being
1010
more reliable and having more infrastructure to diagnose issues. This public release currently only supports modded file injection,

Diff for: installer/dist/config_armoredcore6.toml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Global mod engine configuration
2+
[modengine]
3+
# If set to true the debug console will appear while the game is running
4+
debug = false
5+
6+
# List of files that will be loaded into the game as DLL mods.
7+
# Absolute paths to mods are supported but must use '\\' to separate path items. For example, if your mod is at E:\coolstuff\coolmod.dll, you must enter
8+
# the path in the config as "E:\\coolstuff\\coolmod.dll".
9+
# If there's no drive specifier (C:, D:, etc), the path is relative to where the launcher is located. For example, having the path as "mod.dll" will tell
10+
# Mod Engine 2 to look for the directory mod inside the Mod Engine 2 directory with the launcher.
11+
#
12+
# Multiple mods must be separated with commas. For example if you have 3 mods, you will have something like the following:
13+
# external_dlls = [ "coolmod.dll", "D:\\nicemods\\nicemod.dll", "sosofolder\sosomod.dll" ]
14+
external_dlls = []
15+
16+
# Mod loader configuration
17+
[extension.mod_loader]
18+
enabled = true
19+
20+
# Not applicable for Armored Core 6
21+
loose_params = false
22+
23+
# List of directories that contain modded files in order of prioritization. Inside each specified mod directory must have the game
24+
# assets in Fromsoft's asset structure. I.e. if you mod parts/something.partsbnd.dcx, the modded version must be at mod/parts/something.partsbnd.dcx.
25+
# Absolute paths to mods are supported but must use '\\' to separate path items. For example, if your mod is at E:\coolstuff\coolmod, you must enter
26+
# the path in the config as "E:\\coolstuff\\coolmod".
27+
# If there's no drive specifier (C:, D:, etc), the path is relative to where the launcher is located. For example, having the path as "mod" will tell
28+
# Mod Engine 2 to look for the directory mod inside the Mod Engine 2 directory with the launcher.
29+
#
30+
# Multiple mods must be separated with commas. For example if you have 3 mods, you will have something like the following:
31+
# mods = [
32+
# { enabled = true, name = "coolmod", path = "mod1" },
33+
# { enabled = true, name = "nicemod", path = "mod2" },
34+
# { enabled = true, name = "sosomod", path = "mod3" }
35+
# ]
36+
# Note that modengine 2 currently has no way to resolve conflicting files including regulation.bin, and thus the mod with the highest priority
37+
# will have the modded file be loaded in the case of conflict. Some support for merging of params and potentially other assets is considered for
38+
# a future release.
39+
mods = [
40+
{ enabled = true, name = "default", path = "mod" }
41+
]
42+
43+
# When enabled, scylla hide will be injected into the game. This allows for antidebug measures in the game to be bypassed so that you can attach
44+
# debuggers such as Cheat Engine, x64dbg, windbg, etc to the game without as much trouble. If you're not reverse engineering the game, this option
45+
# is probably not for you.
46+
[extension.scylla_hide]
47+
enabled = false

Diff for: installer/dist/config_eldenring.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ mods = [
4040
{ enabled = true, name = "default", path = "mod" }
4141
]
4242

43-
# When enabled, scylly hide will be injected into the game. This allows for antidebug measures in the game to be bypassed so that you can attach
43+
# When enabled, scylla hide will be injected into the game. This allows for antidebug measures in the game to be bypassed so that you can attach
4444
# debuggers such as Cheat Engine, x64dbg, windbg, etc to the game without as much trouble. If you're not reverse engineering the game, this option
4545
# is probably not for you.
4646
[extension.scylla_hide]

Diff for: installer/dist/launchmod_armoredcore6.bat

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
chcp 65001
2+
:: The above line is necessary in case you edit this file to lead to a path with Unicode characters.
3+
.\modengine2_launcher.exe -t ac6 -c .\config_armoredcore6.toml

Diff for: launcher/launcher.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,25 @@ enum LaunchTarget {
3030
AUTODETECT,
3131
DS3,
3232
ELDEN_RING,
33+
ARMORED_CORE_6,
3334
};
3435

3536
static std::map<LaunchTarget, LaunchTargetParams> launch_targets {
3637
{ DS3, { L"374320", L"Game/DarkSoulsIII.exe", L"config_darksouls3.toml" } },
37-
{ ELDEN_RING, { L"1245620", L"Game/eldenring.exe", L"config_eldenring.toml" } }
38+
{ ELDEN_RING, { L"1245620", L"Game/eldenring.exe", L"config_eldenring.toml" } },
39+
{ ARMORED_CORE_6, { L"1888160", L"Game/armoredcore6.exe", L"config_armoredcore6.toml" } }
3840
};
3941

4042
static std::map<std::string, LaunchTarget> launch_target_names {
4143
{ "ds3", DS3 },
4244
{ "er", ELDEN_RING },
45+
{ "ac6", ARMORED_CORE_6 },
4346
};
4447

4548
static std::map<std::string, LaunchTarget> exe_names {
4649
{ "DarkSoulsIII.exe", DS3 },
4750
{ "eldenring.exe", ELDEN_RING },
51+
{ "armoredcore6.exe", ARMORED_CORE_6 },
4852
};
4953

5054
std::wstring GetCurrentDirectory()

Diff for: src/main.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <optional>
77
#include <windows.h>
88
#include <iostream>
9+
#include <spdlog/sinks/stdout_color_sinks.h>
910
#include <modengine/settings_loader.h>
1011

1112
using namespace modengine;
@@ -53,6 +54,17 @@ int WINAPI modengine_entrypoint(void)
5354
auto settings_status = settings_loader.load(settings);
5455
auto config = settings.get_config_reader().read_config_object<ModEngineConfig>({ "modengine" });
5556

57+
if (config.debug && !is_debugger_enabled) {
58+
// Create debug console
59+
AllocConsole();
60+
FILE* stream;
61+
freopen_s(&stream, "CONOUT$", "w", stdout);
62+
freopen_s(&stream, "CONIN$", "r", stdin);
63+
64+
logger->set_level(spdlog::level::trace);
65+
logger->sinks().push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
66+
}
67+
5668
const auto game_info = GameInfo::from_current_module();
5769
if (!game_info) {
5870
error("Unable to detect a supported game");

Diff for: src/modengine/ext/mod_loader/archive_file_overrides.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ void process_archive_path(wchar_t* raw_path, size_t raw_path_len)
126126
for (auto i = 1; i < prefix_len && i < raw_path_len; i++) {
127127
raw_path[i] = '/';
128128
}
129+
130+
if (get_level() <= level::debug) {
131+
std::wstring replaced(raw_path, raw_path_len);
132+
debug(L"Replaced path with {}", replaced);
133+
}
129134
}
130135

131136
bool path_contains(const fs::path& root, const fs::path& filepath)

Diff for: src/modengine/ext/mod_loader/mod_loader_extension.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ auto loose_params_aob_2 = util::hex_string("0F 85 C5 00 00 00 48 8D 4C 24 28");
1616
//auto loose_params_aob_3 = util::hex_string("E8 C8 F7 F7 FF 90 E9 73 E3 1F 04");
1717

1818
auto virtual_to_archive_path_er_aob = util::hex_aob("e8 ?? ?? ?? ?? 48 83 7b 20 08 48 8d 4b 08 72 03 48 8b 09 4c 8b 4b 18 41 b8 05 00 00 00 4d 3b c8");
19+
auto virtual_to_archive_path_ac6_aob = util::hex_aob("cf e8 ?? ?? ?? ?? 48 83 7b 20 08 48 8d 4b 08 72 03 48 8b 09 4c 8b 4b 18 41 b8 05 00 00 00 4d 3b c8");
1920

2021
static fs::path primary_mod_path(const Settings& settings)
2122
{
@@ -57,7 +58,8 @@ void ModLoaderExtension::on_attach()
5758

5859
register_hook(ALL, &hooked_CreateFileW, kernel32_path.wstring(), "CreateFileW", tCreateFileW);
5960
register_hook(DS3, &hooked_virtual_to_archive_path_ds3, util::rva2addr(0x7d660), virtual_to_archive_path_ds3);
60-
register_hook(ELDEN_RING, &hooked_virtual_to_archive_path_eldenring, virtual_to_archive_path_er_aob, virtual_to_archive_path_eldenring, SCAN_CALL_INST);
61+
register_hook(ELDEN_RING, &hooked_virtual_to_archive_path_eldenring, virtual_to_archive_path_er_aob, 0x0, virtual_to_archive_path_eldenring, SCAN_CALL_INST);
62+
register_hook(ARMORED_CORE_6, &hooked_virtual_to_archive_path_eldenring, virtual_to_archive_path_ac6_aob, 0x1, virtual_to_archive_path_eldenring, SCAN_CALL_INST);
6163

6264
auto config = get_config<ModLoaderConfig>();
6365
for (const auto& mod : config.mods) {

Diff for: src/modengine/game_info.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ static std::unordered_map<std::wstring, GameType> game_type_executables {
1313
{ L"DarkSoulsII.exe", DS2 },
1414
{ L"DarkSoulsIII.exe", DS3 },
1515
{ L"sekiro.exe", SEKIRO },
16-
{ L"eldenring.exe", ELDEN_RING }
16+
{ L"eldenring.exe", ELDEN_RING },
17+
{ L"armoredcore6.exe", ARMORED_CORE_6 }
1718
};
1819

1920
static std::unordered_map<GameType, std::string> game_type_descriptions {
2021
{ DS_REMASTERED, "Dark Souls Remastered" },
2122
{ DS2, "Dark Souls 2: Scholar of The First Sin" },
2223
{ DS3, "Dark Souls 3" },
2324
{ SEKIRO, "Sekiro" },
24-
{ ELDEN_RING, "Elden Ring" }
25+
{ ELDEN_RING, "Elden Ring" },
26+
{ ARMORED_CORE_6, "Armored Core 6" }
2527
};
2628

2729
static std::optional<GameType> game_type_for_exe(const std::wstring& exe_name)

Diff for: src/modengine/hook_set.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ bool HookSet::hook_all()
5353
error("Could not find pattern");
5454
continue;
5555
}
56+
*addr = (uintptr_t)(((char*)*addr) + hook->offset);
5657
debug("Found address at 0x{0:08x}", *addr);
5758
if (hook->mode == SCAN_CALL_INST) {
5859
// Assume near call x64 instruction for now

Diff for: src/modengine/mod_engine.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ void ModEngine::attach()
5353
}
5454

5555
auto lua = m_script_host.get_state();
56+
#if 0
5657
sol_ImGui::Init(lua);
58+
#endif
5759
modengine::scripting::bind_patch_api(this, lua);
5860

5961
m_script_host.load_scripts(m_config.script_roots);

Diff for: src/modengine/settings_loader.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ SettingsLoadResult SettingsLoader::load(modengine::Settings& settings)
3333

3434
if (!result.inline_install) {
3535
const auto global_settings_path = m_installation / "config.toml";
36-
36+
info("Attempting to load global config at {}", global_settings_path.string());
3737
if (fs::exists(global_settings_path)) {
3838
result.found_global_config = load_toml_into(settings, global_settings_path);
39+
if (result.found_global_config)
40+
info("Global config loaded");
3941
}
4042
}
4143

@@ -44,9 +46,12 @@ SettingsLoadResult SettingsLoader::load(modengine::Settings& settings)
4446
if (settings_path_env != nullptr) {
4547
auto path = fs::path(settings_path_env);
4648
auto local_modengine_path = path.parent_path();
49+
info("Attempting to load mod settings config at {}", path.string());
4750

4851
result.found_local_config = load_toml_into(settings, path);
4952
settings.m_modengine_local_path = local_modengine_path;
53+
if (result.found_local_config)
54+
info("Local config loaded");
5055
}
5156

5257
return result;

Diff for: src/modengine/util/platform.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
#include <windows.h>
44

55
namespace modengine::util {
6-
std::filesystem::path&& system_directory()
6+
std::filesystem::path system_directory()
77
{
8-
TCHAR system_folder[MAX_PATH];
8+
TCHAR system_folder[MAX_PATH + 1];
99
if (!GetSystemDirectory(system_folder, MAX_PATH)) {
1010
throw std::runtime_error("GetSystemDirectory(..., MAX_PATH) failed");
1111
}
1212

13-
return std::move(std::filesystem::path(system_folder));
13+
return { system_folder };
1414
}
1515

1616
uintptr_t rva2addr(ptrdiff_t offset)

Diff for: src/modengine/util/platform.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace modengine::util {
66

7-
std::filesystem::path&& system_directory();
7+
std::filesystem::path system_directory();
88
uintptr_t rva2addr(ptrdiff_t offset);
99

1010
}

Diff for: src/modengine/version.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#define VERSION "2.0.0-preview5-@GIT_SHA1@"
1+
#define VERSION "2.1.0-@GIT_SHA1@"
22

33
namespace modengine {
44

0 commit comments

Comments
 (0)