Decompiled source of MegaBonkPlus v0.9.4
MegaBonkPlusMod.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Assets.Scripts.Inventory__Items__Pickups; using Assets.Scripts.Inventory__Items__Pickups.Chests; using Assets.Scripts.Inventory__Items__Pickups.Interactables; using Assets.Scripts.Inventory__Items__Pickups.Items; using Assets.Scripts.Inventory__Items__Pickups.Stats; using Assets.Scripts.Inventory__Items__Pickups.Weapons; using Assets.Scripts.Menu.Shop; using Assets.Scripts.Saves___Serialization.Progression.Achievements; using Assets.Scripts._Data.Tomes; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BonkersLib.Core; using BonkersLib.Enums; using BonkersLib.Services; using BonkersLib.Services.Player; using BonkersLib.Utils; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; using MegaBonkPlusMod.Actions.Base; using MegaBonkPlusMod.Actions.Gameplay; using MegaBonkPlusMod.Actions.Inventory; using MegaBonkPlusMod.Actions.Teleport; using MegaBonkPlusMod.Config; using MegaBonkPlusMod.Core; using MegaBonkPlusMod.Enums; using MegaBonkPlusMod.GameLogic.Minimap; using MegaBonkPlusMod.GameLogic.Trackers; using MegaBonkPlusMod.GameLogic.Trackers.Base; using MegaBonkPlusMod.Infrastructure.Http; using MegaBonkPlusMod.Infrastructure.Http.Attributes; using MegaBonkPlusMod.Infrastructure.Http.Controllers; using MegaBonkPlusMod.Infrastructure.Services; using MegaBonkPlusMod.Models; using MegaBonkPlusMod.Response; using MegaBonkPlusMod.Utils; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("MegaBonkPlusMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MegaBonkPlusMod")] [assembly: AssemblyTitle("MegaBonkPlusMod")] [assembly: AssemblyVersion("1.0.0.0")] namespace MegaBonkPlusMod.Utils { public static class JsonResponse { public static void Send(HttpListenerContext context, string jsonString) { Send(context, jsonString, 200, "application/json"); } public static void Send(HttpListenerContext context, string content, int statusCode, string contentType) { try { byte[] bytes = Encoding.UTF8.GetBytes(content); context.Response.ContentLength64 = bytes.Length; context.Response.ContentType = contentType; context.Response.StatusCode = statusCode; context.Response.OutputStream.Write(bytes, 0, bytes.Length); } catch (Exception) { } finally { context.Response.OutputStream.Close(); context.Response.Close(); } } } public static class MainThreadActionQueue { private static readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>(); public static void QueueAction(Action action) { _queue.Enqueue(action); } public static void ExecuteAll() { Action result; while (_queue.TryDequeue(out result)) { result?.Invoke(); } } } internal static class ModLogger { private static ManualLogSource _modLogger; public static void InitLog(ManualLogSource logger) { _modLogger = logger; } private static bool IsEnabled(LoggingLevelEnum level) { return ModConfig.LogLevel.Value >= level; } public static void LogDebug(string message) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!IsEnabled(LoggingLevelEnum.Debug)) { return; } ManualLogSource modLogger = _modLogger; if (modLogger != null) { bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(8, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[DEBUG] "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message); } modLogger.LogInfo(val); } } public static void LogHttp(string message) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!IsEnabled(LoggingLevelEnum.Http)) { return; } ManualLogSource modLogger = _modLogger; if (modLogger != null) { bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(7, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HTTP] "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message); } modLogger.LogInfo(val); } } public static void LogTrace(string message) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!IsEnabled(LoggingLevelEnum.Trace)) { return; } ManualLogSource modLogger = _modLogger; if (modLogger != null) { bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(8, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TRACE] "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message); } modLogger.LogInfo(val); } } public static void LogInfo(string message) { ManualLogSource modLogger = _modLogger; if (modLogger != null) { modLogger.LogInfo((object)message); } } public static void LogWarning(string message) { ManualLogSource modLogger = _modLogger; if (modLogger != null) { modLogger.LogWarning((object)message); } } public static void LogError(string message) { ManualLogSource modLogger = _modLogger; if (modLogger != null) { modLogger.LogError((object)message); } } } } namespace MegaBonkPlusMod.Response { public class GameStateResponse { public bool IsInGame { get; set; } public string CurrentMap { get; set; } public int MapTier { get; set; } public float StageTime { get; set; } public float TimeAlive { get; set; } public int BossCurses { get; set; } } } namespace MegaBonkPlusMod.Models { public class ApiListResponseModel<T> { [JsonPropertyName("count")] public int Count { get; set; } [JsonPropertyName("items")] public List<T> Items { get; set; } public ApiListResponseModel(List<T> items) { Items = items; Count = items.Count; } public ApiListResponseModel() { Items = new List<T>(); Count = 0; } } public class ItemViewModel { public string id { get; set; } public string name { get; set; } public string description { get; set; } public bool inItemPool { get; set; } public string rarity { get; set; } } public struct PositionDataModel { [JsonPropertyName("x")] public float X { get; set; } [JsonPropertyName("y")] public float Y { get; set; } [JsonPropertyName("z")] public float Z { get; set; } public static PositionDataModel FromVector3(Vector3 vector) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) PositionDataModel result = default(PositionDataModel); result.X = (float)Math.Round(vector.x, 2); result.Y = (float)Math.Round(vector.y, 2); result.Z = (float)Math.Round(vector.z, 2); return result; } } public class TomeInventoryViewModel { public List<TomeSlotViewModel> tomes { get; set; } = new List<TomeSlotViewModel>(); } public class TomeSlotViewModel { public string id { get; set; } public string name { get; set; } public int level { get; set; } } public class TomeViewModel { public string id { get; set; } public string name { get; set; } public string description { get; set; } } public class TrackedObjectDataModel { [JsonPropertyName("instanceId")] public int InstanceId { get; set; } [JsonPropertyName("position")] public PositionDataModel Position { get; set; } [JsonPropertyName("customProperties")] public Dictionary<string, object> CustomProperties { get; set; } public TrackedObjectDataModel() { CustomProperties = new Dictionary<string, object>(); } } public class WeaponInventoryViewModel { public List<WeaponSlotViewModel> weapons { get; set; } = new List<WeaponSlotViewModel>(); } public class WeaponSlotViewModel { public string id { get; set; } public string name { get; set; } public int level { get; set; } } public class WeaponViewModel { public string id { get; set; } public string name { get; set; } public string description { get; set; } } } namespace MegaBonkPlusMod.Infrastructure.Services { public class MinimapCaptureService { private enum CaptureState { Idle, WaitingForSpawn, WaitingForMapDelay, HidingIcons, TakingPicture } private const float MINIMAP_CAPTURE_DELAY = 1.5f; private readonly MinimapStreamer _minimapStreamer; private readonly IReadOnlyList<BaseTracker> _trackers; private CaptureState _captureState = CaptureState.Idle; private float _captureTimer; public MinimapCaptureService(IReadOnlyList<BaseTracker> trackers, MinimapStreamer minimapStreamer) { _trackers = trackers; _minimapStreamer = minimapStreamer; } public void StartCapture() { ModLogger.LogDebug("Starting minimap capture logic..."); _minimapStreamer.ClearData(); _captureState = CaptureState.WaitingForSpawn; _captureTimer = 0f; } public void Update() { if (_captureState == CaptureState.Idle) { return; } _captureTimer -= Time.unscaledDeltaTime; if (!(_captureTimer > 0f)) { switch (_captureState) { case CaptureState.WaitingForSpawn: HandleWaitingForSpawn(); break; case CaptureState.WaitingForMapDelay: HandleWaitingForMapDelay(); break; case CaptureState.HidingIcons: HandleTakingPicture(); break; } } } private void HandleWaitingForSpawn() { foreach (BaseTracker tracker in _trackers) { tracker.ForceUpdatePayload(); } _captureState = CaptureState.WaitingForMapDelay; _captureTimer = 1.5f; } private void HandleWaitingForMapDelay() { _captureState = CaptureState.HidingIcons; try { foreach (BaseTracker tracker in _trackers) { tracker.HideIcons(); } Canvas.ForceUpdateCanvases(); } catch (Exception ex) { _captureState = CaptureState.Idle; ModLogger.LogDebug("Error hiding icons: " + ex.Message); } } private void HandleTakingPicture() { try { _minimapStreamer.TriggerMinimapUpdate(); } catch (Exception ex) { ModLogger.LogDebug("Error creating the MinimapImage: " + ex.Message); } finally { foreach (BaseTracker tracker in _trackers) { tracker.ShowIcons(); } } _captureState = CaptureState.Idle; } } public class TrackerRegistryService { private readonly Dictionary<string, BaseTracker> _trackers = new Dictionary<string, BaseTracker>(); public IReadOnlyDictionary<string, BaseTracker> TrackersDictionary => _trackers; public IReadOnlyList<BaseTracker> TrackersList => _trackers.Values.ToList(); public void RegisterDefaultTrackers() { Register("player", new PlayerTracker(0.1f)); Register("bossSpawner", new BossSpawnerTracker(5f)); Register("shadyGuys", new ShadyGuyTracker(2f)); Register("chargeShrines", new GenericTracker((WorldObjectTypeEnum)0, 2f, delegate(Component obj) { ChargeShrine val3 = (ChargeShrine)(object)((obj is ChargeShrine) ? obj : null); return new Dictionary<string, object> { ["isGolden"] = val3 != null && val3.isGolden }; })); Register("microwaves", new GenericTracker((WorldObjectTypeEnum)9, 2f, delegate(Component obj) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) InteractableMicrowave val2 = (InteractableMicrowave)(object)((obj is InteractableMicrowave) ? obj : null); Dictionary<string, object> dictionary2 = new Dictionary<string, object>(); object obj3; if (val2 == null) { obj3 = null; } else { EItemRarity rarity = val2.rarity; obj3 = ((object)(EItemRarity)(ref rarity)).ToString(); } if (obj3 == null) { obj3 = "Unknown"; } dictionary2["rarity"] = obj3; return dictionary2; })); Register("chests", new GenericTracker((WorldObjectTypeEnum)6, 2f, delegate(Component obj) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) InteractableChest val = (InteractableChest)(object)((obj is InteractableChest) ? obj : null); Dictionary<string, object> dictionary = new Dictionary<string, object>(); object obj2; if (val == null) { obj2 = null; } else { EChest chestType = val.chestType; obj2 = ((object)(EChest)(ref chestType)).ToString(); } if (obj2 == null) { obj2 = "Unknown"; } dictionary["type"] = obj2; return dictionary; })); Register("greedShrines", new GenericTracker((WorldObjectTypeEnum)3, 2f)); Register("moaiShrines", new GenericTracker((WorldObjectTypeEnum)1, 2f)); Register("cursedShrines", new GenericTracker((WorldObjectTypeEnum)2, 2f)); Register("magnetShrines", new GenericTracker((WorldObjectTypeEnum)4, 2f)); Register("challengeShrines", new GenericTracker((WorldObjectTypeEnum)5, 2f)); Register("bosses", new GenericTracker((WorldObjectTypeEnum)12, 2f)); } private void Register(string key, BaseTracker tracker) { _trackers[key] = tracker; } public void UpdateAll() { foreach (BaseTracker value in _trackers.Values) { value.Update(); } } } } namespace MegaBonkPlusMod.Infrastructure.Http { public class ApiResponse<T> { [JsonPropertyName("success")] public bool Success { get; set; } [JsonPropertyName("message")] public string Message { get; set; } [JsonPropertyName("data")] public T Data { get; set; } [JsonPropertyName("statusCode")] public int StatusCode { get; set; } [JsonPropertyName("error")] public string Error { get; set; } public static ApiResponse<T> Ok(T data, string message = "Success") { return new ApiResponse<T> { Success = true, Message = message, Data = data, StatusCode = 200, Error = null }; } public static ApiResponse<T> Created(T data, string message = "Resource created") { return new ApiResponse<T> { Success = true, Message = message, Data = data, StatusCode = 201, Error = null }; } public static ApiResponse<T> BadRequest(string error, string message = "Bad request") { return new ApiResponse<T> { Success = false, Message = message, Data = default(T), StatusCode = 400, Error = error }; } public static ApiResponse<T> NotFound(string message = "Resource not found") { return new ApiResponse<T> { Success = false, Message = message, Data = default(T), StatusCode = 404, Error = "NOT_FOUND" }; } public static ApiResponse<T> ServerError(string error, string message = "Internal server error") { return new ApiResponse<T> { Success = false, Message = message, Data = default(T), StatusCode = 500, Error = error }; } } public class ApiResponse : ApiResponse<object> { public static ApiResponse Ok(string message = "Success") { return new ApiResponse { Success = true, Message = message, StatusCode = 200, Error = null }; } } public class ControllerRouter { private readonly Dictionary<string, (MethodInfo method, object controller)> _getRoutes = new Dictionary<string, (MethodInfo, object)>(); private readonly Dictionary<string, (MethodInfo method, object controller)> _postRoutes = new Dictionary<string, (MethodInfo, object)>(); public void RegisterControllers(params object[] controllers) { ModLogger.LogDebug("Registering API controllers..."); foreach (object controller in controllers) { RegisterController(controller); } } private void RegisterController(object controller) { Type type = controller.GetType(); string basePath = type.GetCustomAttribute<ApiControllerAttribute>()?.BasePath ?? ""; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { HttpGetAttribute customAttribute = methodInfo.GetCustomAttribute<HttpGetAttribute>(); if (customAttribute != null) { string text = CombinePaths(basePath, customAttribute.Route); _getRoutes[text] = (methodInfo, controller); ModLogger.LogDebug($" [GET] {text} → {type.Name}.{methodInfo.Name}"); } HttpPostAttribute customAttribute2 = methodInfo.GetCustomAttribute<HttpPostAttribute>(); if (customAttribute2 != null) { string text2 = CombinePaths(basePath, customAttribute2.Route); _postRoutes[text2] = (methodInfo, controller); ModLogger.LogDebug($" [POST] {text2} → {type.Name}.{methodInfo.Name}"); } } } public bool HandleRequest(HttpListenerContext context) { string absolutePath = context.Request.Url.AbsolutePath; string httpMethod = context.Request.HttpMethod; try { if (httpMethod == "GET" && _getRoutes.TryGetValue(absolutePath, out (MethodInfo, object) value)) { InvokeController(context, value.Item1, value.Item2, null); return true; } if (httpMethod == "POST" && _postRoutes.TryGetValue(absolutePath, out (MethodInfo, object) value2)) { JsonElement? payload = ReadJsonPayload(context); InvokeController(context, value2.Item1, value2.Item2, payload); return true; } } catch (Exception ex) { ModLogger.LogDebug("Error handling controller request: " + ex.Message + "\n" + ex.StackTrace); SendErrorResponse(context, ex); return true; } return false; } private void InvokeController(HttpListenerContext context, MethodInfo method, object controller, JsonElement? payload) { try { ParameterInfo[] parameters = method.GetParameters(); object obj; if (parameters.Length == 0) { obj = method.Invoke(controller, null); } else { if (parameters.Length != 1 || !(parameters[0].ParameterType == typeof(JsonElement))) { throw new InvalidOperationException("Unsupported method signature: " + method.Name); } obj = method.Invoke(controller, new object[1] { payload.GetValueOrDefault() }); } if (obj != null && controller is ApiControllerBase obj2) { Type type = obj.GetType(); MethodInfo methodInfo = typeof(ApiControllerBase).GetMethod("SendResponse", BindingFlags.Instance | BindingFlags.NonPublic).MakeGenericMethod(type.GetGenericArguments().FirstOrDefault() ?? typeof(object)); methodInfo.Invoke(obj2, new object[2] { context, obj }); } } catch (TargetInvocationException ex) { Exception ex2 = ex.InnerException ?? ex; ModLogger.LogDebug("Error invoking controller method: " + ex2.Message); SendErrorResponse(context, ex2); } catch (Exception ex3) { ModLogger.LogDebug("Error invoking controller method: " + ex3.Message); SendErrorResponse(context, ex3); } } private JsonElement? ReadJsonPayload(HttpListenerContext context) { try { using StreamReader streamReader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding); string text = streamReader.ReadToEnd(); if (string.IsNullOrWhiteSpace(text)) { return null; } return JsonDocument.Parse(text).RootElement; } catch (Exception ex) { ModLogger.LogDebug("Error reading JSON payload: " + ex.Message); return null; } } private void SendErrorResponse(HttpListenerContext context, Exception ex) { try { ApiResponse<object> value = ApiResponse<object>.ServerError(ex.Message); string s = JsonSerializer.Serialize(value, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); context.Response.StatusCode = 500; context.Response.ContentType = "application/json"; byte[] bytes = Encoding.UTF8.GetBytes(s); context.Response.OutputStream.Write(bytes, 0, bytes.Length); context.Response.Close(); } catch (Exception ex2) { ModLogger.LogDebug("Error sending error response: " + ex2.Message); try { context.Response.StatusCode = 500; context.Response.Close(); } catch { } } } private string CombinePaths(string basePath, string route) { if (string.IsNullOrEmpty(basePath)) { return route; } if (string.IsNullOrEmpty(route)) { return basePath; } basePath = basePath.TrimEnd('/'); route = route.TrimStart('/'); return basePath + "/" + route; } } public class HttpServer { private readonly ControllerRouter _controllerRouter; private readonly HttpListener _listener; private readonly Assembly _pluginAssembly; private bool _browserOpened; private bool _isRunning; public HttpServer(ControllerRouter controllerRouter) { _controllerRouter = controllerRouter; _listener = new HttpListener(); _listener.Prefixes.Add($"http://localhost:{ModConfig.WebServerPort.Value}/"); _pluginAssembly = Assembly.GetExecutingAssembly(); } public void Start() { if (!_isRunning) { _isRunning = true; Task.Run((Action)RunServerLoop); ModLogger.LogDebug($"HttpServer start requested at http://localhost:{ModConfig.WebServerPort.Value}/"); TryOpenBrowser(); } } public void Stop() { _isRunning = false; try { _listener?.Stop(); _listener?.Close(); } catch (Exception) { } } private async void RunServerLoop() { try { try { _listener.Start(); ModLogger.LogInfo($"HttpServer listening on http://localhost:{ModConfig.WebServerPort.Value}/"); } catch (HttpListenerException ex5) { HttpListenerException ex3 = ex5; _isRunning = false; ModLogger.LogError("HttpServer failed to start: " + ((Exception)(object)ex3).Message); return; } while (_isRunning) { HttpListenerContext context = await _listener.GetContextAsync(); ModLogger.LogHttp("[" + context.Request.HttpMethod + "] " + context.Request.Url.AbsolutePath); try { if (_controllerRouter.HandleRequest(context)) { ModLogger.LogHttp("[HttpServer] Controller handled " + context.Request.Url.AbsolutePath); continue; } } catch (Exception ex4) { ModLogger.LogError($"[HttpServer] Controller crashed for {context.Request.Url.AbsolutePath}: {ex4}"); context.Response.StatusCode = 500; context.Response.Close(); continue; } if (context.Request.HttpMethod == "GET") { try { HandleEmbeddedRequest(context); } catch (Exception ex6) { Exception ex2 = ex6; ModLogger.LogError($"[HttpServer] Static file handler crashed for {context.Request.Url.AbsolutePath}: {ex2}"); } } else { context.Response.StatusCode = 404; context.Response.Close(); } ModLogger.LogHttp("[HttpServer] Finished request " + context.Request.Url.AbsolutePath); } } catch (Exception ex6) { Exception ex = ex6; if (_isRunning && !(ex is ObjectDisposedException)) { ModLogger.LogTrace($"HttpServer loop error: {ex}"); } } } private void HandleEmbeddedRequest(HttpListenerContext context) { string text = context.Request.Url.AbsolutePath; if (text == "/") { text = "/index.html"; } string text2 = "MegaBonkPlusMod.Frontend" + text.Replace('/', '.'); try { using Stream stream = _pluginAssembly.GetManifestResourceStream(text2); if (stream == null) { context.Response.StatusCode = 404; context.Response.Close(); } else { context.Response.ContentType = GetMimeType(text); stream.CopyTo(context.Response.OutputStream); } } catch (Exception value) { ModLogger.LogTrace($"Error serving file '{text2}': {value}"); context.Response.StatusCode = 500; context.Response.Close(); } finally { if (context.Response.OutputStream.CanWrite) { context.Response.OutputStream.Close(); } if (context.Response != null && context.Response.StatusCode != 404) { context.Response.Close(); } ModLogger.LogTrace("Response sent for " + context.Request.Url.AbsolutePath); } } private string GetMimeType(string path) { if (path.EndsWith(".js")) { return "application/javascript"; } if (path.EndsWith(".css")) { return "text/css"; } if (path.EndsWith(".html")) { return "text/html"; } if (path.EndsWith(".png")) { return "image/png"; } if (path.EndsWith(".jpg") || path.EndsWith(".jpeg")) { return "image/jpeg"; } return "application/octet-stream"; } private void TryOpenBrowser() { if (_browserOpened) { return; } _browserOpened = true; string text = $"http://localhost:{ModConfig.WebServerPort.Value}/"; try { ProcessStartInfo startInfo = new ProcessStartInfo { FileName = text, UseShellExecute = true }; Process.Start(startInfo); ModLogger.LogInfo("Opened browser at " + text); } catch (Exception ex) { ModLogger.LogError("Failed to open browser: " + ex.Message); } } } } namespace MegaBonkPlusMod.Infrastructure.Http.Controllers { [ApiController("/api/actions")] public class ActionController : ApiControllerBase { private readonly ActionHandler _actionHandler; public ActionController(ActionHandler actionHandler) { _actionHandler = actionHandler; } [HttpGet("/state")] public ApiResponse<Dictionary<string, object>> GetActionStates() { try { Dictionary<string, object> actionStates = _actionHandler.GetActionStates(); return Ok(actionStates, "Action states retrieved"); } catch (Exception ex) { return ServerError<Dictionary<string, object>>(ex.Message); } } [HttpPost("/execute")] public ApiResponse ExecuteAction(JsonElement payload) { if (!payload.TryGetProperty("action", out var value)) { return BadRequest("Missing 'action' property"); } string actionName = value.GetString(); string resultMessage = null; try { MainThreadActionQueue.QueueAction(delegate { resultMessage = _actionHandler.HandleAction(actionName, payload); }); Thread.Sleep(50); return Ok(resultMessage ?? ("Action '" + actionName + "' queued successfully")); } catch (Exception ex) { return ServerError(ex.Message); } } } public abstract class ApiControllerBase { protected void SendResponse<T>(HttpListenerContext context, ApiResponse<T> response) { context.Response.StatusCode = response.StatusCode; context.Response.ContentType = "application/json"; string s = JsonSerializer.Serialize(response, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = false }); byte[] bytes = Encoding.UTF8.GetBytes(s); context.Response.ContentLength64 = bytes.Length; context.Response.OutputStream.Write(bytes, 0, bytes.Length); try { ModLogger.LogTrace("[HttpServer] Response sent for " + context.Request.Url.AbsolutePath); } catch (Exception value) { ModLogger.LogError($"[HttpServer] Failed to send response for {context.Request.Url.AbsolutePath}: {value}"); throw; } finally { context.Response.OutputStream.Close(); context.Response.Close(); } } protected ApiResponse<T> Ok<T>(T data, string message = "Success") { return ApiResponse<T>.Ok(data, message); } protected ApiResponse Ok(string message = "Success") { return ApiResponse.Ok(message); } protected ApiResponse<T> BadRequest<T>(string error) { return ApiResponse<T>.BadRequest(error); } protected ApiResponse BadRequest(string error) { return new ApiResponse { Success = false, Message = "Bad request", Error = error, StatusCode = 400 }; } protected ApiResponse<T> NotFound<T>(string message = "Not found") { return ApiResponse<T>.NotFound(message); } protected ApiResponse<T> ServerError<T>(string error) { return ApiResponse<T>.ServerError(error); } protected ApiResponse ServerError(string error) { return new ApiResponse { Success = false, Message = "Internal server error", Error = error, StatusCode = 500 }; } } public class TimeScaleRequest { public float TimeScale { get; set; } } [ApiController("/api/game")] public class GameStateController : ApiControllerBase { [HttpGet("/state")] public ApiResponse<GameStateResponse> GetGameState() { try { GameStateService game = BonkersAPI.Game; GameStateResponse data = new GameStateResponse { IsInGame = game.IsInGame, CurrentMap = game.StageName, MapTier = game.StageTier, StageTime = game.StageTime, TimeAlive = game.TimeAlive, BossCurses = game.BossCurses }; return Ok(data, "Game state retrieved"); } catch (Exception ex) { return ServerError<GameStateResponse>(ex.Message); } } [HttpGet("/time-scale")] public ApiResponse<float> GetTimeScale() { try { return Ok(BonkersAPI.Game.CurrentTimeScale, "Time scale retrieved"); } catch (Exception ex) { return ServerError<float>(ex.Message); } } [HttpPost("/time-scale")] public ApiResponse<bool> SetTimeScale(JsonElement payload) { try { float num = 1f; bool flag = false; if (payload.ValueKind == JsonValueKind.Object) { if (payload.TryGetProperty("timeScale", out var value)) { num = value.GetSingle(); flag = true; } else if (payload.TryGetProperty("value", out value)) { num = value.GetSingle(); flag = true; } } if (!flag) { return BadRequest<bool>("Missing 'timeScale' or 'value' property in JSON"); } BonkersAPI.Game.SetTimeScale(num, true); return Ok(data: true, $"TimeScale set to {num}"); } catch (Exception ex) { return ServerError<bool>(ex.Message); } } } [ApiController("/api/hotkeys")] public class HotkeyController : ApiControllerBase { private readonly ActionHandler _actionHandler; public HotkeyController(ActionHandler actionHandler) { _actionHandler = actionHandler; } [HttpGet("")] public ApiResponse<object> GetHotkeyConfig() { try { object currentConfig = HotkeyManager.GetCurrentConfig(); return Ok(currentConfig, "Hotkey configuration retrieved successfully"); } catch (Exception ex) { return ServerError<object>(ex.Message); } } [HttpPost("")] public ApiResponse SetHotkeyConfig(JsonElement payload) { try { List<string> actionNames = HotkeyManager.UpdateConfig(payload); _actionHandler.StopLoopingActions(actionNames); return Ok("Hotkeys updated"); } catch (Exception ex) { return BadRequest(ex.Message); } } } [ApiController("/api")] public class InventoryController : ApiControllerBase { [HttpGet("/weapons/all")] public ApiResponse<List<WeaponViewModel>> GetAllWeapons() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { if (!Object.op_Implicit((Object)(object)BonkersAPI.Data.CurrentDataManager) || BonkersAPI.Data.WeaponData == null) { return ServerError<List<WeaponViewModel>>("Weapon data not initialized"); } List<WeaponViewModel> list = new List<WeaponViewModel>(); Enumerator<EWeapon, WeaponData> enumerator = BonkersAPI.Data.WeaponData.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair<EWeapon, WeaponData> current = enumerator.Current; EWeapon key = current.Key; WeaponData value = current.Value; WeaponViewModel item = new WeaponViewModel { id = ((object)(EWeapon)(ref key)).ToString().ToLowerInvariant(), name = (value.damageSourceName ?? ((Object)value).name), description = ((UnlockableBase)value).GetDescription() }; list.Add(item); } list.Sort((WeaponViewModel a, WeaponViewModel b) => string.Compare(a.name, b.name, StringComparison.OrdinalIgnoreCase)); return Ok(list, $"Retrieved {list.Count} weapons"); } catch (Exception ex) { return ServerError<List<WeaponViewModel>>(ex.Message); } } [HttpGet("/weapons/inventory")] public ApiResponse<WeaponInventoryViewModel> GetWeaponInventory() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) try { if (!BonkersAPI.Game.IsInGame) { return ServerError<WeaponInventoryViewModel>("Not in game"); } WeaponService weapon = BonkersAPI.Weapon; Dictionary<EWeapon, WeaponBase> val = ((weapon != null) ? weapon.CurrentWeapons : null); WeaponInventoryViewModel weaponInventoryViewModel = new WeaponInventoryViewModel(); if (val != null) { Enumerator<EWeapon, WeaponBase> enumerator = val.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair<EWeapon, WeaponBase> current = enumerator.Current; EWeapon key = current.Key; WeaponBase value = current.Value; WeaponData weaponDataFromWeaponBase = weapon.GetWeaponDataFromWeaponBase(value); weaponInventoryViewModel.weapons.Add(new WeaponSlotViewModel { id = ((object)(EWeapon)(ref key)).ToString().ToLowerInvariant(), name = (weaponDataFromWeaponBase.damageSourceName ?? ((Object)weaponDataFromWeaponBase).name), level = value.level }); } } return Ok(weaponInventoryViewModel, $"Retrieved {weaponInventoryViewModel.weapons.Count} equipped weapons"); } catch (Exception ex) { return ServerError<WeaponInventoryViewModel>(ex.Message); } } [HttpGet("/tomes/all")] public ApiResponse<List<TomeViewModel>> GetAllTomes() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { if (!Object.op_Implicit((Object)(object)BonkersAPI.Data.CurrentDataManager) || BonkersAPI.Data.TomeData == null) { return ServerError<List<TomeViewModel>>("Tome data not initialized"); } List<TomeViewModel> list = new List<TomeViewModel>(); Enumerator<ETome, TomeData> enumerator = BonkersAPI.Data.TomeData.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair<ETome, TomeData> current = enumerator.Current; ETome key = current.Key; TomeData value = current.Value; string internalName = ((UnlockableBase)value).GetInternalName(); string description = ((UnlockableBase)value).GetDescription(); TomeViewModel item = new TomeViewModel { id = ((object)(ETome)(ref key)).ToString().ToLowerInvariant(), name = internalName, description = description }; list.Add(item); } list.Sort((TomeViewModel a, TomeViewModel b) => string.Compare(a.name, b.name, StringComparison.OrdinalIgnoreCase)); return Ok(list, $"Retrieved {list.Count} tomes"); } catch (Exception ex) { return ServerError<List<TomeViewModel>>(ex.Message); } } [HttpGet("/tomes/inventory")] public ApiResponse<TomeInventoryViewModel> GetTomeInventory() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) try { if (!BonkersAPI.Game.IsInGame) { return ServerError<TomeInventoryViewModel>("Not in game"); } TomeService tome = BonkersAPI.Tome; Dictionary<ETome, StatModifier> val = ((tome != null) ? tome.CurrentTomes : null); TomeInventoryViewModel tomeInventoryViewModel = new TomeInventoryViewModel(); if (val != null) { Enumerator<ETome, StatModifier> enumerator = val.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair<ETome, StatModifier> current = enumerator.Current; ETome key = current.Key; TomeData tomeDataFromEnum = BonkersAPI.Tome.GetTomeDataFromEnum(key); string internalName = ((UnlockableBase)tomeDataFromEnum).GetInternalName(); int level = tomeDataFromEnum.GetLevel(); tomeInventoryViewModel.tomes.Add(new TomeSlotViewModel { id = ((object)(ETome)(ref key)).ToString().ToLowerInvariant(), name = internalName, level = level }); } } return Ok(tomeInventoryViewModel, $"Retrieved {tomeInventoryViewModel.tomes.Count} equipped tomes"); } catch (Exception ex) { return ServerError<TomeInventoryViewModel>(ex.Message); } } } [ApiController("/api/items")] public class ItemController : ApiControllerBase { [HttpGet("/all")] public ApiResponse<List<ItemViewModel>> GetAllItems() { try { List<ItemData> rawItems = BonkersAPI.Item.GetAllRawItems(); List<ItemViewModel> list = MainThreadDispatcher.Evaluate<List<ItemViewModel>>((Func<List<ItemViewModel>>)delegate { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) List<ItemViewModel> list2 = new List<ItemViewModel>(rawItems.Count); foreach (ItemData item in rawItems) { try { ItemViewModel itemViewModel = new ItemViewModel(); EItem eItem = item.eItem; itemViewModel.id = ((object)(EItem)(ref eItem)).ToString().ToLowerInvariant(); itemViewModel.name = ((Object)item).name; itemViewModel.description = ((UnlockableBase)item).GetDescription(); itemViewModel.inItemPool = item.inItemPool; EItemRarity rarity = item.rarity; itemViewModel.rarity = ((object)(EItemRarity)(ref rarity)).ToString(); list2.Add(itemViewModel); } catch { } } return list2; }); return Ok(list, $"Retrieved {list.Count} items"); } catch (Exception ex) { return ServerError<List<ItemViewModel>>(ex.Message); } } } [ApiController("/api/minimap")] public class MinimapController : ApiControllerBase { private readonly MinimapStreamer _minimapStreamer; public MinimapController(MinimapStreamer minimapStreamer) { _minimapStreamer = minimapStreamer; } [HttpGet("/stream")] public ApiResponse<object> GetMinimapStream() { try { object data = _minimapStreamer.GetData(); return Ok(data, "Minimap data retrieved"); } catch (Exception ex) { return ServerError<object>(ex.Message); } } } [ApiController("/api/trackers")] public class TrackerController : ApiControllerBase { private readonly IReadOnlyDictionary<string, BaseTracker> _trackers; public TrackerController(IReadOnlyDictionary<string, BaseTracker> trackers) { _trackers = trackers; } [HttpGet("/all")] public ApiResponse<Dictionary<string, object>> GetAllTrackerData() { try { Dictionary<string, object> dictionary = new Dictionary<string, object>(); foreach (KeyValuePair<string, BaseTracker> tracker in _trackers) { try { dictionary[tracker.Key] = tracker.Value.GetData(); } catch (Exception ex) { dictionary[tracker.Key] = new { error = ex.Message }; } } return Ok(dictionary, $"Retrieved data from {dictionary.Count} trackers"); } catch (Exception ex2) { return ServerError<Dictionary<string, object>>(ex2.Message); } } [HttpGet("/player")] public ApiResponse<object> GetPlayerData() { return GetTrackerByKey("player"); } [HttpGet("/chests")] public ApiResponse<object> GetChestData() { return GetTrackerByKey("chests"); } [HttpGet("/shrines")] public ApiResponse<List<object>> GetShrineData() { try { List<object> list = new List<object>(); string[] array = new string[6] { "chargeShrines", "greedShrines", "moaiShrines", "cursedShrines", "magnetShrines", "challengeShrines" }; foreach (string key in array) { if (_trackers.TryGetValue(key, out var value)) { object data = value.GetData(); if (data != null) { list.Add(data); } } } return Ok(list, "Shrine data retrieved"); } catch (Exception ex) { return ServerError<List<object>>(ex.Message); } } [HttpGet("/enemies")] public ApiResponse<object> GetEnemyData() { return GetTrackerByKey("bosses"); } [HttpGet("/shady-guys")] public ApiResponse<object> GetShadyGuyData() { return GetTrackerByKey("shadyGuys"); } [HttpGet("/boss-spawners")] public ApiResponse<object> GetBossSpawnerData() { return GetTrackerByKey("bossSpawner"); } [HttpGet("/microwave")] public ApiResponse<object> GetMicrowaveData() { return GetTrackerByKey("microwaves"); } private ApiResponse<object> GetTrackerByKey(string key) { try { if (_trackers.TryGetValue(key, out var value)) { object data = value.GetData(); return Ok(data, key + " data retrieved"); } return NotFound<object>("Tracker '" + key + "' not found"); } catch (Exception ex) { return ServerError<object>(ex.Message); } } } } namespace MegaBonkPlusMod.Infrastructure.Http.Attributes { [AttributeUsage(AttributeTargets.Method)] public class HttpGetAttribute : Attribute { public string Route { get; } public HttpGetAttribute(string route) { Route = route; } } [AttributeUsage(AttributeTargets.Method)] public class HttpPostAttribute : Attribute { public string Route { get; } public HttpPostAttribute(string route) { Route = route; } } [AttributeUsage(AttributeTargets.Class)] public class ApiControllerAttribute : Attribute { public string BasePath { get; } public ApiControllerAttribute(string basePath = "") { BasePath = basePath; } } } namespace MegaBonkPlusMod.GameLogic.Trackers { public class BossSpawnerTracker : BaseTracker { public BossSpawnerTracker(float scanIntervalInSeconds) : base(scanIntervalInSeconds) { } protected override object BuildDataPayload() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) List<TrackedObjectDataModel> list = new List<TrackedObjectDataModel>(); if (!BonkersAPI.Game.IsInGame) { return new ApiListResponseModel<TrackedObjectDataModel>(list); } WorldService world = BonkersAPI.World; Component val = (Component)(object)world.GetBossSpawner().FirstOrDefault(); if (!Object.op_Implicit((Object)(object)val)) { val = (Component)(object)world.GetBossSpawnerFinal().FirstOrDefault(); } if (Object.op_Implicit((Object)(object)val)) { CacheIconsForObject(GameObjectUtils.FindMinimapIcon(val.transform)); TrackedObjectDataModel item = new TrackedObjectDataModel { Position = PositionDataModel.FromVector3(val.transform.position), InstanceId = ((Object)val.gameObject).GetInstanceID() }; list.Add(item); } return new ApiListResponseModel<TrackedObjectDataModel>(list); } } public class GenericTracker : BaseTracker { private readonly Func<Component, Dictionary<string, object>> _customPropertiesExtractor; private readonly WorldObjectTypeEnum _objectType; public GenericTracker(WorldObjectTypeEnum objectType, float scanIntervalInSeconds, Func<Component, Dictionary<string, object>> customPropertiesExtractor = null) : base(scanIntervalInSeconds) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) _objectType = objectType; _customPropertiesExtractor = customPropertiesExtractor; } protected override object BuildDataPayload() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) List<TrackedObjectDataModel> list = new List<TrackedObjectDataModel>(); if (!BonkersAPI.Game.IsInGame) { return new ApiListResponseModel<TrackedObjectDataModel>(list); } try { WorldService world = BonkersAPI.World; IEnumerable<Component> cachedObjects = world.GetCachedObjects<Component>(_objectType); foreach (Component item in cachedObjects) { if (!Object.op_Implicit((Object)(object)item) || !Object.op_Implicit((Object)(object)item.gameObject)) { continue; } try { CacheIconsForObject(GameObjectUtils.FindMinimapIcon(item.transform)); TrackedObjectDataModel trackedObjectDataModel = new TrackedObjectDataModel { Position = PositionDataModel.FromVector3(item.transform.position), InstanceId = ((Object)item.gameObject).GetInstanceID() }; if (_customPropertiesExtractor != null) { try { Dictionary<string, object> dictionary = _customPropertiesExtractor(item); if (dictionary != null) { foreach (KeyValuePair<string, object> item2 in dictionary) { trackedObjectDataModel.CustomProperties[item2.Key] = item2.Value; } } } catch (Exception ex) { ModLogger.LogDebug("[GenericTracker] Error extracting custom properties: " + ex.Message); } } list.Add(trackedObjectDataModel); } catch (Exception ex2) { ModLogger.LogDebug("[GenericTracker] Error processing object: " + ex2.Message); } } } catch (Exception ex3) { ModLogger.LogDebug("[GenericTracker] Error in BuildDataPayload: " + ex3.Message); } return new ApiListResponseModel<TrackedObjectDataModel>(list); } } public class PlayerTracker : BaseTracker { public PlayerTracker(float scanIntervalInSeconds) : base(scanIntervalInSeconds) { } protected override object BuildDataPayload() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) List<TrackedObjectDataModel> list = new List<TrackedObjectDataModel>(); if (!BonkersAPI.Game.IsInGame) { return new ApiListResponseModel<TrackedObjectDataModel>(list); } PlayerService player = BonkersAPI.Player; TrackedObjectDataModel trackedObjectDataModel = new TrackedObjectDataModel { InstanceId = player.InstanceId, Position = PositionDataModel.FromVector3(player.Position) }; trackedObjectDataModel.CustomProperties["character"] = player.CharacterName; Dictionary<EStat, float> statsDict = player.StatsDict; trackedObjectDataModel.CustomProperties["level"] = player.Level; Dictionary<string, object> dictionary = new Dictionary<string, object>(); dictionary["HP"] = $"{player.Health} / {player.MaxHealth}"; dictionary["Shield"] = $"{(int)player.Shield} / {(int)player.MaxShield}"; dictionary["HP Regen"] = statsDict[(EStat)1]; dictionary["Overheal"] = AddTimesStat(statsDict[(EStat)47]); dictionary["Armor"] = AddPercentStat(statsDict[(EStat)4]); dictionary["Evasion"] = AddPercentStat(statsDict[(EStat)5]); dictionary["Lifesteal"] = AddPercentStat(statsDict[(EStat)17]); dictionary["Thorns"] = RoundInt(statsDict[(EStat)3]); dictionary["Damage"] = AddTimesStat(statsDict[(EStat)12]); dictionary["Crit Chance"] = AddPercentStat(statsDict[(EStat)18]); dictionary["Crit Damage"] = AddTimesStat(statsDict[(EStat)19], 2f); dictionary["Attack Speed"] = AddPercentStat(statsDict[(EStat)15]); dictionary["Projectile Count"] = RoundDownInt(statsDict[(EStat)16]); dictionary["Projectile Bounces"] = statsDict[(EStat)45]; dictionary["Evasion"] = AddPercentStat(statsDict[(EStat)5]); dictionary["Size"] = AddTimesStat(statsDict[(EStat)9]); dictionary["Projectile Speed"] = AddTimesStat(statsDict[(EStat)11]); dictionary["Duration"] = AddTimesStat(statsDict[(EStat)10]); dictionary["Damage to Elites"] = AddTimesStat(statsDict[(EStat)23]); dictionary["Knockback"] = AddTimesStat(statsDict[(EStat)24]); dictionary["Movement Speed"] = AddTimesStat(statsDict[(EStat)25]); dictionary["Extra Jumps"] = RoundInt(statsDict[(EStat)46]); dictionary["Jump Height"] = RoundInt(statsDict[(EStat)26]); dictionary["Luck"] = AddPercentStat(statsDict[(EStat)30]); dictionary["Difficulty"] = AddPercentStat(statsDict[(EStat)38]); dictionary["Pickup Range"] = RoundInt(statsDict[(EStat)29]); dictionary["XP Gain"] = AddTimesStat(statsDict[(EStat)32]); dictionary["Gold Gain"] = AddTimesStat(statsDict[(EStat)31]); dictionary["Silver Gain"] = AddTimesStat(statsDict[(EStat)49]); dictionary["Elite Spawn Increase"] = AddTimesStat(statsDict[(EStat)39]); dictionary["Powerup Multiplier"] = AddTimesStat(statsDict[(EStat)40]); dictionary["Powerup Drop Chance"] = AddTimesStat(statsDict[(EStat)41]); trackedObjectDataModel.CustomProperties["stats"] = dictionary; list.Add(trackedObjectDataModel); return new ApiListResponseModel<TrackedObjectDataModel>(list); } protected override void OnTrackerError(Exception ex) { ModLogger.LogDebug("[PlayerTracker] Error: " + ex.Message); } private static string AddPercentStat(float value, float multiplier = 100f) { float num = value * multiplier; return (float)Math.Round(num) + "%"; } private static string AddTimesStat(float value, float multiplier = 1f) { float num = value * multiplier; return ((float)Math.Round(num, 1)).ToString("F1") + "x"; } private static int RoundInt(float value) { return (int)Math.Round(value); } private static int RoundDownInt(float value) { return (int)Math.Floor(value); } } public class ShadyGuyTracker : BaseTracker { public ShadyGuyTracker(float scanIntervalInSeconds) : base(scanIntervalInSeconds) { } protected override object BuildDataPayload() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) List<TrackedObjectDataModel> list = new List<TrackedObjectDataModel>(); if (!BonkersAPI.Game.IsInGame) { return new ApiListResponseModel<TrackedObjectDataModel>(list); } WorldService world = BonkersAPI.World; IEnumerable<InteractableShadyGuy> shadyGuys = world.GetShadyGuys(); foreach (InteractableShadyGuy item in shadyGuys) { CacheIconsForObject(GameObjectUtils.FindMinimapIcon(((Component)item).transform)); TrackedObjectDataModel trackedObjectDataModel = new TrackedObjectDataModel { Position = PositionDataModel.FromVector3(((Component)item).transform.position), InstanceId = ((Object)((Component)item).gameObject).GetInstanceID() }; List<string> list2 = new List<string>(); List<int> list3 = new List<int>(); List<string> list4 = new List<string>(); Enumerator<int> enumerator2 = item.prices.GetEnumerator(); while (enumerator2.MoveNext()) { int current2 = enumerator2.Current; list3.Add(current2); } Enumerator<ItemData> enumerator3 = item.items.GetEnumerator(); while (enumerator3.MoveNext()) { ItemData current3 = enumerator3.Current; list2.Add(((Object)current3).name); EItem eItem = current3.eItem; list4.Add(((object)(EItem)(ref eItem)).ToString().ToLowerInvariant()); } trackedObjectDataModel.CustomProperties["itemNames"] = list2; trackedObjectDataModel.CustomProperties["itemIds"] = list4; trackedObjectDataModel.CustomProperties["itemPrices"] = list3; Dictionary<string, object> customProperties = trackedObjectDataModel.CustomProperties; EItemRarity rarity = item.rarity; customProperties["rarity"] = ((object)(EItemRarity)(ref rarity)).ToString(); list.Add(trackedObjectDataModel); } return new ApiListResponseModel<TrackedObjectDataModel>(list); } } public static class TrackerKeys { public const string Player = "player"; public const string Chests = "chests"; public const string Bosses = "bosses"; public const string ShadyGuys = "shadyGuys"; public const string BossSpawner = "bossSpawner"; public const string Microwaves = "microwaves"; public const string ChargeShrines = "chargeShrines"; public const string GreedShrines = "greedShrines"; public const string MoaiShrines = "moaiShrines"; public const string CursedShrines = "cursedShrines"; public const string MagnetShrines = "magnetShrines"; public const string ChallengeShrines = "challengeShrines"; } } namespace MegaBonkPlusMod.GameLogic.Trackers.Base { public abstract class BasePollingProvider { protected static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions { WriteIndented = false, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }; private readonly float _scanInterval; private volatile string _lastJsonData = "{\"count\":0,\"items\":[]}"; private float _nextScanTime; public BasePollingProvider(float scanIntervalInSeconds) { _scanInterval = scanIntervalInSeconds; } public bool CheckTimer() { if (!BonkersAPI.Game.IsInGame && _scanInterval > 0f) { _lastJsonData = "{\"count\":0,\"items\":[]}"; return false; } if (Time.time < _nextScanTime) { return false; } _nextScanTime = Time.time + _scanInterval; return true; } public virtual void ForceUpdatePayload() { try { object value = BuildDataPayload(); _lastJsonData = JsonSerializer.Serialize(value, JsonOptions); } catch (Exception ex) { ModLogger.LogDebug("Error updating '" + GetType().Name + "': " + ex.Message); _lastJsonData = "{\"count\":0,\"items\":[]}"; OnError(ex); } } public virtual void Update() { if (CheckTimer()) { ForceUpdatePayload(); } } public string GetJsonData() { return _lastJsonData; } protected abstract object BuildDataPayload(); protected virtual void OnError(Exception ex) { } } public abstract class BaseTracker : BasePollingProvider { private readonly List<GameObject> _cachedMinimapIcons = new List<GameObject>(); public int LastKnownCacheCount { get; private set; } public BaseTracker(float scanIntervalInSeconds = 2f) : base(scanIntervalInSeconds) { } protected void CacheIconsForObject(GameObject minimapIcon) { _cachedMinimapIcons.Add(minimapIcon); } public override void ForceUpdatePayload() { _cachedMinimapIcons.Clear(); base.ForceUpdatePayload(); LastKnownCacheCount = _cachedMinimapIcons.Count; } public override void Update() { if (CheckTimer()) { ForceUpdatePayload(); } } public void HideIcons() { foreach (GameObject cachedMinimapIcon in _cachedMinimapIcons) { if (Object.op_Implicit((Object)(object)cachedMinimapIcon) && cachedMinimapIcon.activeSelf) { cachedMinimapIcon.SetActive(false); } } } public void ShowIcons() { foreach (GameObject cachedMinimapIcon in _cachedMinimapIcons) { if (Object.op_Implicit((Object)(object)cachedMinimapIcon)) { cachedMinimapIcon.SetActive(true); } } } public object GetData() { string jsonData = GetJsonData(); if (!string.IsNullOrEmpty(jsonData)) { try { return JsonSerializer.Deserialize<object>(jsonData); } catch { return BuildDataPayload(); } } return BuildDataPayload(); } protected abstract override object BuildDataPayload(); protected override void OnError(Exception ex) { OnTrackerError(ex); } protected virtual void OnTrackerError(Exception ex) { } } } namespace MegaBonkPlusMod.GameLogic.Minimap { public class MinimapStreamer { private const int TARGET_WIDTH = 256; private const int TARGET_HEIGHT = 256; private const string MINIMAP_PATH = "GameUI/Map/FullMapUi/MapRender"; private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions { WriteIndented = false, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }; private volatile string _lastJsonData = "{\"count\":0,\"items\":[]}"; private RawImage _minimapImageComponent; public string GetJsonData() { return _lastJsonData; } public void ClearData() { _lastJsonData = "{\"count\":0,\"items\":[]}"; } private void OnError(Exception ex) { _minimapImageComponent = null; } public void TriggerMinimapUpdate() { Texture2D readableTex = null; try { object value = BuildDataPayload(out readableTex); _lastJsonData = JsonSerializer.Serialize(value, JsonOptions); } catch (Exception ex) { ModLogger.LogError("[MinimapStreamer] FATAL ERROR in TriggerMinimapUpdate: " + ex.Message + "\n" + ex.StackTrace); _lastJsonData = "{\"count\":0,\"items\":[]}"; OnError(ex); } finally { if (Object.op_Implicit((Object)(object)readableTex)) { Object.Destroy((Object)(object)readableTex); } } } private object BuildDataPayload(out Texture2D readableTex) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) readableTex = null; List<TrackedObjectDataModel> list = new List<TrackedObjectDataModel>(); if (!Object.op_Implicit((Object)(object)_minimapImageComponent)) { GameObject val = GameObject.Find("GameUI/Map/FullMapUi/MapRender"); if (!Object.op_Implicit((Object)(object)val)) { ModLogger.LogWarning("[MinimapStreamer] Minimap-GameObject at 'GameUI/Map/FullMapUi/MapRender' NOT found"); return new ApiListResponseModel<TrackedObjectDataModel>(); } _minimapImageComponent = val.GetComponent<RawImage>(); } if (!Object.op_Implicit((Object)(object)((Graphic)_minimapImageComponent).mainTexture)) { return new ApiListResponseModel<TrackedObjectDataModel>(); } readableTex = GetReadableAndScaledTexture(((Graphic)_minimapImageComponent).mainTexture); if (!Object.op_Implicit((Object)(object)readableTex)) { return new ApiListResponseModel<TrackedObjectDataModel>(); } byte[] rawDataFromPixels = GetRawDataFromPixels32(readableTex); if (rawDataFromPixels == null || rawDataFromPixels.Length == 0) { return new ApiListResponseModel<TrackedObjectDataModel>(); } string value = Convert.ToBase64String(rawDataFromPixels); TrackedObjectDataModel trackedObjectDataModel = new TrackedObjectDataModel { Position = PositionDataModel.FromVector3(((Component)_minimapImageComponent).transform.position) }; trackedObjectDataModel.CustomProperties["width"] = ((Texture)readableTex).width; trackedObjectDataModel.CustomProperties["height"] = ((Texture)readableTex).height; trackedObjectDataModel.CustomProperties["format"] = "RGBA32_Raw"; trackedObjectDataModel.CustomProperties["rawPixelData"] = value; list.Add(trackedObjectDataModel); return new ApiListResponseModel<TrackedObjectDataModel>(list); } private Texture2D GetReadableAndScaledTexture(Texture mainTexture) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) RenderTexture val = null; Texture2D val2 = null; try { val = RenderTexture.GetTemporary(256, 256); Graphics.Blit(mainTexture, val); RenderTexture active = RenderTexture.active; RenderTexture.active = val; val2 = new Texture2D(256, 256); val2.ReadPixels(new Rect(0f, 0f, 256f, 256f), 0, 0); val2.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(val); return val2; } catch (Exception ex) { ModLogger.LogDebug("[GetReadableTexture] GPU-Read/Scaling error: " + ex.Message); if (Object.op_Implicit((Object)(object)val)) { RenderTexture.ReleaseTemporary(val); } if (Object.op_Implicit((Object)(object)val2)) { Object.Destroy((Object)(object)val2); } return null; } } private byte[] GetRawDataFromPixels32(Texture2D texture) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) try { Color32[] array = Il2CppArrayBase<Color32>.op_Implicit((Il2CppArrayBase<Color32>)(object)texture.GetPixels32()); if (array == null || array.Length == 0) { return null; } byte[] array2 = new byte[array.Length * 4]; int num = 0; Color32[] array3 = array; foreach (Color32 val in array3) { array2[num++] = val.r; array2[num++] = val.g; array2[num++] = val.b; array2[num++] = byte.MaxValue; } return array2; } catch (Exception ex) { ModLogger.LogDebug("[GetRawDataFromPixels32] Error: " + ex.Message); return null; } } public object GetData() { if (!string.IsNullOrEmpty(_lastJsonData) && _lastJsonData != "{\"count\":0,\"items\":[]}") { try { return JsonSerializer.Deserialize<object>(_lastJsonData); } catch { return null; } } return null; } } } namespace MegaBonkPlusMod.Enums { internal enum LoggingLevelEnum { Info, Debug, Http, Trace } } namespace MegaBonkPlusMod.Core { public static class HotkeyManager { public class HotkeyDefinition { public string Key { get; set; } public string ActionId { get; set; } public JsonElement Payload { get; set; } } private static readonly List<HotkeyDefinition> Hotkeys = new List<HotkeyDefinition>(); private static ConfigEntry<string> _hotkeyConfigEntry; public static bool IsEnabled { get; private set; } = true; public static void Initialize(ConfigFile config) { _hotkeyConfigEntry = config.Bind<string>("Hotkeys", "Configuration", "[]", "Stores the hotkey configuration as a JSON string. Do not edit manually unless you know what you are doing."); LoadConfig(); } private static void LoadConfig() { try { string value = _hotkeyConfigEntry.Value; if (string.IsNullOrWhiteSpace(value) || value == "[]") { ModLogger.LogDebug("[HotkeyManager] No hotkey config found or config is empty, using defaults."); IsEnabled = true; Hotkeys.Clear(); return; } StoredHotkeyConfig storedHotkeyConfig = JsonSerializer.Deserialize<StoredHotkeyConfig>(value); if (storedHotkeyConfig != null) { IsEnabled = storedHotkeyConfig.Enabled; Hotkeys.Clear(); Hotkeys.AddRange(storedHotkeyConfig.Hotkeys ?? new List<HotkeyDefinition>()); ModLogger.LogDebug($"[HotkeyManager] Loaded {Hotkeys.Count} hotkeys from config file."); } } catch (Exception ex) { ModLogger.LogDebug("[HotkeyManager] Error loading hotkey config, resetting to default: " + ex.Message); IsEnabled = true; Hotkeys.Clear(); } } private static void SaveConfig() { try { StoredHotkeyConfig value = new StoredHotkeyConfig { Enabled = IsEnabled, Hotkeys = Hotkeys }; string value2 = JsonSerializer.Serialize(value); _hotkeyConfigEntry.Value = value2; ModLogger.LogDebug("[HotkeyManager] Hotkey config saved."); } catch (Exception ex) { ModLogger.LogDebug("[HotkeyManager] Error saving hotkey config: " + ex.Message); } } public static List<string> UpdateConfig(JsonElement payload) { List<string> list = new List<string>(); try { Dictionary<string, bool> toggleActionsSnapshot = GetToggleActionsSnapshot(Hotkeys); IsEnabled = !payload.TryGetProperty("enabled", out var value) || value.GetBoolean(); Hotkeys.Clear(); if (!payload.TryGetProperty("hotkeys", out var value2) || value2.ValueKind != JsonValueKind.Array) { ModLogger.LogDebug("[HotkeyManager] No hotkeys array in payload."); SaveConfig(); return list; } foreach (JsonElement item in value2.EnumerateArray()) { if (item.TryGetProperty("action", out var value3) && value3.ValueKind != JsonValueKind.Null && item.TryGetProperty("key", out var value4) && value4.ValueKind != JsonValueKind.Null) { string @string = value4.GetString(); string string2 = value3.GetProperty("id").GetString(); JsonElement payload2 = value3.GetProperty("payload").Clone(); Hotkeys.Add(new HotkeyDefinition { Key = @string, ActionId = string2, Payload = payload2 }); } } Dictionary<string, bool> toggleActionsSnapshot2 = GetToggleActionsSnapshot(Hotkeys); foreach (KeyValuePair<string, bool> item2 in toggleActionsSnapshot) { string key = item2.Key; bool value5 = item2.Value; toggleActionsSnapshot2.TryGetValue(key, out var value6); if (value5 && !value6) { list.Add(key); } } ModLogger.LogDebug($"[HotkeyManager] Config updated. {Hotkeys.Count} hotkeys registered."); SaveConfig(); } catch (Exception ex) { ModLogger.LogDebug("[HotkeyManager] Error updating config: " + ex.Message); IsEnabled = true; Hotkeys.Clear(); } return list; } private static Dictionary<string, bool> GetToggleActionsSnapshot(IEnumerable<HotkeyDefinition> hotkeys) { Dictionary<string, bool> dictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); foreach (HotkeyDefinition hotkey in hotkeys) { if (string.IsNullOrEmpty(hotkey.ActionId)) { continue; } bool flag = false; try { if (hotkey.Payload.ValueKind == JsonValueKind.Object && hotkey.Payload.TryGetProperty("mode", out var value) && value.ValueKind == JsonValueKind.String) { string @string = value.GetString(); if (string.Equals(@string, "toggle", StringComparison.OrdinalIgnoreCase)) { flag = true; } } } catch { } if (!dictionary.ContainsKey(hotkey.ActionId)) { dictionary[hotkey.ActionId] = flag; } else { dictionary[hotkey.ActionId] = dictionary[hotkey.ActionId] || flag; } } return dictionary; } public static void CheckKeys(ActionHandler actionHandler) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled || Hotkeys.Count == 0 || !BonkersAPI.Game.IsInGame) { return; } foreach (HotkeyDefinition hotkey in Hotkeys) { if (!Input.GetKeyDown(TranslateJsCodeToUnityKey(hotkey.Key))) { continue; } ModLogger.LogDebug("[HotkeyManager] Hotkey pressed: " + hotkey.Key + " -> " + hotkey.ActionId); try { JsonElement payload = hotkey.Payload.Clone(); if (hotkey.ActionId.Equals("spawn_items", StringComparison.OrdinalIgnoreCase)) { payload = TransformSpawnItemPayload(hotkey.Payload); } actionHandler.HandleAction(hotkey.ActionId, payload); } catch (Exception ex) { ModLogger.LogDebug("[HotkeyManager] Error executing action " + hotkey.ActionId + ": " + ex.Message); } } } private static KeyCode TranslateJsCodeToUnityKey(string jsCode) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (jsCode == "ControlLeft") { jsCode = "LeftControl"; } if (jsCode == "ControlRight") { jsCode = "RightControl"; } if (jsCode == "ShiftLeft") { jsCode = "LeftShift"; } if (jsCode == "ShiftRight") { jsCode = "RightShift"; } if (jsCode == "AltLeft") { jsCode = "LeftAlt"; } if (jsCode == "AltRight") { jsCode = "RightAlt"; } if (Enum.TryParse<KeyCode>(jsCode, ignoreCase: true, out KeyCode result)) { return result; } if (jsCode.StartsWith("Key") && jsCode.Length > 3 && Enum.TryParse<KeyCode>(jsCode.Substring(3), ignoreCase: true, out result)) { return result; } if (jsCode.StartsWith("Digit") && jsCode.Length > 5 && Enum.TryParse<KeyCode>("Alpha" + jsCode.Substring(5), ignoreCase: true, out result)) { return result; } ModLogger.LogDebug("[HotkeyManager] Unmapped key: " + jsCode); return (KeyCode)0; } private static JsonElement TransformSpawnItemPayload(JsonElement flatPayload) { try { string @string = flatPayload.GetProperty("itemId").GetString(); int @int = flatPayload.GetProperty("quantity").GetInt32(); string json = $"\r\n {{\r\n \"items\": [\r\n {{\r\n \"id\": \"{@string}\",\r\n \"quantity\": {@int}\r\n }}\r\n ]\r\n }}"; using JsonDocument jsonDocument = JsonDocument.Parse(json); return jsonDocument.RootElement.Clone(); } catch (Exception ex) { ModLogger.LogDebug("[HotkeyManager] Failed to transform spawn_items payload: " + ex.Message); return JsonDocument.Parse("{}").RootElement; } } public static object GetCurrentConfig() { var hotkeys = Hotkeys.Select((HotkeyDefinition h) => new { key = h.Key, action = new { id = h.ActionId, payload = h.Payload } }).ToList(); return new { enabled = IsEnabled, hotkeys = hotkeys }; } } internal static class ModConfig { public static ConfigEntry<LoggingLevelEnum> LogLevel { get; private set; } public static ConfigEntry<int> WebServerPort { get; private set; } internal static void Initialize(ConfigFile config) { LogLevel = config.Bind<LoggingLevelEnum>("General", "LoggingLevel", LoggingLevelEnum.Info, "Controls log verbosity: Info = only normal logs, Debug = Info + debug, Http = Debug + HTTP, Trace = everything"); WebServerPort = config.Bind<int>("General", "WebServerPort", 8080, "Port for the WebServer"); } } public class ModManager : MonoBehaviour { private ActionHandler _actionHandler; private MinimapCaptureService _minimapCaptureService; private HttpServer _server; private TrackerRegistryService _trackerRegistry; private void Update() { MainThreadActionQueue.ExecuteAll(); _trackerRegistry.UpdateAll(); _actionHandler.UpdateActions(); _minimapCaptureService.Update(); } private void OnDestroy() { ModLogger.LogDebug("Object destroyed, stopping HttpServer…"); BonkersAPI.Game.GameStarted -= OnGameStarted; _server?.Stop(); } private void OnApplicationQuit() { ModLogger.LogDebug("Application quitting, stopping HttpServer…"); BonkersAPI.Game.GameStarted -= OnGameStarted; _server?.Stop(); } public void Initialize() { ModLogger.LogDebug("ModManager initializing..."); _trackerRegistry = new TrackerRegistryService(); _trackerRegistry.RegisterDefaultTrackers(); MinimapStreamer minimapStreamer = new MinimapStreamer(); _minimapCaptureService = new MinimapCaptureService(_trackerRegistry.TrackersList, minimapStreamer); _actionHandler = new ActionHandler(); ControllerRouter controllerRouter = new ControllerRouter(); controllerRouter.RegisterControllers(new ItemController(), new HotkeyController(_actionHandler), new ActionController(_actionHandler), new TrackerController(_trackerRegistry.TrackersDictionary), new MinimapController(minimapStreamer), new GameStateController(), new InventoryController()); _server = new HttpServer(controllerRouter); _server.Start(); BonkersAPI.Game.GameStarted += OnGameStarted; ModLogger.LogDebug("ModManager initialized."); } private void OnGameStarted() { ModLogger.LogDebug("New run detected, starting minimap capture..."); _minimapCaptureService.StartCapture(); _actionHandler.StopAllLoopingActions(); } } [BepInPlugin("com.kss.megabonkplus", "MegaBonkPlus", "0.9.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BasePlugin { public override void Load() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, "com.kss.megabonkplus.cfg"); ConfigFile config = new ConfigFile(text, true); ModConfig.Initialize(config); ModLogger.InitLog(((BasePlugin)this).Log); HotkeyManager.Initialize(config); ClassInjector.RegisterTypeInIl2Cpp<ModManager>(); GameObject val = new GameObject("MegaBonkPlus"); ModManager modManager = val.AddComponent<ModManager>(); modManager.Initialize(); Object.DontDestroyOnLoad((Object)(object)val); ModLogger.LogInfo("MegaBonkPlus Initialized"); ModLogger.LogInfo($"Logging-Level: {ModConfig.LogLevel.Value}"); } } public static class PluginInfo { public const string PLUGIN_GUID = "com.kss.megabonkplus"; public const string PLUGIN_NAME = "MegaBonkPlus"; public const string PLUGIN_VERSION = "0.9.4"; } } namespace MegaBonkPlusMod.Config { internal class StoredHotkeyConfig { public bool Enabled { get; set; } public List<HotkeyManager.HotkeyDefinition> Hotkeys { get; set; } } } namespace MegaBonkPlusMod.Actions.Teleport { public class TeleportAction : IAction { public string Execute(JsonElement payload, ActionHandler handler) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (!payload.TryGetProperty("instanceId", out var value) || value.ValueKind != JsonValueKind.Number) { ModLogger.LogDebug("[TeleportAction] failed: 'instanceId' missing in Payload"); return "Error: 'instanceId' missing"; } int instanceId = value.GetInt32(); Il2CppArrayBase<GameObject> source = Resources.FindObjectsOfTypeAll<GameObject>(); GameObject val = ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => ((Object)g).GetInstanceID() == instanceId)); if (!Object.op_Implicit((Object)(object)val)) { ModLogger.LogDebug($"[TeleportAction] failed: ObjectID {instanceId} not found"); return "Error: Object not found"; } ModLogger.LogDebug("[TeleportAction] Starting Teleport-Job to " + ((Object)val).name + "..."); Vector3 position = val.transform.position; BonkersAPI.Player.TeleportTo(position); return "Teleport successful"; } } public class TeleportToNearestAction : IAction { public string Execute(JsonElement payload, ActionHandler actionHandler) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_04e6: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) if (!payload.TryGetProperty("object", out var value)) { ModLogger.LogDebug("[TeleportToNearest] failed: 'object' missing in Payload"); return "Error: 'object' missing"; } if (!BonkersAPI.Game.IsInGame) { return "Cannot teleport: Not in game"; } string @string = value.GetString(); Vector3 zero = Vector3.zero; switch (@string) { case "chest": zero = (Vector3)(((??)BonkersAPI.World.GetNearestChest()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "charge_shrine": zero = (Vector3)(((??)BonkersAPI.World.GetNearestChargeShrine()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "shady_guy": zero = (Vector3)(((??)BonkersAPI.World.GetNearestShadyGuy()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "boss_spawner": zero = (Vector3)(((??)BonkersAPI.World.GetNearestBossSpawner()) ?? ((??)BonkersAPI.World.GetNearestBossSpawnerFinal()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "moai_shrine": zero = (Vector3)(((??)BonkersAPI.World.GetNearestMoaiShrine()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "challenge_shrine": zero = (Vector3)(((??)BonkersAPI.World.GetNearestChallengeShrine()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "cursed_shrine": zero = (Vector3)(((??)BonkersAPI.World.GetNearestCursedShrine()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "greed_shrine": zero = (Vector3)(((??)BonkersAPI.World.GetNearestGreedShrine()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "magnet_shrine": zero = (Vector3)(((??)BonkersAPI.World.GetNearestMagnetShrine()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "microwave": zero = (Vector3)(((??)BonkersAPI.World.GetNearestMicrowave()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; case "open_chest": zero = (Vector3)(((??)BonkersAPI.World.GetNearestOpenChest()) ?? zero); if (zero != Vector3.zero) { BonkersAPI.Player.TeleportTo(zero); } break; default: return "Error: Unknown teleport target '" + @string + "'"; } return "Teleport successful"; } } } namespace MegaBonkPlusMod.Actions.Inventory { public class TomeAction : IAction { public string Execute(JsonElement payload, ActionHandler actionHandler) { //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if (!BonkersAPI.Game.IsInGame) { return "Cannot modify tomes: Not in game"; } TomeService tome = BonkersAPI.Tome; if (((tome != null) ? tome.TomeInventory : null) == null) { return "Tome service or inventory not available"; } if (!payload.TryGetProperty("mode", out var value) || value.ValueKind != JsonValueKind.String) { return "Error: 'mode' is required"; } string text = value.GetString()?.Trim().ToLowerInvariant(); if (string.IsNullOrEmpty(text)) { return "Error: 'mode' is empty"; } if (!payload.TryGetProperty("tome", out var value2) || value2.ValueKind != JsonValueKind.String) { return "Error: 'tome' (ETome name) is required"; } string @string = value2.GetString(); if (string.IsNullOrWhiteSpace(@string)) { return "Error: 'tome' is empty"; } if (!Enum.TryParse<ETome>(@string, ignoreCase: true, out ETome result)) { return "Error: Unknown tome '" + @string + "'"; } switch (text) { case "add": return HandleAddTome(payload, result); case "remove": case "removetome": return HandleRemoveTome(result); default: return "Error: Unknown mode '" + text + "' (expected 'add' or 'remove')"; } } private string HandleAddTome(JsonElement payload, ETome eTome) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) string text = "random"; if (payload.TryGetProperty("upgrade", out var value) && value.ValueKind == JsonValueKind.Object) { if (value.TryGetProperty("mode", out var value2) && value2.ValueKind == JsonValueKind.String) { text = value2.GetString()?.Trim().ToLowerInvariant() ?? "random"; } } else { text = "random"; value = default(JsonElement); } string text2 = text; string text3 = text2; if (!(text3 == "random")) { if (text3 == "custom") { return AddTomeWithCustomStats(eTome, value); } BonkersAPI.Tome.AddTome(eTome); ModLogger.LogDebug($"[TomeAction] Added tome {eTome} with default AddTome behavior"); return $"Added or upgraded tome '{eTome}' (default behavior)"; } return AddTomeWithRandomUpgrades(eTome, value); } private string AddTomeWithRandomUpgrades(ETome eTome, JsonElement upgradeElement) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) ERarity val = (ERarity)0; if (upgradeElement.ValueKind == JsonValueKind.Object && upgradeElement.TryGetProperty("rarity", out var value) && value.ValueKind == JsonValueKind.String) { string @string = value.GetString(); if (!string.IsNullOrWhiteSpace(@string) && Enum.TryParse<ERarity>(@string, ignoreCase: true, out ERarity result)) { val = result; } } Dictionary<ETome, StatModifier> currentTomes = BonkersAPI.Tome.CurrentTomes; StatModifier val2 = default(StatModifier); if (currentTomes == null || !currentTomes.TryGetValue(eTome, ref val2) || val2 == null) { BonkersAPI.Tome.AddTome(eTome); return $"Added '{eTome}' Tome"; } if (BonkersAPI.Tome.GetTomeLevel(eTome) < 99) { BonkersAPI.Tome.UpgradeWithRandomStats(eTome, val); ModLogger.LogDebug($"[TomeAction] Added / upgraded tome {eTome} with random upgrades (rarity={val})"); return $"Upgraded '{eTome}' Tome {val}"; } return $"Error: Cannot upgrade tome {eTome} (already at max level)"; } private string AddTomeWithCustomStats(ETome eTome, JsonElement upgradeElement) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) if (upgradeElement.ValueKind != JsonValueKind.Object || !upgradeElement.TryGetProperty("stats", out var value) || value.ValueKind != JsonValueKind.Array) { return "Error: For upgrade.mode='custom' you must provide 'upgrade.stats' as an array"; } List<StatModifier> val = new List<StatModifier>(); foreach (JsonElement item in value.EnumerateArray()) { if (item.ValueKind == JsonValueKind.Object) { StatModifier val2 = TryCreateStatModifierFromJson(item); if (val2 != null) { val.Add(val2); } if (val.Count >= 4) { break; } } } if (val.Count == 0) { return "Error: No valid custom stat modifiers provided (or all invalid)"; } TomeData tomeDataFromEnum = BonkersAPI.Tome.GetTomeDataFromEnum(eTome); BonkersAPI.Tome.AddTomeWithStats(tomeDataFromEnum, val, (ERarity)5); ModLogger.LogDebug($"[TomeAction] Added tome {eTome} with {val.Count} custom stat modifiers"); return $"Added tome '{eTome}' with {val.Count} custom stat modifiers"; } private string HandleRemoveTome(ETome eTome) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) Dictionary<ETome, StatModifier> currentTomes = BonkersAPI.Tome.CurrentTomes; if (currentTomes != null && currentTomes.ContainsKey(eTome)) { if (BonkersAPI.Tome.RemoveTome(eTome)) { ModLogger.LogDebug($"[TomeAction] Removed tome {eTome}"); return $"Removed tome '{eTome}'"; } return $"Error: Failed to remove tome '{eTome}'"; } return $"Error: Tome '{eTome}' not in inventory"; } private StatModifier TryCreateStatModifierFromJson(JsonElement statJson) { //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown try { string text = null; string text2 = null; float modification = 0f; if (statJson.TryGetProperty("stat", out var value) && value.ValueKind == JsonValueKind.String) { text = value.GetString(); } if (statJson.TryGetProperty("operation", out var value2) && value2.ValueKind == JsonValueKind.String) { text2 = value2.GetString(); } if (statJson.TryGetProperty("value", out var value3)) { float result; if (value3.ValueKind == JsonValueKind.Number) { modification = value3.GetSingle(); } else if (value3.ValueKind == JsonValueKind.String && float.TryParse(value3.GetString(), out result)) { modification = result; } } if (string.IsNullOrWhiteSpace(text)) { ModLogger.LogDebug("[TomeAction] StatModifier missing 'stat' field"); return null; } if (string.IsNullOrWhiteSpace(text2)) { ModLogger.LogDebug("[TomeAction] StatModifier missing 'operation' field"); return null; } if (!Enum.TryParse<EStat>(text, ignoreCase: true, out EStat result2)) { ModLogger.LogDebug("[TomeAction] Unknown EStat '" + text + "'"); return null; } if (!Enum.TryParse<EStatModifyType>(text2, ignoreCase: true, out EStatModifyType result3)) { ModLogger.LogDebug("[TomeAction] Unknown EStatModifyType '" + text2 + "'"); return null; } return new StatModifier { stat = result2, modifyType = result3, modification = modification }; } catch (Exception ex) { ModLogger.LogDebug("[TomeAction] Failed to parse StatModifier from json: " + ex.Message); return null; } } } public class WeaponAction : IAction { public string Execute(JsonElement payload, ActionHandler actionHandler) { //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) if (!BonkersAPI.Game.IsInGame) { return "Cannot modify weapons: Not in game"; } WeaponService weapon = BonkersAPI.Weapon; if (((weapon != null) ? weapon.WeaponInventory : null) == null) { return "Weapon service or inventory not available"; } if (!payload.TryGetProperty("mode", out var value) || value.ValueKind != JsonValueKind.String) { return "Error: 'mode' is required"; } string text = value.GetString()?.Trim().ToLowerInvariant(); if (string.IsNullOrEmpty(text)) { return "Error: 'mode' is empty"; } if (!payload.TryGetProperty("weapon", out var value2) || value2.ValueKind != JsonValueKind.String) { return "Error: 'weapon' (EWeapon name) is required"; } string @string = value2.GetString(); if (string.IsNullOrWhiteSpace(@string)) { return "Error: 'weapon' is empty"; } if (!Enum.TryParse<EWeapon>(@string, ignoreCase: true, out EWeapon result)) { return "Error: Unknown weapon '" + @string + "'"; } switch (text) { case "add": return HandleAddWeapon(payload, result); case "remove": case "removeweapon": return HandleRemoveWeapon(result); case "downgrade": case "downgradeweapon": return HandleDowngradeWeapon(result); case "clear": case "clearupgrades": return HandleClearWeaponUpgrades(result); case "options": return GetWeaponUpgradeOptions(result); default: return "Error: Unknown mode '" + text + "' (expected 'add', 'remove', 'downgrade', 'clear' or 'options')"; } } private string HandleAddWeapon(JsonElement payload, EWeapon eWeapon) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) string text = "random"; if (payload.TryGetProperty("upgrade", out var value) && value.ValueKind == JsonValueKind.Object) { if (value.TryGetProperty("mode", out var value2) && value2.ValueKind == JsonValueKind.String) { text = value2.GetString()?.Trim().ToLowerInvariant() ?? "random"; } } else { text = "random"; value = default(JsonElement); } string text2 = text; string text3 = text2; if (!(text3 == "random")) { if (text3 == "custom") { return AddWeaponWithCustomStats(eWeapon, value); } BonkersAPI.Weapon.AddWeapon(eWeapon); ModLogger.LogDebug($"[WeaponAction] Added weapon {eWeapon} with default AddWeapon behavior"); return $"Added or upgraded weapon '{eWeapon}' (default behavior)"; } return AddWeaponWithRandomUpgrades(eWeapon, value); } private string AddWeaponWithRandomUpgrades(EWeapon eWeapon, JsonElement upgradeElement) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) ERarity val = (ERarity)0; if (upgradeElement.ValueKind == JsonValueKind.Object && upgradeElement.TryGetProperty("rarity", out var value) && value.ValueKind == JsonValueKind.String) { string @string = value.GetString(); if (!string.IsNullOrWhiteSpace(@string) && Enum.TryParse<ERarity>(@string, ignoreCase: true, out ERarity result)) { val = result; } } Dictionary<EWeapon, WeaponBase> currentWeapons = BonkersAPI.Weapon.CurrentWeapons; WeaponBase val2 = default(WeaponBase); if (currentWeapons == null || !currentWeapons.TryGetValue(eWeapon, ref val2) || val2 == null) { BonkersAPI.Weapon.AddWeapon(eWeapon); return $"Added '{eWeapon}'"; } WeaponBase val3 = default(WeaponBase); if (currentWeapons != null && currentWeapons.TryGetValue(eWeapon, ref val3) && val3 != null) { BonkersAPI.Weapon.UpgradeWithRandomStats(val3, val); ModLogger.LogDebug($"[WeaponAction] Upgraded weapon {eWeapon} with random upgrades (rarity={val})"); return $"Upgraded '{eWeapon}' {val}"; } return $"Error: Failed to add or retrieve weapon '{eWeapon}'"; } private string AddWeaponWithCustomStats(EWeapon eWeapon, JsonElement upgradeElement) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (upgradeElement.ValueKind != JsonValueKind.Object || !upgradeElement.TryGetProperty("stats", out var value) || value.ValueKind != JsonValueK