ci: modernize workflow to .NET 9.0 and enable auto-prerelease

This commit is contained in:
Marvin
2026-04-14 19:01:59 +02:00
parent 675344e5b1
commit ee6a14d46f
6 changed files with 237 additions and 15 deletions
+22 -12
View File
@@ -9,18 +9,17 @@ on:
jobs:
build:
# Funktioniert auf GitHub (windows-latest) und Gitea Runners mit entsprechendem Label
runs-on: ${{ github.server_url == 'https://github.com' && 'windows-latest' || 'windows' }}
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore gregCore.csproj
@@ -28,18 +27,29 @@ jobs:
- name: Build gregCore
run: dotnet build gregCore.csproj -c Release -p:CI=true
- name: Package Release
if: startsWith(github.ref, 'refs/tags/v')
- name: Create Artifacts
shell: pwsh
run: |
./gregScripts/Build-Release.ps1
$outDir = "publish"
New-Item -ItemType Directory -Path $outDir -Force
Copy-Item "bin/Release/net6.0/gregCore.dll" $outDir/
if (Test-Path "bin/Release/net6.0/gregCore.pdb") { Copy-Item "bin/Release/net6.0/gregCore.pdb" $outDir/ }
# Zip it
Compress-Archive -Path "$outDir/*" -DestinationPath "$outDir/gregCore-v1.0.0.30-pre.zip"
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: gregCore-binaries
path: publish/*.dll
- name: Create Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main'
uses: softprops/action-gh-release@v2
with:
tag_name: latest
name: gregCore Latest Build
prerelease: true
files: publish/*.zip
body_path: CHANGELOG.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
using HarmonyLib;
using UnityEngine;
namespace greg.Harmony;
/// <summary>
/// Patches the Unity Application version to ensure it is correctly reported to MelonLoader and other mods,
/// as it is not properly configured in the game's Unity build.
/// </summary>
[HarmonyPatch(typeof(Application), "version", MethodType.Getter)]
public static class GregGameVersionPatch
{
private const string GameVersion = "1.0.45.5";
public static bool Prefix(ref string __result)
{
__result = GameVersion;
return false; // Skip the original getter
}
}
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MelonLoader;
using MelonLoader.Utils;
namespace greg.Core.Plugins;
/// <summary>
/// Utility for recursive dependency resolution across mod directories.
/// </summary>
public static class gregDependencyResolver
{
private static readonly HashSet<string> _foundAssemblies = new(StringComparer.OrdinalIgnoreCase);
private static bool _scanComplete;
private static readonly object _lock = new();
/// <summary>
/// Checks if the specified dependencies are present in the filesystem.
/// Supports deep recursive searching in StreamingAssets and standard Mods folder.
/// </summary>
/// <param name="logger">Logger for reporting missing dependencies.</param>
/// <param name="modName">Name of the mod requesting the check.</param>
/// <param name="required">List of required DLL filenames (without extension).</param>
/// <param name="optional">List of optional DLL filenames (without extension).</param>
/// <returns>True if all required dependencies are found; otherwise, false.</returns>
public static bool CheckDependencies(MelonLogger.Instance logger, string modName, string[] required, string[] optional = null)
{
EnsureScan(logger);
bool allMet = true;
var missingRequired = new List<string>();
if (required != null)
{
foreach (var req in required)
{
if (!_foundAssemblies.Contains(req))
{
allMet = false;
missingRequired.Add(req);
}
}
}
if (!allMet)
{
logger.Error($"[{modName}] CRITICAL: Missing required dependencies: {string.Join(", ", missingRequired)}");
logger.Error($"[{modName}] This mod will be disabled to prevent crashes.");
}
if (optional != null)
{
foreach (var opt in optional)
{
if (!_foundAssemblies.Contains(opt))
{
logger.Warning($"[{modName}] Optional dependency '{opt}' not found. Some features may be unavailable.");
}
}
}
return allMet;
}
private static void EnsureScan(MelonLogger.Instance logger)
{
lock (_lock)
{
if (_scanComplete) return;
var roots = new List<string>
{
MelonEnvironment.ModsDirectory,
Path.Combine(MelonEnvironment.GameRootDirectory, "Data Center_Data", "StreamingAssets", "mods")
};
foreach (var root in roots)
{
if (Directory.Exists(root))
{
ScanDirectoryRecursive(root, 0, 12);
}
}
_scanComplete = true;
logger.Msg($"[gregCore] Dependency scan complete. Found {_foundAssemblies.Count} unique assemblies in mods directories.");
}
}
private static void ScanDirectoryRecursive(string path, int currentDepth, int maxDepth)
{
if (currentDepth > maxDepth) return;
try
{
// Scan files in current directory
foreach (var file in Directory.GetFiles(path, "*.dll"))
{
var name = Path.GetFileNameWithoutExtension(file);
_foundAssemblies.Add(name);
}
// Recurse into subdirectories
foreach (var dir in Directory.GetDirectories(path))
{
ScanDirectoryRecursive(dir, currentDepth + 1, maxDepth);
}
}
catch
{
// Ignore access errors
}
}
}
+71
View File
@@ -0,0 +1,71 @@
using System;
using MelonLoader;
namespace greg.Core.Plugins;
/// <summary>
/// Unified base class for all gregCore ecosystem mods and plugins.
/// Handles automatic dependency resolution and lifecycle management.
/// </summary>
public abstract class gregModBase : MelonMod
{
/// <summary>
/// Gets the list of required assembly/DLL names (without extension).
/// If any are missing, the mod will not initialize.
/// </summary>
public virtual string[] RequiredDependencies => Array.Empty<string>();
/// <summary>
/// Gets the list of optional assembly/DLL names (without extension).
/// If missing, a warning is logged but the mod still initializes.
/// </summary>
public virtual string[] OptionalDependencies => Array.Empty<string>();
/// <summary>
/// Indicates if the dependency check failed.
/// If true, all lifeycle methods (Update, GUI, etc.) are short-circuited.
/// </summary>
protected bool IsDependencySearchFailed { get; private set; }
public sealed override void OnInitializeMelon()
{
if (!gregDependencyResolver.CheckDependencies(LoggerInstance, MelonAssembly.Assembly.GetName().Name, RequiredDependencies, OptionalDependencies))
{
IsDependencySearchFailed = true;
return;
}
try
{
OnInitializeMod();
}
catch (Exception ex)
{
LoggerInstance.Error($"Unhandled exception during OnInitializeMod: {ex.Message}");
IsDependencySearchFailed = true;
}
}
/// <summary>
/// Actual initialization logic for the mod. Called only if dependencies are satisfied.
/// </summary>
public virtual void OnInitializeMod() { }
public override void OnUpdate() { if (!IsDependencySearchFailed) OnUpdateMod(); }
public virtual void OnUpdateMod() { }
public override void OnFixedUpdate() { if (!IsDependencySearchFailed) OnFixedUpdateMod(); }
public virtual void OnFixedUpdateMod() { }
public override void OnLateUpdate() { if (!IsDependencySearchFailed) OnLateUpdateMod(); }
public virtual void OnLateUpdateMod() { }
public override void OnGUI() { if (!IsDependencySearchFailed) OnGuiMod(); }
public virtual void OnGuiMod() { }
public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (!IsDependencySearchFailed) OnSceneLoadedMod(buildIndex, sceneName); }
public virtual void OnSceneLoadedMod(int buildIndex, string sceneName) { }
public override void OnApplicationQuit() { if (!IsDependencySearchFailed) OnApplicationQuitMod(); }
public virtual void OnApplicationQuitMod() { }
}
+8 -3
View File
@@ -4,10 +4,15 @@ using MelonLoader;
namespace greg.Core.Plugins;
/// <summary>
/// Base class for gregCore standalone plugins.
/// Base class for gregCore standalone plugins (extensions).
/// </summary>
public abstract class gregPluginBase : MelonMod
public abstract class gregPluginBase : gregModBase
{
/// <summary>
/// Extension plugins always require gregCore to function.
/// </summary>
public override string[] RequiredDependencies => new[] { "gregCore" };
/// <summary>
/// Gets the plugin's unique identifier.
/// </summary>
@@ -31,7 +36,7 @@ public abstract class gregPluginBase : MelonMod
/// <summary>
/// Registers the plugin with the central framework registry.
/// </summary>
public override void OnInitializeMelon()
public override void OnInitializeMod()
{
gregRegistry.RegisterPlugin(this);
}