- Disabled IMGUI drawing in Core.cs for Unity 6 stability. - Consolidated GregCoreMod and DataCenterModLoaderMod into a single GregCoreMod class for better organization and clarity. - Updated GregBootstrapper to use a boolean flag for hook integration. - Simplified HookIntegration class by removing unnecessary fields and methods, focusing on essential functionality. - Updated PlayerPatch and ShopPatch to emit hooks using string representation for better compatibility. - Introduced ModMenu and GregHardwareID classes for centralized mod configuration and unique object identification. - Enhanced GregDevConsole for improved logging and UI management. - Added legacy shims for backward compatibility with older mods. - Improved UI management with CanvasGroup for better input handling. - Updated QoL settings to allow for a range in slider values.
This commit is contained in:
Binary file not shown.
+3
-3
@@ -13,9 +13,9 @@
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
|
||||
<EnableDefaultNoneItems>false</EnableDefaultNoneItems>
|
||||
<Version>1.0.0.35</Version>
|
||||
<FileVersion>1.0.0.35</FileVersion>
|
||||
<AssemblyVersion>1.0.0.35</AssemblyVersion>
|
||||
<Version>1.0.0.38</Version>
|
||||
<FileVersion>1.0.0.38</FileVersion>
|
||||
<AssemblyVersion>1.0.0.38</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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": ""
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+85
-221
@@ -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<GregEventId, string> _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<GregEventId, List<Action<ulong>>> _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<object> callback)
|
||||
{
|
||||
_sdkApi = gregCore.GameLayer.Bootstrap.GregServiceContainer.Get<gregCore.Sdk.IGregAPI>();
|
||||
}
|
||||
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<bool>? 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<float>? 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<gregCore.Sdk.Models.GregPayload> 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<string, object> { { "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<object> 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<object> 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<ulong> handler)
|
||||
public class GregSettingsProxy
|
||||
{
|
||||
if (!_subscriptions.ContainsKey(eventId))
|
||||
_subscriptions[eventId] = new List<Action<ulong>>();
|
||||
|
||||
_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<bool> cb, string cat = "General", string desc = "") { }
|
||||
public void RegisterSlider(string modId, string k, string n, float min, float max, float def, Action<float> 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<ulong> 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<object> 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 }
|
||||
}
|
||||
|
||||
@@ -82,27 +82,28 @@ public static class GoFFIBridge
|
||||
_apiTable.set_game_paused = AddDelegate<SetDoubleDelegate>(val => GregAPI.SetGamePaused(val > 0));
|
||||
_apiTable.get_time_scale = AddDelegate<GetFloatDelegate>(() => GregAPI.GetTimeScale());
|
||||
_apiTable.set_time_scale = AddDelegate<SetFloatDelegate>(val => GregAPI.SetTimeScale(val));
|
||||
_apiTable.trigger_save = AddDelegate<DispatchDelegate>(() => GregAPI.TriggerSave());
|
||||
_apiTable.trigger_save = AddDelegate<DispatchDelegate>(() => { GregAPI.TriggerSave(); return 0; });
|
||||
_apiTable.get_difficulty = AddDelegate<GetIntDelegate>(() => GregAPI.GetDifficulty());
|
||||
|
||||
_apiTable.get_player_position = AddDelegate<GetPlayerPosDelegate>((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<LogDelegate>(ptr => GregAPI.ShowNotification(Marshal.PtrToStringAnsi(ptr) ?? ""));
|
||||
|
||||
_apiTable.subscribe_event = AddDelegate<SubscribeDelegate>((eventId, cbPtr) => {
|
||||
var callback = Marshal.GetDelegateForFunctionPointer<EventActionDelegate>(cbPtr);
|
||||
GregAPI.Subscribe((GregEventId)eventId, data => callback(eventId, data));
|
||||
GregAPI.Subscribe(((GregEventId)eventId).ToString(), data => callback(eventId, (ulong)data));
|
||||
});
|
||||
_apiTable.fire_event = AddDelegate<EventActionDelegate>((id, data) => GregAPI.FireEvent((GregEventId)id, data));
|
||||
_apiTable.fire_event = AddDelegate<EventActionDelegate>((id, data) => GregAPI.FireEvent(((GregEventId)id).ToString(), data));
|
||||
|
||||
// Hook API (New)
|
||||
_apiTable.on_hook = AddDelegate<OnHookDelegate>((hookPtr, cbPtr) => {
|
||||
string hookName = Marshal.PtrToStringAnsi(hookPtr) ?? "";
|
||||
var callback = Marshal.GetDelegateForFunctionPointer<HookActionDelegate>(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);
|
||||
|
||||
@@ -110,7 +110,7 @@ public static class LuaFFIBridge
|
||||
greg["get_player_position"] = (Func<Table>)(() => {
|
||||
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<uint, Closure>)((id, callback) => {
|
||||
GregAPI.Subscribe((GregEventId)id, data => callback.Call(data));
|
||||
GregAPI.Subscribe(((GregEventId)id).ToString(), data => callback.Call(data));
|
||||
});
|
||||
greg["fire_event"] = (Action<uint, ulong>)((id, data) => GregAPI.FireEvent((GregEventId)id, data));
|
||||
greg["fire_event"] = (Action<uint, ulong>)((id, data) => GregAPI.FireEvent(((GregEventId)id).ToString(), data));
|
||||
|
||||
// Hook API (New)
|
||||
greg["on"] = (Action<string, Closure>)((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;
|
||||
|
||||
@@ -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<PythonPlugin> _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<object>)(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() { }
|
||||
}
|
||||
|
||||
@@ -89,13 +89,12 @@ public static class RustFFIBridge
|
||||
_apiTable.set_game_paused = AddDelegate<SetDoubleDelegate>(val => GregAPI.SetGamePaused(val > 0));
|
||||
_apiTable.get_time_scale = AddDelegate<GetFloatDelegate>(() => GregAPI.GetTimeScale());
|
||||
_apiTable.set_time_scale = AddDelegate<SetFloatDelegate>(val => GregAPI.SetTimeScale(val));
|
||||
_apiTable.trigger_save = AddDelegate<DispatchDelegate>(() => GregAPI.TriggerSave());
|
||||
_apiTable.trigger_save = AddDelegate<DispatchDelegate>(() => { GregAPI.TriggerSave(); return 0; });
|
||||
_apiTable.get_difficulty = AddDelegate<GetIntDelegate>(() => GregAPI.GetDifficulty());
|
||||
|
||||
// Player
|
||||
_apiTable.get_player_position = AddDelegate<GetPlayerPosDelegate>((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<SubscribeDelegate>((eventId, cbPtr) => {
|
||||
var callback = Marshal.GetDelegateForFunctionPointer<EventActionDelegate>(cbPtr);
|
||||
GregAPI.Subscribe((GregEventId)eventId, data => callback(eventId, data));
|
||||
GregAPI.Subscribe(((GregEventId)eventId).ToString(), data => callback(eventId, (ulong)data));
|
||||
});
|
||||
_apiTable.fire_event = AddDelegate<EventActionDelegate>((id, data) => GregAPI.FireEvent((GregEventId)id, data));
|
||||
_apiTable.fire_event = AddDelegate<EventActionDelegate>((id, data) => GregAPI.FireEvent(((GregEventId)id).ToString(), data));
|
||||
|
||||
// Hook API (New)
|
||||
_apiTable.on_hook = AddDelegate<OnHookDelegate>((hookPtr, cbPtr) => {
|
||||
string hookName = Marshal.PtrToStringAnsi(hookPtr) ?? "";
|
||||
var callback = Marshal.GetDelegateForFunctionPointer<HookActionDelegate>(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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using gregCore.UI;
|
||||
|
||||
namespace gregCore.Core.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Centralized registry for all mod configurations.
|
||||
/// Mods register their settings here, and the SettingsHub generates the UI.
|
||||
/// </summary>
|
||||
public static class ModMenu
|
||||
{
|
||||
private static readonly Dictionary<string, ModCategory> _categories = new();
|
||||
public static IEnumerable<ModCategory> 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<Action<GregUIBuilder>> _uiBuilders = new();
|
||||
|
||||
public ModCategory(string name) => Name = name;
|
||||
|
||||
public ModCategory CreateToggle(string label, bool defaultValue, Action<bool> onValueChanged)
|
||||
{
|
||||
_uiBuilders.Add(builder => builder.AddToggle(label, defaultValue, onValueChanged));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModCategory CreateSlider(string label, float min, float max, float defaultValue, Action<float> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-154
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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).");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Der zentrale Einstiegspunkt des Frameworks (Prod-Layer: Core).
|
||||
/// Verantwortlich für Lifecycle, Service-Orchestrierung und globale Initialisierung.
|
||||
/// </summary>
|
||||
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<IGregLogger>();
|
||||
|
||||
// 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<gregCore.UI.GregUIDragHandler>();
|
||||
Il2CppInterop.Runtime.Injection.ClassInjector.RegisterTypeInIl2Cpp<greg.Furniture.FurniturePlacer>();
|
||||
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<GregHardwareID>();
|
||||
ClassInjector.RegisterTypeInIl2Cpp<GregUIDragHandler>();
|
||||
|
||||
// Initialize Core Systems
|
||||
GregUIManager.Initialize();
|
||||
GregDevConsole.Initialize();
|
||||
|
||||
MelonLogger.Msg("gregCore initialized successfully.");
|
||||
}
|
||||
|
||||
// 3. Plugin Loading
|
||||
_container.GetRequired<IGregPluginRegistry>().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<Infrastructure.Performance.GregPerformanceGovernor>()?.OnUpdate();
|
||||
GregServiceContainer.Get<Core.Events.GregEventBus>()?.FlushDeferredEvents();
|
||||
GregServiceContainer.Get<Infrastructure.Settings.Services.GregInputBindingService>()?.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<Infrastructure.Settings.Services.GregHudService>()?.OnGUI();
|
||||
GregServiceContainer.Get<Infrastructure.Settings.Services.GregNotificationService>()?.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<IGregEventBus>()
|
||||
.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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace gregCore.Core.Persistence
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures every spawned object has a unique, deterministic ID that survives save/load cycles.
|
||||
/// </summary>
|
||||
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<string, GameObject> _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<string, GameObject> GetAllHardware() => _registry;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ internal static class GregBootstrapper
|
||||
|
||||
container.Register<IAssemblyScanner>(new AssemblyScanner());
|
||||
|
||||
HookIntegration.Install(bus, logger);
|
||||
HookIntegration.Install(bus, true);
|
||||
global::gregCore.PublicApi.greg._context = apiContext;
|
||||
global::gregCore.PublicApi.greg._governor = governor;
|
||||
|
||||
|
||||
@@ -1,104 +1,43 @@
|
||||
/// <file-summary>
|
||||
/// Schicht: GameLayer
|
||||
/// Zweck: Bindet Harmony-Patches an den IGregEventBus.
|
||||
/// Maintainer: Kennt alle Patch-Klassen, installiert sie via Harmony.
|
||||
/// </file-summary>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <file-summary>
|
||||
/// <file-summary>
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using HarmonyLib;
|
||||
using HarmonyLib;
|
||||
using Il2Cpp;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using System;
|
||||
@@ -298,3 +298,4 @@ public static class MapDataHealing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<string, object> { { "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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using HarmonyLib;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace gregCore.GameLayer.Patches.Input;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
@@ -24,4 +24,4 @@ internal static class KeybindPatches
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <file-summary>
|
||||
/// <file-summary>
|
||||
/// 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
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <file-summary>
|
||||
/// <file-summary>
|
||||
/// 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
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <file-summary>
|
||||
/// <file-summary>
|
||||
/// 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
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<GregDevConsole> _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<LogEntry> _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<GregDevConsole>();
|
||||
Instance = go.AddComponent(Il2CppInterop.Runtime.Il2CppType.Of<GregDevConsole>()).Cast<GregDevConsole>();
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,11 @@ namespace greg.Mods.HexViewer
|
||||
public static void Initialize()
|
||||
{
|
||||
var go = new GameObject("greg_HexViewer");
|
||||
go.AddComponent<HexViewerWidget>();
|
||||
UnityEngine.Object.DontDestroyOnLoad(go);
|
||||
|
||||
// Safer IL2CPP initialization
|
||||
Il2CppInterop.Runtime.Injection.ClassInjector.RegisterTypeInIl2Cpp<HexViewerWidget>();
|
||||
go.AddComponent(Il2CppInterop.Runtime.Il2CppType.Of<HexViewerWidget>());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
|
||||
@@ -37,13 +37,14 @@ namespace gregCore.UI
|
||||
builder._activePanel.GetComponent<Image>().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<Image>();
|
||||
// Outer Border
|
||||
var border = builder._activePanel.AddComponent<Image>();
|
||||
border.sprite = GregUITheme.RoundedSprite;
|
||||
border.type = Image.Type.Sliced;
|
||||
|
||||
|
||||
+38
-8
@@ -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<string, GameObject> _panels = new();
|
||||
|
||||
public static Canvas RootCanvas => _canvas;
|
||||
@@ -36,14 +37,34 @@ namespace gregCore.UI
|
||||
_scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
|
||||
_raycaster = _rootObject.AddComponent<GraphicRaycaster>();
|
||||
|
||||
_canvasGroup = _rootObject.AddComponent<CanvasGroup>();
|
||||
|
||||
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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<GameObject> 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<ServerInfo> 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);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,41 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Il2Cpp;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace greg.Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// Legacy-Schnittstelle für ältere Mods (z.B. CableThrottle).
|
||||
/// Diese Klasse MUSS exakt diese statischen Felder bereitstellen, um MissingFieldExceptions zu vermeiden.
|
||||
/// </summary>
|
||||
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<float> PlayerCoinChanged = _ => { };
|
||||
public static Action<float> PlayerReputationChanged = _ => { };
|
||||
public static Action<float> PlayerXpChanged = _ => { };
|
||||
public static Action<int> DayEnded = _ => { };
|
||||
public static Action<int> MonthEnded = _ => { };
|
||||
public static Action<object> CustomerAccepted = _ => { };
|
||||
public static Action<object> ServerInstalled = _ => { };
|
||||
public static Action<object> ServerBroken = _ => { };
|
||||
public static Action<object> ServerRepaired = _ => { };
|
||||
public static Action<float> ShopCheckout = _ => { };
|
||||
// Change to Action<object> to support legacy API callbacks with null parameters
|
||||
public static Action<object> OnCoinsChanged;
|
||||
public static Action<object> OnXpChanged;
|
||||
public static Action<object> OnReputationChanged;
|
||||
|
||||
public static Action<object> SystemGameLoaded;
|
||||
public static Action<object> SystemGameSaved;
|
||||
|
||||
public static Action<object> GameLoaded;
|
||||
public static Action<object> GameSaved;
|
||||
public static Action<object> MoneyChanged;
|
||||
public static Action<object> XpChanged;
|
||||
public static Action<object> ReputationChanged;
|
||||
public static Action<object> DayEnded;
|
||||
public static Action<object> MonthEnded;
|
||||
|
||||
static gregNativeEventHooks()
|
||||
public static Action<object> 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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user