From 42988efe20b8b592a8bf94b237b1aeac1095211f Mon Sep 17 00:00:00 2001
From: Jamesssssssssssssss
<87044058+Jamesssssssssssssss@users.noreply.github.com>
Date: Sun, 11 Jan 2026 16:14:11 +0000
Subject: [PATCH] Release mod GitHub Action and optimise crowdin + discord
(#463)
* release workflow
* update release workflow
* remove changelog input entirely
* dotnet 6.0
* create test version without crowdin
* give test name...
* fix file paths
* enable windows targeting to build on linux?
* copy CustomRoles.cs to CTA before build
* copy from the right folder...
* rename challenger to solopvp_player
* temporary customroles fix
* fix bepinex link
* remove packaging, fix download links, finito?
* i am so silly
* bro cannot read
* sure, this'll work
* surely this one
* attempt to cache bepinex
* ... actually rename solopvp_player to challenger
* optimisations
* less steps hopefully fixing permission problems
* will a trailing slash solve my problems
* a few dots for good measure
* why am i making this so difficult
* remove added line
* split things up more to do msbuild on windows
* why does it keep changing the paths
* restore nuget packages
* CORRECT PATHS
* use dotnet instead of nuget cope
* apparently that checkout was quite important
* add runtime identifier back
* fix name
* rename control panel
* actually use nuget??
* .NEt again D:
* remove imaginary line
* test
* IT BUILT
* cds nuts
* remove this line again for testing
* final path change
* changelog output
* please find my exe
* fix backticks
* final final path change
* make the build dir?
* new changelog
* fix string parsing
* better changelog
* lol
* enable crowdin action
* rename challenger to solopvp_player
* ... actually rename solopvp_player to challenger
* optimisations
* less steps hopefully fixing permission problems
* will a trailing slash solve my problems
* a few dots for good measure
* why am i making this so difficult
* remove added line
* split things up more to do msbuild on windows
* why does it keep changing the paths
* restore nuget packages
* CORRECT PATHS
* use dotnet instead of nuget cope
* apparently that checkout was quite important
* add runtime identifier back
* fix name
* rename control panel
* actually use nuget??
* .NEt again D:
* remove imaginary line
* test
* IT BUILT
* cds nuts
* remove this line again for testing
* final path change
* changelog output
* please find my exe
* fix backticks
* final final path change
* make the build dir?
* new changelog
* fix string parsing
* better changelog
* lol
* enable crowdin action
* cleanup
* build with .NET 6, use bepinex pre-release 735, add configs
* disable crowdin temporarily
* checkout for packaging
* make config dir
* woohoo! uncommenting crowdin
---
.github/workflows/discord_webhook_filter.yml | 189 ----------------
.github/workflows/post_modnews.yml | 27 ---
.github/workflows/release.yml | 207 ++++++++++++++++++
CHANGELOG.md | 3 +
.../CustomTeamAssigner.csproj | 1 +
packaging/BepInEx.cfg | 194 ++++++++++++++++
packaging/at.duikbo.regioninstall.cfg | 15 ++
7 files changed, 420 insertions(+), 216 deletions(-)
delete mode 100644 .github/workflows/discord_webhook_filter.yml
delete mode 100644 .github/workflows/post_modnews.yml
create mode 100644 .github/workflows/release.yml
create mode 100644 CHANGELOG.md
create mode 100644 packaging/BepInEx.cfg
create mode 100644 packaging/at.duikbo.regioninstall.cfg
diff --git a/.github/workflows/discord_webhook_filter.yml b/.github/workflows/discord_webhook_filter.yml
deleted file mode 100644
index d29665f26..000000000
--- a/.github/workflows/discord_webhook_filter.yml
+++ /dev/null
@@ -1,189 +0,0 @@
-name: Discord Webhook Filter
-
-on:
- pull_request:
- types: [opened, synchronize, reopened, closed, ready_for_review]
- branches: [ main ]
- pull_request_review:
- types: [submitted]
- workflow_run:
- workflows: ["Build"]
- types: [completed]
- push:
- branches: [ main ]
-
-jobs:
- notify:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check if notification should be sent
- id: filter
- run: |
- SHOULD_NOTIFY="true"
-
- # Check if this is the source file update commit we want to see
- IS_SOURCE_UPDATE="false"
- if [[ "${{ github.event_name }}" == "push" ]] || [[ "${{ github.event_name }}" == "pull_request" ]]; then
- COMMIT_MSG="${{ github.event.head_commit.message || github.event.pull_request.title }}"
- if echo "${COMMIT_MSG}" | grep -q "Update source file en_US.json"; then
- IS_SOURCE_UPDATE="true"
- echo "Allowing: Source file update detected"
- fi
- fi
-
- # Skip translation branch activity UNLESS it's the source file update
- if [[ "${{ github.head_ref }}" == "translation" ]] || [[ "${{ github.ref }}" == "refs/heads/translation" ]]; then
- if [[ "${IS_SOURCE_UPDATE}" == "false" ]]; then
- echo "Skipping: Translation branch activity (not source file update)"
- SHOULD_NOTIFY="false"
- fi
- fi
-
- # For workflow_run events from translation branch, always skip (these are the "checks skipped" messages)
- if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
- if [[ "${{ github.event.workflow_run.head_branch }}" == "translation" ]]; then
- echo "Skipping: Workflow run on translation branch"
- SHOULD_NOTIFY="false"
- fi
- fi
-
- echo "should_notify=${SHOULD_NOTIFY}" >> $GITHUB_OUTPUT
-
- - name: Send Discord notification
- if: steps.filter.outputs.should_notify == 'true'
- env:
- DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL }}
- run: |
- # Prepare notification based on event type
- case "${{ github.event_name }}" in
- pull_request)
- PR_NUM="${{ github.event.pull_request.number }}"
- PR_TITLE="${{ github.event.pull_request.title }}"
- PR_USER="${{ github.event.pull_request.user.login }}"
- PR_URL="${{ github.event.pull_request.html_url }}"
-
- case "${{ github.event.action }}" in
- opened)
- TITLE="New Pull Request"
- COLOR="3447003"
- DESCRIPTION="**${PR_TITLE}**\n\n${PR_USER} opened [PR #${PR_NUM}](${PR_URL})"
- ;;
- closed)
- if [[ "${{ github.event.pull_request.merged }}" == "true" ]]; then
- TITLE="Pull Request Merged"
- COLOR="5763719"
- DESCRIPTION="**${PR_TITLE}**\n\n[PR #${PR_NUM}](${PR_URL}) was merged into main"
- else
- TITLE="Pull Request Closed"
- COLOR="15158332"
- DESCRIPTION="**${PR_TITLE}**\n\n[PR #${PR_NUM}](${PR_URL}) was closed without merging"
- fi
- ;;
- synchronize)
- TITLE="Pull Request Updated"
- COLOR="16776960"
- DESCRIPTION="**${PR_TITLE}**\n\nNew commits pushed to [PR #${PR_NUM}](${PR_URL})"
- ;;
- ready_for_review)
- TITLE="Pull Request Ready for Review"
- COLOR="16776960"
- DESCRIPTION="**${PR_TITLE}**\n\n[PR #${PR_NUM}](${PR_URL}) is ready for review"
- ;;
- reopened)
- TITLE="Pull Request Reopened"
- COLOR="16776960"
- DESCRIPTION="**${PR_TITLE}**\n\n[PR #${PR_NUM}](${PR_URL}) was reopened"
- ;;
- esac
- URL="${PR_URL}"
- ;;
-
- workflow_run)
- WORKFLOW_NAME="${{ github.event.workflow_run.name }}"
- WORKFLOW_CONCLUSION="${{ github.event.workflow_run.conclusion }}"
- WORKFLOW_BRANCH="${{ github.event.workflow_run.head_branch }}"
- WORKFLOW_URL="${{ github.event.workflow_run.html_url }}"
-
- if [[ "${WORKFLOW_CONCLUSION}" == "success" ]]; then
- TITLE="${WORKFLOW_NAME} Successful"
- COLOR="5763719"
- DESCRIPTION="Branch: \`${WORKFLOW_BRANCH}\`\n\n[View workflow run](${WORKFLOW_URL})"
- elif [[ "${WORKFLOW_CONCLUSION}" == "failure" ]]; then
- TITLE="${WORKFLOW_NAME} Failed"
- COLOR="15158332"
- DESCRIPTION="Branch: \`${WORKFLOW_BRANCH}\`\n\n[View workflow run](${WORKFLOW_URL})"
- else
- TITLE="${WORKFLOW_NAME} ${WORKFLOW_CONCLUSION}"
- COLOR="16776960"
- DESCRIPTION="Branch: \`${WORKFLOW_BRANCH}\`\n\n[View workflow run](${WORKFLOW_URL})"
- fi
- URL="${WORKFLOW_URL}"
- ;;
-
- pull_request_review)
- REVIEW_USER="${{ github.event.review.user.login }}"
- REVIEW_STATE="${{ github.event.review.state }}"
- PR_NUM="${{ github.event.pull_request.number }}"
- PR_TITLE="${{ github.event.pull_request.title }}"
- REVIEW_URL="${{ github.event.review.html_url }}"
-
- case "${REVIEW_STATE}" in
- approved)
- TITLE="Pull Request Approved"
- COLOR="5763719"
- ;;
- changes_requested)
- TITLE="Changes Requested"
- COLOR="16776960"
- ;;
- commented)
- TITLE="Review Comment"
- COLOR="3447003"
- ;;
- esac
- DESCRIPTION="**${PR_TITLE}**\n\n${REVIEW_USER} reviewed [PR #${PR_NUM}](${REVIEW_URL})"
- URL="${REVIEW_URL}"
- ;;
-
- push)
- PUSHER="${{ github.event.pusher.name }}"
- COMMIT_MSG="${{ github.event.head_commit.message }}"
- COMMIT_URL="${{ github.event.head_commit.url }}"
- BRANCH="${{ github.ref_name }}"
-
- TITLE="Push to ${BRANCH}"
- COLOR="3447003"
- # Truncate commit message if too long
- SHORT_MSG=$(echo "${COMMIT_MSG}" | head -n 1 | cut -c1-100)
- DESCRIPTION="${PUSHER}: ${SHORT_MSG}\n\n[View commit](${COMMIT_URL})"
- URL="${COMMIT_URL}"
- ;;
- esac
-
- # Escape special characters for JSON
- TITLE=$(echo "${TITLE}" | sed 's/"/\\"/g')
- DESCRIPTION=$(echo "${DESCRIPTION}" | sed 's/"/\\"/g')
-
- # Send Discord webhook
- HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Content-Type: application/json" \
- -d "{
- \"embeds\": [{
- \"title\": \"${TITLE}\",
- \"description\": \"${DESCRIPTION}\",
- \"url\": \"${URL}\",
- \"color\": ${COLOR},
- \"footer\": {
- \"text\": \"${{ github.repository }}\"
- },
- \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)\"
- }]
- }" \
- "${DISCORD_WEBHOOK}")
-
- if [[ "${HTTP_STATUS}" -ge 200 ]] && [[ "${HTTP_STATUS}" -lt 300 ]]; then
- echo "Notification sent successfully (HTTP ${HTTP_STATUS})"
- else
- echo "Failed to send notification (HTTP ${HTTP_STATUS})"
- exit 1
- fi
diff --git a/.github/workflows/post_modnews.yml b/.github/workflows/post_modnews.yml
deleted file mode 100644
index 178c9088b..000000000
--- a/.github/workflows/post_modnews.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Post ModNews on Release
-
-on:
- release:
- types: [published]
-
-jobs:
- send-mod-news:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repo
- uses: actions/checkout@v3
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: 3.x
-
- - name: Install dependencies
- run: pip install requests markdown
-
- - name: Run script and send ModNews
- env:
- MODNEWS_API_URL: ${{ secrets.MODNEWS_API_URL }}
- MODNEWS_API_TOKEN: ${{ secrets.MODNEWS_API_TOKEN }}
- run: python release_to_modnews.py
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..662ebbec0
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,207 @@
+name: Build & Release EHR
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: "Version (e.g. 7.0.2)"
+ required: true
+
+jobs:
+ prepare-build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Sync translations from Crowdin
+ uses: crowdin/github-action@v2
+ with:
+ upload_sources: false
+ download_translations: true
+ config: crowdin.yml
+ push_translations: true
+ commit_message: "chore: update translations for release ${{ github.event.inputs.version }}"
+ env:
+ CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # ---------------------------------------------------------
+ # 1) Build EHR on Linux
+ # ---------------------------------------------------------
+ build-ehr:
+ runs-on: ubuntu-latest
+ needs: [prepare-build]
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 6.0.x
+
+ - name: Build EHR
+ run: dotnet build EHR.csproj -c Release -o build/
+
+ - name: Upload EHR artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ehr
+ path: build/EHR.dll
+
+ # ---------------------------------------------------------
+ # 2) Build Control Panel on Windows using MSBuild
+ # ---------------------------------------------------------
+ build-control-panel:
+ runs-on: windows-latest
+ needs: [prepare-build]
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 6.0.x
+
+ - name: Setup MSBuild
+ uses: microsoft/setup-msbuild@v2
+
+ - name: Restore .NET packages
+ run: dotnet restore -p:SelfContained=true CTA/CustomTeamAssigner/CustomTeamAssigner.csproj
+
+ - name: Build Control Panel (MSBuild)
+ run: |
+ msbuild CTA/CustomTeamAssigner/CustomTeamAssigner.csproj `
+ /p:Configuration=Release `
+ /p:Platform="x64" `
+ /p:PublishSingleFile=true `
+ /p:SelfContained=true `
+ /p:RuntimeIdentifier=win-x64 `
+ /p:IncludeAllContentForSelfExtract=true `
+ /p:DebugType=None `
+ /p:PublishDir=build\ `
+ /t:publish
+
+ - name: Rename exe file
+ run: |
+ mkdir build/
+ mv CTA/CustomTeamAssigner/build/CustomTeamAssigner.exe build/EHR_Control-Panel_BETA.exe
+
+ - name: Upload Control Panel artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: control-panel
+ path: build\EHR_Control-Panel_BETA.exe
+
+ # ---------------------------------------------------------
+ # 3) Package everything on Linux
+ # ---------------------------------------------------------
+ package:
+ runs-on: ubuntu-latest
+ needs: [build-ehr, build-control-panel]
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Download EHR artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: ehr
+ path: artifacts/ehr
+
+ - name: Prepare release folder
+ run: mkdir -p release
+
+ - name: Download BepInEx 6 pre-release 735
+ run: |
+ curl -L https://builds.bepinex.dev/projects/bepinex_be/735/BepInEx-Unity.IL2CPP-win-x64-6.0.0-be.735%2B5fef357.zip -o bepinex.zip
+ unzip bepinex.zip -d release
+ chmod -R u+rwX,go+rX release
+
+ - name: Copy EHR dll to plugins
+ run: cp artifacts/ehr/EHR.dll release/BepInEx/plugins/
+
+ - name: Copy configs to BepInEx config
+ run: |
+ mkdir -p release/BepInEx/config/
+ cp packaging/* release/BepInEx/config/
+
+ - name: Download modded regions DLL to plugins
+ run: curl -L https://github.com/miniduikboot/Mini.RegionInstall/releases/download/v1.2.0/Mini.RegionInstall.dll -o release/BepInEx/plugins/Mini.RegionInstall.dll
+
+ - name: Create Epic/MS Store ZIP
+ run: |
+ cd release
+ zip -r "../EHR.v${{ github.event.inputs.version }}_Epic-Games_Microsoft-Store.zip" .
+
+ - name: Create Steam ZIP
+ run: |
+ echo "945360" > steam_appid.txt
+ zip -r "EHR.v${{ github.event.inputs.version }}_Steam.zip" .
+
+ - name: Upload release artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: final-zips
+ path: ./EHR*.zip
+
+ # ---------------------------------------------------------
+ # 4) Create GitHub Release
+ # ---------------------------------------------------------
+ release:
+ runs-on: ubuntu-latest
+ needs: [package]
+
+ steps:
+ - uses: actions/checkout@v4
+
+ # -----------------------------
+ # Download all artifacts
+ # -----------------------------
+ - name: Download packaged ZIPs
+ uses: actions/download-artifact@v4
+ with:
+ name: final-zips
+ path: release-artifacts/zips
+
+ - name: Download EHR.dll
+ uses: actions/download-artifact@v4
+ with:
+ name: ehr
+ path: release-artifacts/ehr
+
+ - name: Download Control Panel EXE
+ uses: actions/download-artifact@v4
+ with:
+ name: control-panel
+ path: release-artifacts/control-panel
+
+ # -----------------------------
+ # Create GitHub Release
+ # -----------------------------
+ - name: Create Release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: "v${{ github.event.inputs.version }}"
+ name: "EHR v${{ github.event.inputs.version }}"
+ generate_release_notes: true
+ body: ${cat CHANGELOG.md}
+ files: |
+ release-artifacts/zips/*
+ release-artifacts/ehr/EHR.dll
+ release-artifacts/control-panel/*.exe
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # -----------------------------
+ # Send Mod News
+ # -----------------------------
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.x
+
+ - name: Install dependencies
+ run: pip install requests markdown
+
+ - name: Run script and send ModNews
+ env:
+ MODNEWS_API_URL: ${{ secrets.MODNEWS_API_URL }}
+ MODNEWS_API_TOKEN: ${{ secrets.MODNEWS_API_TOKEN }}
+ run: python release_to_modnews.py
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..b2b78a831
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+### Roles
+
+- Added Empress (new Coven role)
\ No newline at end of file
diff --git a/CTA/CustomTeamAssigner/CustomTeamAssigner.csproj b/CTA/CustomTeamAssigner/CustomTeamAssigner.csproj
index 83c1116f8..16f505290 100644
--- a/CTA/CustomTeamAssigner/CustomTeamAssigner.csproj
+++ b/CTA/CustomTeamAssigner/CustomTeamAssigner.csproj
@@ -6,6 +6,7 @@
enable
enable
true
+ true
diff --git a/packaging/BepInEx.cfg b/packaging/BepInEx.cfg
new file mode 100644
index 000000000..ba5711eb2
--- /dev/null
+++ b/packaging/BepInEx.cfg
@@ -0,0 +1,194 @@
+[Caching]
+
+## Enable/disable assembly metadata cache
+## Enabling this will speed up discovery of plugins and patchers by caching the metadata of all types BepInEx discovers.
+# Setting type: Boolean
+# Default value: true
+EnableAssemblyCache = true
+
+[Detours]
+
+## The native provider to use for managed detours
+# Setting type: DetourProvider
+# Default value: Default
+# Acceptable values: Default, Dobby, Funchook
+DetourProviderType = Default
+
+[Harmony.Logger]
+
+## Specifies which Harmony log channels to listen to.
+## NOTE: IL channel dumps the whole patch methods, use only when needed!
+# Setting type: LogChannel
+# Default value: Warn, Error
+# Acceptable values: None, Info, IL, Warn, Error, Debug, All
+# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)
+LogChannels = Warn, Error
+
+[IL2CPP]
+
+## Whether to run Il2CppInterop automatically to generate Il2Cpp support assemblies when they are outdated.
+## If disabled assemblies in `BepInEx/interop` won't be updated between game or BepInEx updates!
+##
+# Setting type: Boolean
+# Default value: true
+UpdateInteropAssemblies = true
+
+## URL to the ZIP of managed Unity base libraries.
+## The base libraries are used by Il2CppInterop to generate interop assemblies.
+## The URL can include {VERSION} template which will be replaced with the game's Unity engine version.
+##
+# Setting type: String
+# Default value: https://unity.bepinex.dev/libraries/{VERSION}.zip
+UnityBaseLibrariesSource = https://unity.bepinex.dev/libraries/{VERSION}.zip
+
+## The RegEx string to pass to Il2CppAssemblyUnhollower for renaming obfuscated names.
+## All types and members matching this RegEx will get a name based on their signature,
+## resulting in names that persist after game updates.
+##
+# Setting type: String
+# Default value:
+UnhollowerDeobfuscationRegex =
+
+## If enabled, Il2CppInterop will use xref to find dead methods and generate CallerCount attributes.
+# Setting type: Boolean
+# Default value: true
+ScanMethodRefs = false
+
+## If enabled, BepInEx will save dummy assemblies generated by an Cpp2IL dumper into BepInEx/dummy.
+# Setting type: Boolean
+# Default value: false
+DumpDummyAssemblies = false
+
+## The path to the folder where IL2CPPInterop assemblies are stored.
+## Supports the following placeholders:
+## {BepInEx} - Path to the BepInEx folder.
+## {ProcessName} - Name of the current process
+##
+# Setting type: String
+# Default value: {BepInEx}
+IL2CPPInteropAssembliesPath = {BepInEx}
+
+## Automatically load all interop assemblies right before loading plugins.
+## Some plugins may not work properly without this, but it may cause issues in some games.
+##
+# Setting type: Boolean
+# Default value: true
+PreloadIL2CPPInteropAssemblies = true
+
+## The path to the IL2CPP metadata file.
+## Supports the following placeholders:
+## {BepInEx} - Path to the BepInEx folder.
+## {ProcessName} - Name of the current process
+## {GameDataPath} - Path to the game's Data folder.
+##
+# Setting type: String
+# Default value: {GameDataPath}/il2cpp_data/Metadata/global-metadata.dat
+GlobalMetadataPath = {GameDataPath}/il2cpp_data/Metadata/global-metadata.dat
+
+[Logging]
+
+## Enables showing unity log messages in the BepInEx logging system.
+# Setting type: Boolean
+# Default value: true
+UnityLogListening = true
+
+[Logging.Console]
+
+## Enables showing a console for log output.
+# Setting type: Boolean
+# Default value: true
+Enabled = true
+
+## If enabled, will prevent closing the console (either by deleting the close button or in other platform-specific way).
+# Setting type: Boolean
+# Default value: false
+PreventClose = false
+
+## If true, console is set to the Shift-JIS encoding, otherwise UTF-8 encoding.
+# Setting type: Boolean
+# Default value: false
+ShiftJisEncoding = false
+
+## Hints console manager on what handle to assign as StandardOut. Possible values:
+## Auto - lets BepInEx decide how to redirect console output
+## ConsoleOut - prefer redirecting to console output; if possible, closes original standard output
+## StandardOut - prefer redirecting to standard output; if possible, closes console out
+##
+# Setting type: ConsoleOutRedirectType
+# Default value: Auto
+# Acceptable values: Auto, ConsoleOut, StandardOut
+StandardOutType = Auto
+
+## Which log levels to show in the console output.
+# Setting type: LogLevel
+# Default value: Fatal, Error, Warning, Message, Info
+# Acceptable values: None, Fatal, Error, Warning, Message, Info, Debug, All
+# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)
+LogLevels = Fatal, Error, Warning, Message, Info
+
+[Logging.Disk]
+
+## Appends to the log file instead of overwriting, on game startup.
+# Setting type: Boolean
+# Default value: false
+AppendLog = false
+
+## Enables writing log messages to disk.
+# Setting type: Boolean
+# Default value: true
+Enabled = true
+
+## Only displays the specified log levels in the disk log output.
+# Setting type: LogLevel
+# Default value: Fatal, Error, Warning, Message, Info
+# Acceptable values: None, Fatal, Error, Warning, Message, Info, Debug, All
+# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)
+LogLevels = Fatal, Error, Warning, Message, Info
+
+## If true, instantly writes any received log entries to disk.
+## This incurs a major performance hit if a lot of log messages are being written, however it is really useful for debugging crashes.
+##
+# Setting type: Boolean
+# Default value: false
+InstantFlushing = false
+
+## The maximum amount of concurrent log files that will be written to disk.
+## As one log file is used per open game instance, you may find it necessary to increase this limit when debugging multiple instances at the same time.
+##
+# Setting type: Int32
+# Default value: 5
+ConcurrentFileLimit = 5
+
+## Include unity log messages in log file output.
+# Setting type: Boolean
+# Default value: false
+WriteUnityLog = false
+
+[Preloader]
+
+## Specifies which MonoMod backend to use for Harmony patches. Auto uses the best available backend.
+## This setting should only be used for development purposes (e.g. debugging in dnSpy). Other code might override this setting.
+# Setting type: MonoModBackend
+# Default value: auto
+# Acceptable values: auto, dynamicmethod, methodbuilder, cecil
+HarmonyBackend = auto
+
+## If enabled, BepInEx will save patched assemblies into BepInEx/DumpedAssemblies.
+## This can be used by developers to inspect and debug preloader patchers.
+# Setting type: Boolean
+# Default value: false
+DumpAssemblies = false
+
+## If enabled, BepInEx will load patched assemblies from BepInEx/DumpedAssemblies instead of memory.
+## This can be used to be able to load patched assemblies into debuggers like dnSpy.
+## If set to true, will override DumpAssemblies.
+# Setting type: Boolean
+# Default value: false
+LoadDumpedAssemblies = false
+
+## If enabled, BepInEx will call Debugger.Break() once before loading patched assemblies.
+## This can be used with debuggers like dnSpy to install breakpoints into patched assemblies before they are loaded.
+# Setting type: Boolean
+# Default value: false
+BreakBeforeLoadAssemblies = false
+
diff --git a/packaging/at.duikbo.regioninstall.cfg b/packaging/at.duikbo.regioninstall.cfg
new file mode 100644
index 000000000..8e970a56b
--- /dev/null
+++ b/packaging/at.duikbo.regioninstall.cfg
@@ -0,0 +1,15 @@
+## Settings file was created by EHR
+## Plugin GUID: at.duikbo.regioninstall
+
+[General]
+
+## Create an array of regions you want to add/update. To create this array, go to https://impostor.github.io/Impostor/ and put the Regions array from the server file in here
+# Setting type: String
+# Default value: {\"CurrentRegionIdx\":0,\"Regions\":[]}
+Regions = { \"CurrentRegionIdx\": 2, \"Regions\": [ { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Niko-NA\", \"PingServer\": \"https://au-us.niko233.me\", \"Servers\": [ { \"Name\": \"http-1\", \"Ip\": \"https://au-us.niko233.me\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 }, { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Niko-AS\", \"PingServer\": \"https://au-as.niko233.me\", \"Servers\": [ { \"Name\": \"http-1\", \"Ip\": \"https://au-as.niko233.me\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 }, { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Niko-EU\", \"PingServer\": \"https://au-eu.niko233.me\", \"Servers\": [ { \"Name\": \"http-1\", \"Ip\": \"https://au-eu.niko233.me\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 }, { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Niko-CN\", \"PingServer\": \"play.simpfun.cn\", \"Servers\": [ { \"Name\": \"http-1\", \"Ip\": \"https://au-cn.niko233.me\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 }, { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Modded EU (MEU)\", \"PingServer\": \"https://au-eu.duikbo.at\", \"Servers\": [ { \"Name\": \"Http-1\", \"Ip\": \"https://au-eu.duikbo.at\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 }, { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Modded NA (MNA)\", \"PingServer\": \"https://aumods.org\", \"Servers\": [ { \"Name\": \"Http-1\", \"Ip\": \"https://aumods.org\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 }, { \"$type\": \"StaticHttpRegionInfo, Assembly-CSharp\", \"Name\": \"Modded Asia (MAS)\", \"PingServer\": \"https://au-as.duikbo.at\", \"Servers\": [ { \"Name\": \"Http-1\", \"Ip\": \"https://au-as.duikbo.at\", \"Port\": 443, \"UseDtls\": false, \"Players\": 0, \"ConnectionFailures\": 0 } ], \"TargetServer\": null, \"TranslateName\": 1003 } ] }
+
+## Comma-seperated list of region names that should be removed.
+# Setting type: String
+# Default value:
+RemoveRegions = Niko233(NA_US),Niko233(NA_US2),Niko233(AS_CN),Niko233(AS_CN2),NikoCat233(US),NikoCat233(CN),Niko233(AS3),Niko233(NA2),Niko233(EU2),Niko233(AS2),Custom,Niko233(NA),Niko233(EU),Niko233(AS),Niko233(CN),Modded SA (MSA)
+