From d79288f11d0e663c56749eb32aacdb440db2ad15 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Tue, 7 Jan 2025 19:06:18 +0000 Subject: [PATCH 1/3] Begin Monkeyloader Work --- .forgejo/workflows/build-on-tag.yml | 7 ++- Dockerfile | 10 +++- defaults/loader/Loader.cs | 76 +++++++++++++++++++++++++++++ defaults/loader/Loader.csproj | 11 +++++ docker-compose.yml | 12 ++--- scripts/02_setup_config.sh | 60 ++++++++++++++++++++--- scripts/03_download_mods.sh | 41 +++++++--------- scripts/99_start.sh | 16 ++++-- 8 files changed, 187 insertions(+), 46 deletions(-) create mode 100644 defaults/loader/Loader.cs create mode 100644 defaults/loader/Loader.csproj diff --git a/.forgejo/workflows/build-on-tag.yml b/.forgejo/workflows/build-on-tag.yml index 888102b..e7607c9 100644 --- a/.forgejo/workflows/build-on-tag.yml +++ b/.forgejo/workflows/build-on-tag.yml @@ -29,9 +29,8 @@ jobs: # Build and push multi-platform Docker images docker build -t $REPO_HOST/$REPO_PATH:$TAG --push . # Tag and push latest - docker tag $REPO_HOST/$REPO_PATH:$TAG $REPO_HOST/$REPO_PATH:latest - docker push $REPO_HOST/$REPO_PATH:latest + docker tag $REPO_HOST/$REPO_PATH:$TAG + docker push $REPO_HOST/$REPO_PATH:$TAG # Remove the local image to save storage - docker rmi $REPO_HOST/$REPO_PATH:$TAG - docker rmi $REPO_HOST/$REPO_PATH:latest \ No newline at end of file + docker rmi $REPO_HOST/$REPO_PATH:$TAG \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index afe92f8..36b362c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,10 @@ -FROM mcr.microsoft.com/dotnet/runtime +FROM mcr.microsoft.com/dotnet/sdk AS SDK + +COPY ./defaults/loader /loader +WORKDIR /loader +RUN dotnet build -o /app -c Release + +FROM mcr.microsoft.com/dotnet/runtime AS runtime ENV \ LANG="en_US.UTF-8" \ @@ -21,6 +27,7 @@ RUN DEBIAN_FRONTEND=noninteractive \ locales \ mono-complete \ opus-tools \ + unzip \ sudo # make data directories @@ -38,6 +45,7 @@ ENV STOP_LAUNCH=false COPY defaults /mnt/defaults COPY scripts /scripts +COPY --from=SDK /app/ /app/ RUN chmod +x /scripts/* ENTRYPOINT ["/scripts/00_setup.sh"] diff --git a/defaults/loader/Loader.cs b/defaults/loader/Loader.cs new file mode 100644 index 0000000..38d8876 --- /dev/null +++ b/defaults/loader/Loader.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +class Program +{ + static void Main(string[] args) + { + // Hardcoded working directory + string workDir = "/data/resonite/Headless"; + string resonitePath = Path.Combine(workDir, "Resonite.dll"); + string winhttpPath = Path.Combine(workDir, "winhttp.dll"); + + Console.WriteLine($"Using hardcoded work directory: {workDir}"); + + // Verify work directory exists + if (!Directory.Exists(workDir)) + { + Console.WriteLine($"Error: Work directory '{workDir}' does not exist."); + return; + } + + // Verify winhttp.dll exists + if (!File.Exists(winhttpPath)) + { + Console.WriteLine($"Error: Cannot find winhttp.dll at {winhttpPath}"); + return; + } + + // Load the winhttp.dll + IntPtr handle = LoadLibrary(winhttpPath); + if (handle == IntPtr.Zero) + { + Console.WriteLine("Failed to load winhttp.dll"); + return; + } + + Console.WriteLine("winhttp.dll loaded successfully"); + + // Verify Resonite.dll exists + if (!File.Exists(resonitePath)) + { + Console.WriteLine($"Error: Cannot find Resonite.dll at {resonitePath}"); + return; + } + + // Load and execute Resonite.dll + Assembly resoniteAssembly = Assembly.LoadFrom(resonitePath); + + // Find the entry point and invoke it + MethodInfo entryPoint = resoniteAssembly.EntryPoint; + if (entryPoint == null) + { + Console.WriteLine("Error: Could not find entry point in Resonite.dll"); + return; + } + + Console.WriteLine("Executing Resonite.dll with provided arguments..."); + entryPoint.Invoke(null, new object[] { args }); + } + + #if WINDOWS + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern IntPtr LoadLibrary(string lpFileName); + #else + [DllImport("libc.so.6", SetLastError = true)] + private static extern IntPtr dlopen(string fileName, int flags); + + private static IntPtr LoadLibrary(string fileName) + { + const int RTLD_NOW = 2; + return dlopen(fileName, RTLD_NOW); + } + #endif +} diff --git a/defaults/loader/Loader.csproj b/defaults/loader/Loader.csproj new file mode 100644 index 0000000..1035c2d --- /dev/null +++ b/defaults/loader/Loader.csproj @@ -0,0 +1,11 @@ + + + + Exe + net9.0 + enable + enable + true + + + diff --git a/docker-compose.yml b/docker-compose.yml index 481997d..98088e1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,7 @@ services: resonite: - # build: . - image: git.merith.xyz/oci/resonite:nightly - - container_name: resonite + build: . + # image: git.merith.xyz/oci/resonite:nightly network_mode: host stdin_open: true tty: true @@ -35,11 +33,13 @@ services: COMMAND: "/scripts/99_start.sh" # Wether to enable the Resonite Mod Loader - RESONITE_MOD_LOADER: true + MONKEY_LOADER: false # list of mods to load, MOD_URLS: | - https://github.com/New-Project-Final-Final-WIP/HeadlessTweaks/releases/latest/download/HeadlessTweaks.dll + https://github.com/Raidriar796/StresslessHeadless/releases/download/2.0.0-rc1/StresslessHeadless.dll + + # https://github.com/New-Project-Final-Final-WIP/HeadlessTweaks/releases/latest/download/HeadlessTweaks.dll # Controls the UID:GID of the headless, defaults to `root` if not set RUN_AS: 1000 diff --git a/scripts/02_setup_config.sh b/scripts/02_setup_config.sh index 5ec5d7c..30de30e 100755 --- a/scripts/02_setup_config.sh +++ b/scripts/02_setup_config.sh @@ -1,10 +1,10 @@ #!/bin/bash ## Setup Resonite Config -echo "Setting up Resonite Config" +echo "Setting up Resonite Config" # if CONFIG_FILE is not set, use default config path -if [ ! -f $CONFIG_FILE ]; then +if [ ! -f $CONFIG_FILE ]; then echo "No Resonite Config found, copying from template" cp /mnt/defaults/resonite.json $CONFIG_FILE fi @@ -16,10 +16,54 @@ if [ ! -n "$CONFIG_DATA" ]; then CONFIG_DATA=$(grep -v " null," "$CONFIG_FILE") fi -## Setup Modloader Configs -if [ "$RESONITE_MOD_LOADER" == "true" ]; then - echo "Setting up Modloader Configs" - DEFAULT_RESONITE_ARGS=$(echo "$DEFAULT_RESONITE_ARGS -LoadAssembly /data/resonite/Headless/Libraries/ResoniteModLoader.dll") +if [ "$MONKEY_LOADER" == "true" ]; then + echo "Downloading MonkeyLoader" + + # Define variables + monkeyloader_url="https://github.com/ResoniteModdingGroup/MonkeyLoader.GamePacks.Resonite/releases/download/v0.21.2/MonkeyLoader-v0.24.0+Resonite-v0.21.2+RML-v3.0.4.zip" + destination_dir="/data/resonite/Headless" + zip_file="$destination_dir/MonkeyLoader.zip" + + # Check if the zip file already exists + if [ ! -f "$zip_file" ]; then + echo "Downloading from $monkeyloader_url to $zip_file" + curl -L -o "$zip_file" "$monkeyloader_url" + else + echo "File already exists: $zip_file, skipping download." + fi + + if [ ! -f "/data/resonite/Headless/run_monkeyloader.sh" ]; then + # Extract the zip file + echo "Extracting $zip_file to $destination_dir" + unzip -o "$zip_file" -d "$destination_dir" + + # Clean up zip-specific structure (move contents correctly if necessary) + if [ -d "$destination_dir/zipfiles" ]; then + echo "Moving extracted contents to $destination_dir" + mv "$destination_dir/zipfiles/"* "$destination_dir" + rmdir "$destination_dir/zipfiles" + fi + fi + + if [ -f "$destination_dir/MonkeyLoader/GamePacks/MonkeyLoader.GamePacks.Resonite.Unity.nupkg" ]; then + rm "$destination_dir/MonkeyLoader/GamePacks/MonkeyLoader.GamePacks.Resonite.Unity.nupkg" + fi + if [ -f "$destination_dir/MonkeyLoader/GamePacks/MonkeyLoader.GamePacks.Unity.nupkg" ]; then + rm "$destination_dir/MonkeyLoader/GamePacks/MonkeyLoader.GamePacks.Unity.nupkg" + fi + + echo "MonkeyLoader setup complete." else - echo "Modloader is disabled" -fi \ No newline at end of file + echo "MonkeyLoader Disabled" + + # Remove MonkeyLoader directory and run_monkeyloader.sh script if they exist + if [ -d "/data/resonite/Headless/MonkeyLoader" ]; then + echo "Removing MonkeyLoader directory" + rm -rf "/data/resonite/Headless/MonkeyLoader" + fi + + if [ -f "/data/resonite/Headless/run_monkeyloader.sh" ]; then + echo "Removing run_monkeyloader.sh script" + rm -f "/data/resonite/Headless/run_monkeyloader.sh" + fi +fi diff --git a/scripts/03_download_mods.sh b/scripts/03_download_mods.sh index 3bb56b1..be78cc6 100755 --- a/scripts/03_download_mods.sh +++ b/scripts/03_download_mods.sh @@ -7,12 +7,6 @@ # want to use simply because google made it... # shell scripts are typically known by docker hosters so... -# Define file URLs and their associated positions -file_urls=( - "https://github.com/resonite-modding-group/ResoniteModLoader/releases/latest/download/ResoniteModLoader.dll /data/resonite/Headless/Libraries/ResoniteModLoader.dll" - "https://github.com/resonite-modding-group/ResoniteModLoader/releases/latest/download/0Harmony.dll /data/resonite/Headless/rml_libs/0Harmony.dll" -) - # Function to download a file from URL to destination download_file() { local url="$1" @@ -28,30 +22,33 @@ download_file() { fi } -# Loop through each file URL and download -for file_url in "${file_urls[@]}"; do - read -r url destination <<< "$file_url" - # Backup existing file if exists - if [ -f "$destination" ]; then - mv "$destination" "${destination}.bak" - fi - # Download file - download_file "$url" "$destination" -done - # Download additional files from a list of URLs to /data/resonite/Headless/rml_mods # shellcheck disable=SC2153 -for url in $MOD_URLS ; do - destination="/data/resonite/Headless/rml_mods/$(basename "$url")" +for url in $MOD_URLS; do + modname=$(basename "$url") + destination="" + + # Determine the destination based on the file extension + if [[ "$modname" == *.dll ]]; then + destination="/data/resonite/Headless/rml_mods/$modname" + elif [[ "$modname" == *.nupkg ]]; then + destination="/data/resonite/Headless/MonkeyLoader/Mods/$modname" + else + echo "Unknown file type for $modname, skipping." + continue + fi + # Check if file already exists, if yes, skip download if [ ! -f "$destination" ]; then echo "Downloading mod: $url" download_file "$url" "$destination" + else + echo "File already exists: $destination, skipping download." fi done # if resonte mod loader is enabled, create and link rml_mods, libs, and config -if [ "$RESONITE_MOD_LOADER" == "true" ]; then +if [ "$MONKEY_LOADER" == "true" ]; then for dir in rml_mods rml_libs rml_config; do if [ -d "/data/resonite/Headless/$dir" ]; then continue @@ -59,8 +56,4 @@ if [ "$RESONITE_MOD_LOADER" == "true" ]; then mkdir -p "/data/resonite/Headless/$dir" ln -s "./Headless/$dir" "./$dir" done - if [ ! -f "/data/resonite/Libraries/ResoniteModLoader.dll" ]; then - mkdir -p "/data/resonite/Libraries" - ln -s "/data/resonite/Headless/Libraries/ResoniteModLoader.dll" "/data/resonite/Libraries/ResoniteModLoader.dll" - fi fi \ No newline at end of file diff --git a/scripts/99_start.sh b/scripts/99_start.sh index a7eeab5..238fe84 100755 --- a/scripts/99_start.sh +++ b/scripts/99_start.sh @@ -1,11 +1,21 @@ #!/bin/bash +cd /data/resonite/Headless || exit + if [ "$STOP_LAUNCH" == "true" ]; then echo "STOP_LAUNCH is set to true, exiting..." exit 0 fi -cd /data/resonite/Headless || exit + echo "Running Resonite" -echo "exec: dotnet Resonite.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS" -dotnet Resonite.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS +if [ "$MONKEY_LOADER" == "true" ]; then + echo "exec: dotnet /app/Loader.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS" + # dotnet Resonite.dll -LoadAssembly MonkeyLoader/MonkeyLoader.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS + # bash run_monkeyloader.sh $DEFAULT_RESONITE_ARGS $RESONITE_ARGS + dotnet /app/Loader.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS + +else + echo "exec: dotnet Resonite.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS" + dotnet Resonite.dll $DEFAULT_RESONITE_ARGS $RESONITE_ARGS +fi \ No newline at end of file From 402c38642947b7dd64034d719962417125102947 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Tue, 7 Jan 2025 19:51:36 +0000 Subject: [PATCH 2/3] net9 harmony --- docker-compose.yml | 5 +++-- scripts/03_download_mods.sh | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 481997d..b97e11f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: ## These have their defualts set in the Dockerfile, and are safe to remove from this file # Prevents SteamCMD from updating the gamefiles - DISABLE_STEAMCMD: "false" + DISABLE_STEAMCMD: false # Where to located the config file, defaults to /data/Config.json # if config file does not exist, it will generate a template one at that location @@ -39,7 +39,8 @@ services: # list of mods to load, MOD_URLS: | - https://github.com/New-Project-Final-Final-WIP/HeadlessTweaks/releases/latest/download/HeadlessTweaks.dll + https://github.com/Raidriar796/StresslessHeadless/releases/download/2.0.0-rc1/StresslessHeadless.dll + # https://github.com/New-Project-Final-Final-WIP/HeadlessTweaks/releases/latest/download/HeadlessTweaks.dll # Controls the UID:GID of the headless, defaults to `root` if not set RUN_AS: 1000 diff --git a/scripts/03_download_mods.sh b/scripts/03_download_mods.sh index 3bb56b1..9087bf3 100755 --- a/scripts/03_download_mods.sh +++ b/scripts/03_download_mods.sh @@ -10,7 +10,9 @@ # Define file URLs and their associated positions file_urls=( "https://github.com/resonite-modding-group/ResoniteModLoader/releases/latest/download/ResoniteModLoader.dll /data/resonite/Headless/Libraries/ResoniteModLoader.dll" - "https://github.com/resonite-modding-group/ResoniteModLoader/releases/latest/download/0Harmony.dll /data/resonite/Headless/rml_libs/0Harmony.dll" + # "https://github.com/resonite-modding-group/ResoniteModLoader/releases/latest/download/0Harmony.dll /data/resonite/Headless/rml_libs/0Harmony.dll" + # net9 Harmony + "https://github.com/stiefeljackal/pardeike.Harmony/releases/download/temp-release/0Harmony.dll /data/resonite/Headless/rml_libs/0Harmony.dll" ) # Function to download a file from URL to destination From df234baeab8619eb02e5c1904ca2a11faf45c9c5 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Fri, 18 Jul 2025 18:46:05 -0700 Subject: [PATCH 3/3] fix the fucking readme --- Readme.md | 98 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 20 deletions(-) diff --git a/Readme.md b/Readme.md index 2904b26..2e110c4 100644 --- a/Readme.md +++ b/Readme.md @@ -1,35 +1,93 @@ -# README for Docker Image Build and Publish Workflows + +# Resonite Headless Docker Image & CI Workflows ## Overview -This repository contains two GitHub Actions workflows that automate the building and publishing of Docker images to an OCI registry. +This repository provides a Docker image and automation scripts for running [Resonite Headless](https://resonite.com/) in a containerized environment. It includes: -### Workflows +- Dockerfile and Docker Compose setup +- Scripts for installation, configuration, and mod management +- CI workflows for automated image builds and publishing -1. **On Commit to Main** - - **Trigger:** Activates on commits to the `main` branch (tags are excluded). - - **Purpose:** Builds and publishes a Docker image for each commit. -2. **On Tag Push** - - **Trigger:** Activates when a new tag is pushed. - - **Purpose:** Builds and publishes a Docker image for the tag and tags it as `latest`. +## Quick Start -## Prerequisites +1. **Create or edit your `docker-compose.yml`:** -- **Secrets Needed:** - - `OCI_TOKEN`: Your OCI registry token. - - `OCI_USER`: Your OCI registry username. + Example: + ```yaml + services: + resonite: + image: git.merith.xyz/oci/resonite:nightly + container_name: resonite + network_mode: host # dont actually know what ports resonite needs + stdin_open: true + tty: true + volumes: + - ./data:/data:rw + - ./data/resonite:/data/resonite:rw + - ./data/steamcmd:/data/steamcmd:rw + - ./scripts:/scripts:ro ## Optional if you need an override for one of the scripts + environment: + DISABLE_STEAMCMD: false + CONFIG_FILE: "/data/Config.json" + COMMAND: "/scripts/99_start.sh" + RESONITE_MOD_LOADER: true + MOD_URLS: | + https://github.com/Raidriar796/StresslessHeadless/releases/download/2.0.0-rc1/StresslessHeadless.dll + RUN_AS: 1000 + STOP_LAUNCH: false + env_file: + - ./steamcred.env + ``` -## How to Use +2. **Configure environment variables:** + - Copy `steamcred.env` and fill in your Steam credentials (`STEAM_USER`, `STEAM_PASS`, `STEAM_AUTH`, `STEAM_BETA`). + - Edit `docker-compose.yml` to adjust options as needed (see above). -1. **Clone the Repository:** Get a local copy of this repository. -2. **Modify Dockerfile:** Update the `Dockerfile` for your application. -3. **Push Changes:** Push changes to the `main` branch or create a new tag. -4. **Check Workflow Status:** View the Actions tab in Forgjo to monitor workflow runs. +3. **Start the container:** + ```sh + docker-compose up -d + ``` -## Notes +## Quick Reference -- Ensure your Docker environment is compatible with multi-platform builds if necessary. +- **Docker image:** `git.merith.xyz/oci/resonite:nightly` +- **Repository:** https://git.merith.xyz/oci/resonite +- **Default compose file:** See example above or use the provided `docker-compose.yml`. + +## Configuration + +### Environment Variables (in `docker-compose.yml`) + +- `DISABLE_STEAMCMD`: Prevents SteamCMD from updating game files (default: false) +- `CONFIG_FILE`: Path to config file (default: `/data/Config.json`) +- `COMMAND`: Startup script (default: `/scripts/99_start.sh`) +- `RESONITE_MOD_LOADER`: Enable Resonite Mod Loader (default: false) +- `MOD_URLS`: List of mod URLs to download +- `RUN_AS`: UID:GID to run the server as (default: root) +- `STOP_LAUNCH`: If true, prevents server from starting (for debugging) + +### Steam Credentials +Set in `steamcred.env` (not tracked in git): +- `STEAM_USER`, `STEAM_PASS`, `STEAM_AUTH`, `STEAM_BETA` + +### Volumes +- `/data`: Persistent data +- `/data/resonite`: Game files +- `/data/steamcmd`: SteamCMD files + +## Scripts + +- `00_setup.sh`: Main entrypoint, sets up environment and runs install/config/mod scripts +- `01_install.sh`: Installs Resonite Headless via SteamCMD +- `02_setup_config.sh`: Sets up configuration file from template if missing +- `03_download_mods.sh`: Downloads mods and sets up mod loader if enabled +- `99_start.sh`: Starts the Resonite server + +## Mod Support + +To enable mod support, set `RESONITE_MOD_LOADER: true` and provide mod URLs in `MOD_URLS`. The scripts will download and link mods automatically. ## License