refactor(launcher): Major re-work of launcher

Kudos to Shiz for providing the groundwork for this.

Fundamentally re-think how launcher operates and
bootstrapping the games is managed and configured.

This brings it significantly closer to how the original
bootstrap is doing the job: launcher now utilizes the
data (structures) provided by the bootstrap.xml configuration
file. This creates compatibility with vanilla data dumps
and original stock images. Note that bemanitools does not
include any code or means to run DRM'd data, only decrypted.

But, this allows users to keep decrypted dumps as stock as
possible which means:

* No copying around of property files anymore
* Keep the modules/ folder with the binaries
* Have bemanitools binaries separate in the data
* No need to edit/customize the original configuration files

A list of key features of the "new" launcher:

* Boostrap games by following the configuration provided by
  stock game's bootstrap.xml files
* Custom launcher.xml configuration file that adds further
  launcher configurable features, composability of
  bootstrap.xml configuration(s) as well as configuration
  overriding/stacking of selected types of configurations,
  e.g. eamuse config, avs-config. The latter eliminates
  the need for modifying stock config files in the prop/
  folder
* Unified logging system: launcher and AVS logging uses
  the same logger, all output can now be in a single file
* Original features such as various hook types still
  available

Due to the significant architectural changes, this also
breaks with any backwards compatibility to existing
launcher setups. Thus, users need to migrate by re-applying
the new configuration format and migrating their config
parameters accordingly.

Further migration instructions and updated documentation
will be provided upon release.

Co-authored-by: Shiz <hi@shiz.me>
This commit is contained in:
icex2
2024-02-25 09:30:53 +01:00
co-authored by Shiz
parent d72996c5d9
commit 04310f49fd
37 changed files with 4917 additions and 943 deletions
+144 -15
View File
@@ -1,22 +1,29 @@
#define LOG_MODULE "module"
#include <windows.h>
#include "core/log.h"
#include "hook/pe.h"
#include "imports/avs.h"
#include "imports/eapki.h"
#include "launcher/module.h"
#include "launcher/property-util.h"
#include "util/log.h"
#include "util/str.h"
#define MM_ALLOCATION_GRANULARITY 0x10000
static bool module_replace_dll_iat(HMODULE hModule, struct array *iat_hook_dlls)
static bool
module_replace_dll_iat(HMODULE hModule, const struct array *iat_hook_dlls)
{
log_assert(hModule);
log_assert(iat_hook_dlls);
log_misc("replace dll iat: %p", hModule);
if (iat_hook_dlls->nitems == 0)
return true;
@@ -127,11 +134,13 @@ inject_fail:
return false;
}
void module_context_init(struct module_context *module, const char *path)
void module_init(struct module_context *module, const char *path)
{
log_assert(module != NULL);
log_assert(path != NULL);
log_info("init: %s", path);
module->dll = LoadLibrary(path);
if (module->dll == NULL) {
@@ -159,16 +168,20 @@ void module_context_init(struct module_context *module, const char *path)
}
module->path = str_dup(path);
log_misc("init done");
}
void module_context_init_with_iat_hooks(
void module_with_iat_hooks_init(
struct module_context *module,
const char *path,
struct array *iat_hook_dlls)
const struct array *iat_hook_dlls)
{
log_assert(module != NULL);
log_assert(path != NULL);
log_info("init iat hooks: %s", path);
module->dll = LoadLibraryExA(path, NULL, DONT_RESOLVE_DLL_REFERENCES);
if (module->dll == NULL) {
@@ -211,16 +224,71 @@ void module_context_init_with_iat_hooks(
module->path = str_dup(path);
}
bool module_context_invoke_init(
void module_init_invoke(
const struct module_context *module,
char *sidcode,
struct property_node *app_config)
struct ea3_ident_config *ea3_ident_config,
struct property_node *app_params_node)
{
char sidcode_short[17];
char sidcode_long[21];
char security_code[9];
dll_entry_init_t init;
bool ok;
log_assert(module != NULL);
log_assert(sidcode != NULL);
log_assert(app_config != NULL);
log_info("init invoke");
/* Set up security env vars */
str_format(
security_code,
lengthof(security_code),
"G*%s%s%s%s",
ea3_ident_config->model,
ea3_ident_config->dest,
ea3_ident_config->spec,
ea3_ident_config->rev);
log_misc("security code: %s", security_code);
std_setenv("/env/boot/version", "0.0.0");
std_setenv("/env/profile/security_code", security_code);
std_setenv("/env/profile/system_id", ea3_ident_config->pcbid);
std_setenv("/env/profile/account_id", ea3_ident_config->pcbid);
std_setenv("/env/profile/license_id", ea3_ident_config->softid);
std_setenv("/env/profile/software_id", ea3_ident_config->softid);
std_setenv("/env/profile/hardware_id", ea3_ident_config->hardid);
/* Set up the short sidcode string, let dll_entry_init mangle it */
str_format(
sidcode_short,
lengthof(sidcode_short),
"%s%s%s%s%s",
ea3_ident_config->model,
ea3_ident_config->dest,
ea3_ident_config->spec,
ea3_ident_config->rev,
ea3_ident_config->ext);
log_misc("sidcode short: %s", sidcode_short);
/* Set up long-form sidcode env var */
str_format(
sidcode_long,
lengthof(sidcode_long),
"%s:%s:%s:%s:%s",
ea3_ident_config->model,
ea3_ident_config->dest,
ea3_ident_config->spec,
ea3_ident_config->rev,
ea3_ident_config->ext);
log_misc("sidecode long: %s", sidcode_long);
/* Set this up beforehand, as certain games require it in dll_entry_init */
std_setenv("/env/profile/soft_id_code", sidcode_long);
init = (void *) GetProcAddress(module->dll, "dll_entry_init");
@@ -229,16 +297,67 @@ bool module_context_invoke_init(
"%s: dll_entry_init not found. Is this a game DLL?", module->path);
}
return init(sidcode, app_config);
log_info("Invoking game init...");
struct property *prop =
property_util_cstring_load("<param><io>p3io</io></param>");
struct property_node *prop_node = property_search(prop, NULL, "/param");
property_util_log(prop);
property_util_node_log(prop_node);
ok = init(sidcode_short, prop_node);
if (!ok) {
log_fatal("%s: dll_module_init() returned failure", module->path);
} else {
log_info("Game init done");
}
/* Back-propagate sidcode, as some games modify it during init */
memcpy(
ea3_ident_config->model,
sidcode_short + 0,
sizeof(ea3_ident_config->model) - 1);
ea3_ident_config->dest[0] = sidcode_short[3];
ea3_ident_config->spec[0] = sidcode_short[4];
ea3_ident_config->rev[0] = sidcode_short[5];
memcpy(
ea3_ident_config->ext,
sidcode_short + 6,
sizeof(ea3_ident_config->ext));
/* Set up long-form sidcode env var again */
str_format(
sidcode_long,
lengthof(sidcode_long),
"%s:%s:%s:%s:%s",
ea3_ident_config->model,
ea3_ident_config->dest,
ea3_ident_config->spec,
ea3_ident_config->rev,
ea3_ident_config->ext);
std_setenv("/env/profile/soft_id_code", sidcode_long);
log_misc("back-propagated sidcode long: %s", sidcode_long);
log_misc("init invoke done");
}
bool module_context_invoke_main(const struct module_context *module)
bool module_main_invoke(const struct module_context *module)
{
/* GCC warns if you call a variable "main" */
dll_entry_main_t main_;
bool result;
log_assert(module != NULL);
log_info("main invoke");
main_ = (void *) GetProcAddress(module->dll, "dll_entry_main");
if (main_ == NULL) {
@@ -246,11 +365,19 @@ bool module_context_invoke_main(const struct module_context *module)
"%s: dll_entry_main not found. Is this a game DLL?", module->path);
}
return main_();
log_info("Invoking game's main function...");
result = main_();
log_info("Main terminated, result: %d", result);
return result;
}
void module_context_fini(struct module_context *module)
void module_fini(struct module_context *module)
{
log_info("fini");
if (module == NULL) {
return;
}
@@ -260,4 +387,6 @@ void module_context_fini(struct module_context *module)
if (module->dll != NULL) {
FreeLibrary(module->dll);
}
log_misc("fini done");
}