generated from oci/template
Compare commits
1 commit
main
...
monkeyload
Author | SHA1 | Date | |
---|---|---|---|
d79288f11d |
9 changed files with 206 additions and 126 deletions
|
@ -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
|
||||
docker rmi $REPO_HOST/$REPO_PATH:$TAG
|
10
Dockerfile
10
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"]
|
||||
|
||||
|
|
98
Readme.md
98
Readme.md
|
@ -1,93 +1,35 @@
|
|||
|
||||
# Resonite Headless Docker Image & CI Workflows
|
||||
# README for Docker Image Build and Publish Workflows
|
||||
|
||||
## Overview
|
||||
|
||||
This repository provides a Docker image and automation scripts for running [Resonite Headless](https://resonite.com/) in a containerized environment. It includes:
|
||||
This repository contains two GitHub Actions workflows that automate the building and publishing of Docker images to an OCI registry.
|
||||
|
||||
- Dockerfile and Docker Compose setup
|
||||
- Scripts for installation, configuration, and mod management
|
||||
- CI workflows for automated image builds and publishing
|
||||
### Workflows
|
||||
|
||||
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.
|
||||
|
||||
## Quick Start
|
||||
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`.
|
||||
|
||||
1. **Create or edit your `docker-compose.yml`:**
|
||||
## Prerequisites
|
||||
|
||||
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
|
||||
```
|
||||
- **Secrets Needed:**
|
||||
- `OCI_TOKEN`: Your OCI registry token.
|
||||
- `OCI_USER`: Your OCI registry username.
|
||||
|
||||
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).
|
||||
## How to Use
|
||||
|
||||
3. **Start the container:**
|
||||
```sh
|
||||
docker-compose up -d
|
||||
```
|
||||
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.
|
||||
|
||||
## Quick Reference
|
||||
## Notes
|
||||
|
||||
- **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.
|
||||
- Ensure your Docker environment is compatible with multi-platform builds if necessary.
|
||||
|
||||
## License
|
||||
|
||||
|
|
76
defaults/loader/Loader.cs
Normal file
76
defaults/loader/Loader.cs
Normal file
|
@ -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
|
||||
}
|
11
defaults/loader/Loader.csproj
Normal file
11
defaults/loader/Loader.csproj
Normal file
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -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
|
||||
|
@ -25,7 +23,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
|
||||
|
@ -35,11 +33,12 @@ 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/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
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
|
@ -7,14 +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"
|
||||
# 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
|
||||
download_file() {
|
||||
local url="$1"
|
||||
|
@ -30,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
|
||||
|
@ -61,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
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue