Decompiled source of MegaBonkPlus v0.9.4

MegaBonkPlusMod.dll

Decompiled 2 weeks ago
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