Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions .github/workflows/build-be.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Configure paths
run: |
New-Item -ItemType Directory -Force -Path ./artifacts/release/x64
Expand Down Expand Up @@ -36,13 +36,13 @@ jobs:
Copy-Item -Path ./assets/windows/doorstop_config.ini -Destination ./artifacts/verbose/x86/doorstop_config.ini
Copy-Item -Path ./LICENSE -Destination ./artifacts/verbose/LICENSE
- name: Upload Release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_win_release
path: artifacts/release
include-hidden-files: true
- name: Upload Verbose
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_win_verbose
path: artifacts/verbose
Expand All @@ -57,7 +57,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Configure paths
run: |
bash -c "mkdir -p artifacts/{verbose,release,debug}/{x86,x64}"
Expand Down Expand Up @@ -94,19 +94,19 @@ jobs:
cp assets/nix/run.sh artifacts/debug/x64/run.sh
cp LICENSE artifacts/debug/LICENSE
- name: Upload Release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_linux_release
path: artifacts/release
include-hidden-files: true
- name: Upload Verbose
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_linux_verbose
path: artifacts/verbose
include-hidden-files: true
- name: Upload Debug
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_linux_debug
path: artifacts/debug
Expand All @@ -117,7 +117,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Configure paths
run: |
mkdir -p artifacts/{verbose,release,debug}/universal
Expand All @@ -143,19 +143,19 @@ jobs:
cp assets/nix/run.sh artifacts/debug/universal/run.sh
cp LICENSE artifacts/debug/LICENSE
- name: Upload Release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_macos_release
path: artifacts/release
include-hidden-files: true
- name: Upload Verbose
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_macos_verbose
path: artifacts/verbose
include-hidden-files: true
- name: Upload Debug
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: doorstop_macos_debug
path: artifacts/debug
Expand All @@ -171,7 +171,7 @@ jobs:

steps:
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
path: artifacts
- name: Grab version
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/doc-links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Doc Links
on: [push, pull_request]

jobs:
links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: dtolnay/rust-toolchain@stable
- run: |
if [ ! -f tooling/doc-link-check ]; then
mkdir -p tooling
if [ -d phenotype-tooling ]; then
cd phenotype-tooling && cargo build --release --bin doc-link-check 2>&1 | tail -5
ln -sf ../phenotype-tooling/target/release/doc-link-check ../tooling/
else
echo "Note: doc-link-check not available; skipping" && exit 0
fi
fi
tooling/doc-link-check docs/ || true
12 changes: 10 additions & 2 deletions assets/windows/doorstop_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@
# Enable Doorstop?
enabled=true

# Path to the assembly to load and execute
# NOTE: The entrypoint must be of format `static void Doorstop.Entrypoint.Start()`
# Path to the assembly (or assemblies) to load and execute.
# NOTE: The entrypoint in each assembly must be `static void Doorstop.Entrypoint.Start()`
#
# Multiple assemblies can be specified with semicolons (no spaces around them):
# target_assembly=BepInEx\core\BepInEx.dll;ecs_plugins\MyPlugin.dll
#
# A directory path can also be used — all *.dll files in that directory are loaded:
# target_assembly=BepInEx\core;ecs_plugins
#
# Semicolon-separated directories and files can be combined freely.
target_assembly=Doorstop.dll

# If true, Unity's output log is redirected to <current folder>\output_log.txt
Expand Down
162 changes: 100 additions & 62 deletions src/bootstrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ void mono_doorstop_bootstrap(void *mono_domain) {
#undef CONFIG_EXT
}

setenv(TEXT("DOORSTOP_INVOKE_DLL_PATH"), config.target_assembly, TRUE);
setenv(TEXT("DOORSTOP_PROCESS_PATH"), app_path, TRUE);

char *assembly_dir = mono.assembly_getrootdir();
Expand All @@ -56,75 +55,104 @@ void mono_doorstop_bootstrap(void *mono_domain) {
setenv(TEXT("DOORSTOP_MANAGED_FOLDER_DIR"), norm_assembly_dir, TRUE);
free(norm_assembly_dir);

LOG("Opening assembly: %s", config.target_assembly);
void *file = fopen(config.target_assembly, "r");
if (!file) {
LOG("Failed to open assembly: %s", config.target_assembly);
if (config.num_assemblies == 0) {
LOG("No target assemblies configured — nothing to bootstrap.");
free(app_path);
return;
}

size_t size = get_file_size(file);
void *data = malloc(size);
fread(data, size, 1, file);
fclose(file);

LOG("Opened Assembly DLL (%d bytes); opening its main image", size);

char *dll_path = narrow(config.target_assembly);
MonoImageOpenStatus s = MONO_IMAGE_OK;
void *image = mono.image_open_from_data_with_name(data, size, TRUE, &s,
FALSE, dll_path);
free(data);
if (s != MONO_IMAGE_OK) {
LOG("Failed to load assembly image: %s. Got result: %d\n",
config.target_assembly, s);
return;
}
LOG("Bootstrapping %d assembly/ies...", (int)config.num_assemblies);

LOG("Image opened; loading included assembly");
for (config.assembly_index = 0;
config.assembly_index < config.num_assemblies;
config.assembly_index++) {

s = MONO_IMAGE_OK;
void *assembly = mono.assembly_load_from_full(image, dll_path, &s, FALSE);
free(dll_path);
if (s != MONO_IMAGE_OK) {
LOG("Failed to load assembly: %s. Got result: %d\n",
config.target_assembly, s);
return;
}
char_t *current_assembly =
config.target_assemblies[config.assembly_index];

LOG("Assembly loaded; looking for Doorstop.Entrypoint:Start");
void *desc = mono.method_desc_new("Doorstop.Entrypoint:Start", TRUE);
void *method = mono.method_desc_search_in_image(desc, image);
mono.method_desc_free(desc);
if (!method) {
LOG("Failed to find method Doorstop.Entrypoint:Start");
return;
}
LOG("[%d/%d] Opening assembly: %s",
(int)(config.assembly_index + 1),
(int)config.num_assemblies,
current_assembly);

void *signature = mono.method_signature(method);
unsigned int params = mono.signature_get_param_count(signature);
if (params != 0) {
LOG("Method has %d parameters; expected 0", params);
return;
}
/* Expose the current DLL path to managed code via env var. */
setenv(TEXT("DOORSTOP_INVOKE_DLL_PATH"), current_assembly, TRUE);

void *file = fopen(current_assembly, "r");
if (!file) {
LOG("Failed to open assembly: %s — skipping.", current_assembly);
continue;
}

size_t size = get_file_size(file);
void *data = malloc(size);
fread(data, size, 1, file);
fclose(file);

LOG("Opened Assembly DLL (%d bytes); opening its main image",
(int)size);

char *dll_path = narrow(current_assembly);
MonoImageOpenStatus s = MONO_IMAGE_OK;
void *image = mono.image_open_from_data_with_name(data, size, TRUE,
&s, FALSE, dll_path);
free(data);
if (s != MONO_IMAGE_OK) {
LOG("Failed to load assembly image: %s. Got result: %d — skipping.",
current_assembly, s);
free(dll_path);
continue;
}

LOG("Image opened; loading included assembly");

s = MONO_IMAGE_OK;
void *assembly =
mono.assembly_load_from_full(image, dll_path, &s, FALSE);
free(dll_path);
if (s != MONO_IMAGE_OK) {
LOG("Failed to load assembly: %s. Got result: %d — skipping.",
current_assembly, s);
continue;
}

LOG("Assembly loaded; looking for Doorstop.Entrypoint:Start");
void *desc = mono.method_desc_new("Doorstop.Entrypoint:Start", TRUE);
void *method = mono.method_desc_search_in_image(desc, image);
mono.method_desc_free(desc);
if (!method) {
LOG("Failed to find Doorstop.Entrypoint:Start in %s — skipping.",
current_assembly);
continue;
}

LOG("Invoking method %p", method);
void *exc = NULL;
mono.runtime_invoke(method, NULL, NULL, &exc);
if (exc != NULL) {
LOG("Error invoking code!");
if (mono.object_to_string) {
void *str = mono.object_to_string(exc, NULL);
char *exc_str_n = mono.string_to_utf8(str);
char_t *exc_str = widen(exc_str_n);
LOG("Error message: %s", exc_str);
LOG("\n");
free(exc_str);
mono.free(exc_str_n);
void *signature = mono.method_signature(method);
unsigned int params = mono.signature_get_param_count(signature);
if (params != 0) {
LOG("Method has %d parameters; expected 0 — skipping.", params);
continue;
}

LOG("Invoking method %p in %s", method, current_assembly);
void *exc = NULL;
mono.runtime_invoke(method, NULL, NULL, &exc);
if (exc != NULL) {
LOG("Error invoking code in %s!", current_assembly);
if (mono.object_to_string) {
void *str = mono.object_to_string(exc, NULL);
char *exc_str_n = mono.string_to_utf8(str);
char_t *exc_str = widen(exc_str_n);
LOG("Error message: %s", exc_str);
LOG("\n");
free(exc_str);
mono.free(exc_str_n);
}
} else {
LOG("Assembly %s bootstrapped successfully.", current_assembly);
}
}
LOG("Done");

LOG("All assemblies bootstrapped.");
free(app_path);
}

Expand Down Expand Up @@ -263,9 +291,19 @@ void il2cpp_doorstop_bootstrap() {
char_t *app_path = program_path();
char *app_path_n = narrow(app_path);

char_t *target_dir = get_folder_name(config.target_assembly);
/* For IL2CPP we use the first configured assembly as the entrypoint. */
char_t *first_assembly = (config.num_assemblies > 0)
? config.target_assemblies[0]
: NULL;
if (!first_assembly) {
LOG("No target assemblies configured — skipping IL2CPP bootstrap.");
free(app_path);
free(app_path_n);
return;
}
char_t *target_dir = get_folder_name(first_assembly);
char *target_dir_n = narrow(target_dir);
char_t *target_name = get_file_name(config.target_assembly, FALSE);
char_t *target_name = get_file_name(first_assembly, FALSE);
char *target_name_n = narrow(target_name);

char_t *app_paths_env =
Expand All @@ -284,7 +322,7 @@ void il2cpp_doorstop_bootstrap() {
const char *props = "APP_PATHS";

setenv(TEXT("DOORSTOP_INITIALIZED"), TEXT("TRUE"), TRUE);
setenv(TEXT("DOORSTOP_INVOKE_DLL_PATH"), config.target_assembly, TRUE);
setenv(TEXT("DOORSTOP_INVOKE_DLL_PATH"), first_assembly, TRUE);
setenv(TEXT("DOORSTOP_MANAGED_FOLDER_DIR"), config.clr_corlib_dir, TRUE);
setenv(TEXT("DOORSTOP_PROCESS_PATH"), app_path, TRUE);
setenv(TEXT("DOORSTOP_DLL_SEARCH_DIRS"), app_paths_env, TRUE);
Expand Down
13 changes: 11 additions & 2 deletions src/config/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ void cleanup_config() {
val = NULL; \
}

FREE_NON_NULL(config.target_assembly);
if (config.target_assemblies != NULL) {
for (size_t i = 0; i < config.num_assemblies; i++) {
FREE_NON_NULL(config.target_assemblies[i]);
}
free(config.target_assemblies);
config.target_assemblies = NULL;
config.num_assemblies = 0;
}
FREE_NON_NULL(config.boot_config_override);
FREE_NON_NULL(config.mono_dll_search_path_override);
FREE_NON_NULL(config.clr_corlib_dir);
Expand All @@ -27,7 +34,9 @@ void init_config_defaults() {
config.mono_debug_enabled = FALSE;
config.mono_debug_suspend = FALSE;
config.mono_debug_address = NULL;
config.target_assembly = NULL;
config.target_assemblies = NULL;
config.num_assemblies = 0;
config.assembly_index = 0;
config.boot_config_override = NULL;
config.mono_dll_search_path_override = NULL;
config.clr_corlib_dir = NULL;
Expand Down
Loading