Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Default owner for everything
* @KooshaPari
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
Loading