Decompiled source of BonkersLib v1.0.4

BonkersLib.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.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Assets.Scripts.Actors.Enemies;
using Assets.Scripts.Actors.Player;
using Assets.Scripts.Game.Other;
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.Upgrades;
using Assets.Scripts.Inventory__Items__Pickups.Weapons;
using Assets.Scripts.Managers;
using Assets.Scripts.Menu.Shop;
using Assets.Scripts.Saves___Serialization.Progression.Achievements;
using Assets.Scripts.Saves___Serialization.Progression.Unlocks;
using Assets.Scripts._Data.Tomes;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BonkersLib.Core;
using BonkersLib.Enums;
using BonkersLib.Services;
using BonkersLib.Services.Player;
using BonkersLib.Services.World;
using BonkersLib.Utils;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Inventory__Items__Pickups.Xp_and_Levels;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

[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("BonkersLib")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BonkersLib")]
[assembly: AssemblyTitle("BonkersLib")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BonkersLib.Utils
{
	public static class CollectionExtensions
	{
		public static Dictionary<TKey, TValue> ToSafeCopy<TKey, TValue>(this Dictionary<TKey, TValue> source)
		{
			Dictionary<TKey, TValue> val = new Dictionary<TKey, TValue>();
			if (source == null)
			{
				return val;
			}
			Enumerator<TKey, TValue> enumerator = source.GetEnumerator();
			while (enumerator.MoveNext())
			{
				KeyValuePair<TKey, TValue> current = enumerator.Current;
				if (!val.ContainsKey(current.Key))
				{
					val.Add(current.Key, current.Value);
				}
			}
			return val;
		}
	}
	public class GameObjectUtils
	{
		public static GameObject FindMinimapIcon(Transform objTransform)
		{
			if (!Object.op_Implicit((Object)(object)objTransform))
			{
				return null;
			}
			Transform root = objTransform.root;
			Il2CppArrayBase<Transform> componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform item in componentsInChildren)
			{
				if (((Object)item).name.StartsWith("MinimapIcon"))
				{
					return ((Component)item).gameObject;
				}
			}
			return null;
		}
	}
	internal static class ModLogger
	{
		private static ManualLogSource _modLogger;

		public static void InitLog(ManualLogSource logger)
		{
			_modLogger = logger;
		}

		public static void LogDebug(string message)
		{
			if (ModConfig.IsDebugLoggingEnabled.Value)
			{
				LogInfo(message);
			}
		}

		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 BonkersLib.Services
{
	public class AchievementService
	{
		public Dictionary<string, MyAchievement> AllAchievements => BonkersAPI.Data.AchievementData;

		public void UnlockAll()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				Dictionary<string, MyAchievement> allAchievements = AllAchievements;
				if (allAchievements != null)
				{
					Enumerator<string, MyAchievement> enumerator = allAchievements.GetEnumerator();
					while (enumerator.MoveNext())
					{
						KeyValuePair<string, MyAchievement> current = enumerator.Current;
						MyAchievements.TryUnlock(current.Key);
					}
					ModLogger.LogDebug("Unlocked all achievements!");
				}
			});
		}
	}
	public class DataService
	{
		public DataManager CurrentDataManager { get; private set; }

		public Dictionary<EItem, ItemData> ItemData => MainThreadDispatcher.Evaluate(delegate
		{
			DataManager currentDataManager = CurrentDataManager;
			return (currentDataManager != null) ? currentDataManager.itemData.ToSafeCopy<EItem, ItemData>() : null;
		});

		public Dictionary<EWeapon, WeaponData> WeaponData => MainThreadDispatcher.Evaluate(delegate
		{
			DataManager currentDataManager = CurrentDataManager;
			return (currentDataManager != null) ? currentDataManager.weapons.ToSafeCopy<EWeapon, WeaponData>() : null;
		});

		public Dictionary<ETome, TomeData> TomeData => MainThreadDispatcher.Evaluate(delegate
		{
			DataManager currentDataManager = CurrentDataManager;
			return (currentDataManager != null) ? currentDataManager.tomeData.ToSafeCopy<ETome, TomeData>() : null;
		});

		public Dictionary<ECharacter, CharacterData> CharacterData => MainThreadDispatcher.Evaluate(delegate
		{
			DataManager currentDataManager = CurrentDataManager;
			return (currentDataManager != null) ? currentDataManager.characterData.ToSafeCopy<ECharacter, CharacterData>() : null;
		});

		public Dictionary<string, MyAchievement> AchievementData => MainThreadDispatcher.Evaluate(delegate
		{
			DataManager currentDataManager = CurrentDataManager;
			return (currentDataManager != null) ? currentDataManager.achievementsData.ToSafeCopy<string, MyAchievement>() : null;
		});

		internal void SetDataManager()
		{
			CurrentDataManager = AlwaysManager.Instance.dataManager;
		}
	}
	public class GameStateService
	{
		private const float TIMEOUT_WORLD_LOAD_DELAY = 2f;

		private const float DELAY_AFTER_FOUND = 0.5f;

		private float _worldLoadTimer;

		private bool _shrinesDetected;

		private float _delayAfterFoundTimer;

		private bool _isTimeScaleLocked;

		private float _targetTimeScale = 1f;

		private GameManager _gameManagerInstance;

		private EnemyManager _enemyManagerInstance;

		private PickupManager _pickupManagerInstance;

		private RunConfig _currentRunConfig;

		public GameManager GameManagerInstance => MainThreadDispatcher.Evaluate(() => _gameManagerInstance);

		public EnemyManager EnemyManagerInstance => MainThreadDispatcher.Evaluate(() => _enemyManagerInstance);

		public PickupManager PickupManagerInstance => MainThreadDispatcher.Evaluate(() => _pickupManagerInstance);

		public MyPlayer PlayerController => MainThreadDispatcher.Evaluate(delegate
		{
			GameManager gameManagerInstance = _gameManagerInstance;
			return (gameManagerInstance != null) ? gameManagerInstance.player : null;
		});

		public GameStateEnum CurrentStateEnum { get; private set; }

		public bool IsInGame => MainThreadDispatcher.Evaluate(() => CurrentStateEnum == GameStateEnum.InGame);

		public RunConfig CurrentRunConfig => MainThreadDispatcher.Evaluate(() => _currentRunConfig);

		public MapData CurrentMapData => MainThreadDispatcher.Evaluate(delegate
		{
			RunConfig currentRunConfig = _currentRunConfig;
			return (currentRunConfig != null) ? currentRunConfig.mapData : null;
		});

		public float StageTime => MainThreadDispatcher.Evaluate(delegate
		{
			GameManager gameManagerInstance = _gameManagerInstance;
			return (gameManagerInstance != null) ? gameManagerInstance.lastFoundStageTime : 0f;
		});

		public float TimeAlive => MainThreadDispatcher.Evaluate(delegate
		{
			GameManager gameManagerInstance = _gameManagerInstance;
			return (gameManagerInstance != null) ? gameManagerInstance.GetAliveTime() : 0f;
		});

		public int BossCurses => MainThreadDispatcher.Evaluate(delegate
		{
			GameManager gameManagerInstance = _gameManagerInstance;
			return (gameManagerInstance != null) ? gameManagerInstance.bossCurses : 0;
		});

		public int StageTier => MainThreadDispatcher.Evaluate(delegate
		{
			RunConfig currentRunConfig = _currentRunConfig;
			return (currentRunConfig != null) ? (currentRunConfig.mapTierIndex + 1) : (-1);
		});

		public string StageName => MainThreadDispatcher.Evaluate(delegate
		{
			MapData currentMapData = CurrentMapData;
			return ((currentMapData != null) ? ((UnlockableBase)currentMapData).GetName() : null) ?? "N/A";
		});

		public float CurrentTimeScale => MainThreadDispatcher.Evaluate(() => Time.timeScale);

		public event Action GameStarted;

		public event Action SceneChanged;

		public GameStateService()
		{
			CurrentStateEnum = GameStateEnum.MainMenu;
		}

		public void RestartRun()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				MapController.RestartRun();
				ModLogger.LogDebug("[GameStateService] Restart run requested");
			});
		}

		internal void Update()
		{
			if (_isTimeScaleLocked)
			{
				ApplyTimeScale(_targetTimeScale);
			}
			switch (CurrentStateEnum)
			{
			case GameStateEnum.Loading:
				HandleLoadingState();
				break;
			case GameStateEnum.WaitingForWorldLoad:
				HandleWaitingForWorldLoadState();
				break;
			}
		}

		private void HandleLoadingState()
		{
			if (!Object.op_Implicit((Object)(object)_gameManagerInstance))
			{
				_gameManagerInstance = Object.FindObjectOfType<GameManager>();
			}
			if (Object.op_Implicit((Object)(object)_gameManagerInstance) && Object.op_Implicit((Object)(object)_gameManagerInstance.player))
			{
				ModLogger.LogDebug("[GameStateService] Found GameManager and Player, waiting for world objects to spawn...");
				_enemyManagerInstance = Object.FindObjectOfType<EnemyManager>();
				_pickupManagerInstance = Object.FindObjectOfType<PickupManager>();
				_currentRunConfig = MapController.runConfig;
				CurrentStateEnum = GameStateEnum.WaitingForWorldLoad;
				_worldLoadTimer = 2f;
				_shrinesDetected = false;
				_delayAfterFoundTimer = 0f;
			}
		}

		private void HandleWaitingForWorldLoadState()
		{
			if (!_shrinesDetected && HasWorldStartedBasedOnShrines())
			{
				_shrinesDetected = true;
				_delayAfterFoundTimer = 0.5f;
				ModLogger.LogDebug($"[GameStateService] Shrine detected, waiting additional {0.5f:0.00}s before starting game");
			}
			if (_shrinesDetected)
			{
				_delayAfterFoundTimer -= Time.unscaledDeltaTime;
				if (_delayAfterFoundTimer <= 0f)
				{
					SwitchToInGame("Detected shrines and post-delay elapsed");
					return;
				}
			}
			_worldLoadTimer -= Time.unscaledDeltaTime;
			if (_worldLoadTimer <= 0f)
			{
				ModLogger.LogDebug("[GameStateService] World load timeout reached, switching to InGame state anyway");
				SwitchToInGame("Timeout reached");
			}
		}

		internal void OnSceneChanged(Scene scene)
		{
			ModLogger.LogDebug("[GameStateService] Scene changed: " + ((Scene)(ref scene)).name);
			if (((Scene)(ref scene)).name == "MainMenu")
			{
				CurrentStateEnum = GameStateEnum.MainMenu;
				ClearGameInstances();
				BonkersAPI.World.OnSceneChanged();
				this.SceneChanged?.Invoke();
			}
			else
			{
				CurrentStateEnum = GameStateEnum.Loading;
				ClearGameInstances();
				BonkersAPI.World.OnSceneChanged();
			}
			SetTimeScale(1f, lockValue: true);
		}

		private bool HasWorldStartedBasedOnShrines()
		{
			InteractableShrineGreed val = Object.FindObjectOfType<InteractableShrineGreed>(true);
			InteractableShrineMagnet val2 = Object.FindObjectOfType<InteractableShrineMagnet>(true);
			InteractableShrineCursed val3 = Object.FindObjectOfType<InteractableShrineCursed>(true);
			return Object.op_Implicit((Object)(object)val) || Object.op_Implicit((Object)(object)val2) || Object.op_Implicit((Object)(object)val3);
		}

		private void SwitchToInGame(string reason)
		{
			ModLogger.LogDebug("[GameStateService] World load complete (" + reason + "), switching to InGame state");
			CurrentStateEnum = GameStateEnum.InGame;
			BonkersAPI.World.OnGameStarted();
			this.GameStarted?.Invoke();
		}

		private void ClearGameInstances()
		{
			_gameManagerInstance = null;
			_enemyManagerInstance = null;
			_currentRunConfig = null;
			_pickupManagerInstance = null;
			_worldLoadTimer = 0f;
			_shrinesDetected = false;
			_delayAfterFoundTimer = 0f;
		}

		public void SetTimeScale(float newScale, bool lockValue = false)
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (newScale < 0f)
				{
					newScale = 0f;
				}
				_targetTimeScale = newScale;
				_isTimeScaleLocked = lockValue;
				ApplyTimeScale(newScale);
				ModLogger.LogDebug($"[GameStateService] TimeScale set to: {newScale} (Locked: {lockValue})");
			});
		}

		public void UnlockTimeScale()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				_isTimeScaleLocked = false;
				ModLogger.LogDebug("[GameStateService] TimeScale Lock removed.");
			});
		}

		private void ApplyTimeScale(float scale)
		{
			if (Math.Abs(Time.timeScale - scale) > 0.001f)
			{
				Time.timeScale = scale;
				Time.fixedDeltaTime = 0.02f * scale;
			}
		}
	}
	public class PlayerService
	{
		private const float SAFE_RANGE = 15f;

		private const float Y_OFFSET = 10f;

		private Vector3 _teleportTarget;

		private bool _tryingToTeleport;

		private MyPlayer _player => BonkersAPI.Game.PlayerController;

		public string CharacterName => MainThreadDispatcher.Evaluate(delegate
		{
			//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)
			object result;
			if (!Object.op_Implicit((Object)(object)_player))
			{
				result = "N/A";
			}
			else
			{
				ECharacter character = _player.character;
				result = ((object)(ECharacter)(ref character)).ToString();
			}
			return (string)result;
		});

		public Vector3 Position => MainThreadDispatcher.Evaluate(() => Object.op_Implicit((Object)(object)_player) ? ((Component)_player.feet).transform.position : Vector3.zero);

		public int InstanceId => MainThreadDispatcher.Evaluate(() => Object.op_Implicit((Object)(object)_player) ? ((Object)((Component)_player).gameObject).GetInstanceID() : (-1));

		public GameObject GameObject => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			return (player != null) ? ((Component)player).gameObject : null;
		});

		public PlayerInventory Inventory => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			return (player != null) ? player.inventory : null;
		});

		public PlayerHealth PlayerHealth => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			object result;
			if (player == null)
			{
				result = null;
			}
			else
			{
				PlayerInventory inventory = player.inventory;
				result = ((inventory != null) ? inventory.playerHealth : null);
			}
			return (PlayerHealth)result;
		});

		public PlayerXp PlayerXp => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			object result;
			if (player == null)
			{
				result = null;
			}
			else
			{
				PlayerInventory inventory = player.inventory;
				result = ((inventory != null) ? inventory.playerXp : null);
			}
			return (PlayerXp)result;
		});

		public PlayerStatsNew Stats => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			object result;
			if (player == null)
			{
				result = null;
			}
			else
			{
				PlayerInventory inventory = player.inventory;
				result = ((inventory != null) ? inventory.playerStats : null);
			}
			return (PlayerStatsNew)result;
		});

		public Dictionary<EStat, float> StatsDict => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			object result;
			if (player == null)
			{
				result = null;
			}
			else
			{
				PlayerInventory inventory = player.inventory;
				if (inventory == null)
				{
					result = null;
				}
				else
				{
					PlayerStatsNew playerStats = inventory.playerStats;
					result = ((playerStats != null) ? playerStats.stats.ToSafeCopy<EStat, float>() : null);
				}
			}
			return (Dictionary<EStat, float>)result;
		});

		public Dictionary<EStat, float> RawStatsDict => MainThreadDispatcher.Evaluate(delegate
		{
			MyPlayer player = _player;
			object result;
			if (player == null)
			{
				result = null;
			}
			else
			{
				PlayerInventory inventory = player.inventory;
				if (inventory == null)
				{
					result = null;
				}
				else
				{
					PlayerStatsNew playerStats = inventory.playerStats;
					result = ((playerStats != null) ? playerStats.rawStats.ToSafeCopy<EStat, float>() : null);
				}
			}
			return (Dictionary<EStat, float>)result;
		});

		public int Health => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerHealth playerHealth = PlayerHealth;
			return (playerHealth != null) ? playerHealth.hp : 0;
		});

		public int MaxHealth => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerHealth playerHealth = PlayerHealth;
			return (playerHealth != null) ? playerHealth.maxHp : 0;
		});

		public float Shield => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerHealth playerHealth = PlayerHealth;
			return (playerHealth != null) ? playerHealth.shield : 0f;
		});

		public float MaxShield => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerHealth playerHealth = PlayerHealth;
			return (playerHealth != null) ? playerHealth.maxShield : 0f;
		});

		public float Gold => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerInventory inventory = Inventory;
			return (inventory != null) ? inventory.gold : 0f;
		});

		public int Level => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerInventory inventory = Inventory;
			return (inventory != null) ? inventory.GetCharacterLevel() : 0;
		});

		internal PlayerService()
		{
		}

		internal void Update()
		{
			if (BonkersAPI.Game.IsInGame && _tryingToTeleport)
			{
				TryToTeleport();
			}
		}

		private void TryToTeleport()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_player))
			{
				float num = Vector3.Distance(((Component)_player).transform.position, _teleportTarget);
				if (num <= 15f)
				{
					_tryingToTeleport = false;
					ModLogger.LogDebug("[PlayerService] Teleport completed/arrived");
				}
				else
				{
					((Component)_player).transform.position = _teleportTarget;
				}
			}
		}

		public void TeleportTo(Vector3 targetPosition)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: 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)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				if (BonkersAPI.Game.IsInGame)
				{
					_teleportTarget = targetPosition + new Vector3(0f, 10f, 0f);
					_tryingToTeleport = true;
					ModLogger.LogDebug($"[PlayerService] Starting teleport to {_teleportTarget} from {((Component)_player).transform.position}");
				}
			});
		}

		public void GiveGold(int amount)
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (BonkersAPI.Game.IsInGame)
				{
					MyPlayer player = _player;
					if (player != null)
					{
						PlayerInventory inventory = player.inventory;
						if (inventory != null)
						{
							inventory.ChangeGold(amount);
						}
					}
					ModLogger.LogDebug($"[PlayerService] Gave {amount} gold to player");
				}
			});
		}

		public void SetGold(int amount)
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (BonkersAPI.Game.IsInGame)
				{
					MyPlayer player = _player;
					if (((player != null) ? player.inventory : null) != null)
					{
						_player.inventory.gold = amount;
						BonkersAPI.Ui.RefreshUi();
						ModLogger.LogDebug($"[PlayerService] Set gold to {amount}");
					}
				}
			});
		}

		public void AddLevel(int amount)
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (BonkersAPI.Game.IsInGame)
				{
					MyPlayer player = _player;
					if (((player != null) ? player.inventory : null) != null)
					{
						for (int i = 0; i < amount; i++)
						{
							_player.inventory.AddLevel();
						}
						ModLogger.LogDebug($"[PlayerService] Added {amount} Levels to player");
					}
				}
			});
		}

		public void GiveItem(string itemId, int quantity)
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				if (BonkersAPI.Game.IsInGame)
				{
					MyPlayer player = _player;
					if (((player != null) ? player.inventory : null) != null)
					{
						ItemData val = ((IEnumerable<ItemData>)BonkersAPI.Item.GetAllRawItems()).FirstOrDefault((Func<ItemData, bool>)delegate(ItemData item)
						{
							//IL_0001: Unknown result type (might be due to invalid IL or missing references)
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							EItem eItem = item.eItem;
							return string.Equals(((object)(EItem)(ref eItem)).ToString(), itemId, StringComparison.OrdinalIgnoreCase);
						});
						if (Object.op_Implicit((Object)(object)val))
						{
							_player.inventory.itemInventory.AddItem(val.eItem, quantity);
							ModLogger.LogDebug($"[PlayerService] Gave Player Item: {quantity}x {itemId}");
						}
						else
						{
							ModLogger.LogDebug("[PlayerService] Item-ID '" + itemId + "' could not be found");
						}
					}
				}
			});
		}

		public void PickUpAllXp()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (BonkersAPI.Game.IsInGame)
				{
					PickupManager pickupManagerInstance = BonkersAPI.Game.PickupManagerInstance;
					if (pickupManagerInstance != null)
					{
						pickupManagerInstance.PickupAllXp();
					}
					ModLogger.LogDebug("[PlayerService] Picked up all XP");
				}
			});
		}
	}
	public class UiService
	{
		private InventoryHud _inventoryHud;

		private KillsAndGoldCounter _xpAndGoldCounter;

		public void RefreshUi()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (Object.op_Implicit((Object)(object)_inventoryHud))
				{
					_inventoryHud.Refresh();
				}
				if (Object.op_Implicit((Object)(object)_xpAndGoldCounter))
				{
					_xpAndGoldCounter.UpdateGoldCounter();
					_xpAndGoldCounter.UpdateKillCounter();
				}
			});
		}

		internal void OnGameStarted()
		{
			_inventoryHud = null;
			_xpAndGoldCounter = null;
			_inventoryHud = Object.FindObjectOfType<InventoryHud>(true);
			_xpAndGoldCounter = Object.FindObjectOfType<KillsAndGoldCounter>(true);
			if (!Object.op_Implicit((Object)(object)_inventoryHud) || !Object.op_Implicit((Object)(object)_xpAndGoldCounter))
			{
				ModLogger.LogDebug("[UiService] Could not find required UI elements. Please check your scene setup.");
			}
		}
	}
	public class WorldService
	{
		private readonly WorldObjectCache _cache;

		private EnemyManager _enemyManager => BonkersAPI.Game.EnemyManagerInstance;

		public bool AreEnemiesSpawning => MainThreadDispatcher.Evaluate(delegate
		{
			EnemyManager enemyManager = _enemyManager;
			return enemyManager != null && enemyManager.enabledWaves;
		});

		internal WorldService()
		{
			_cache = new WorldObjectCache();
		}

		internal void Update()
		{
			if (BonkersAPI.Game.IsInGame && _cache.IsValid)
			{
				_cache.UpdateDynamicObjects();
				_cache.CleanupCompleted();
			}
		}

		internal void OnSceneChanged()
		{
			ModLogger.LogDebug("[WorldService] Scene changed, invalidating cache");
			_cache.Invalidate();
		}

		internal void OnGameStarted()
		{
			ModLogger.LogDebug("[WorldService] Game started, building cache");
			_cache.BuildCache();
		}

		public T GetComponentByInstanceId<T>(int instanceId) where T : Component
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				EnsureCacheValid();
				return _cache.GetComponentByInstanceId<T>(instanceId);
			});
		}

		public IEnumerable<ChargeShrine> GetChargeShrines()
		{
			return this.GetCachedObjects<ChargeShrine>(WorldObjectTypeEnum.ChargeShrine);
		}

		public IEnumerable<InteractableShrineMoai> GetMoaiShrines()
		{
			return this.GetCachedObjects<InteractableShrineMoai>(WorldObjectTypeEnum.MoaiShrine);
		}

		public IEnumerable<InteractableShrineCursed> GetCursedShrines()
		{
			return this.GetCachedObjects<InteractableShrineCursed>(WorldObjectTypeEnum.CursedShrine);
		}

		public IEnumerable<InteractableShrineGreed> GetGreedShrines()
		{
			return this.GetCachedObjects<InteractableShrineGreed>(WorldObjectTypeEnum.GreedShrine);
		}

		public IEnumerable<InteractableShrineMagnet> GetMagnetShrines()
		{
			return this.GetCachedObjects<InteractableShrineMagnet>(WorldObjectTypeEnum.MagnetShrine);
		}

		public IEnumerable<InteractableShrineChallenge> GetChallengeShrines()
		{
			return this.GetCachedObjects<InteractableShrineChallenge>(WorldObjectTypeEnum.ChallengeShrine);
		}

		public IEnumerable<InteractableChest> GetChests()
		{
			return this.GetCachedObjects<InteractableChest>(WorldObjectTypeEnum.Chest);
		}

		public IEnumerable<OpenChest> GetOpenChests()
		{
			return this.GetCachedObjects<OpenChest>(WorldObjectTypeEnum.OpenChest);
		}

		public IEnumerable<InteractableShadyGuy> GetShadyGuys()
		{
			return this.GetCachedObjects<InteractableShadyGuy>(WorldObjectTypeEnum.ShadyGuy);
		}

		public IEnumerable<InteractableMicrowave> GetMicrowaves()
		{
			return this.GetCachedObjects<InteractableMicrowave>(WorldObjectTypeEnum.Microwave);
		}

		public IEnumerable<InteractableBossSpawner> GetBossSpawner()
		{
			return this.GetCachedObjects<InteractableBossSpawner>(WorldObjectTypeEnum.BossSpawner);
		}

		public IEnumerable<InteractableBossSpawnerFinal> GetBossSpawnerFinal()
		{
			return this.GetCachedObjects<InteractableBossSpawnerFinal>(WorldObjectTypeEnum.BossSpawnerFinal);
		}

		public IEnumerable<Enemy> GetBosses()
		{
			return this.GetCachedObjects<Enemy>(WorldObjectTypeEnum.Boss);
		}

		public Vector3? GetNearestChargeShrine()
		{
			return GetNearestObject(WorldObjectTypeEnum.ChargeShrine);
		}

		public Vector3? GetNearestMoaiShrine()
		{
			return GetNearestObject(WorldObjectTypeEnum.MoaiShrine);
		}

		public Vector3? GetNearestCursedShrine()
		{
			return GetNearestObject(WorldObjectTypeEnum.CursedShrine);
		}

		public Vector3? GetNearestGreedShrine()
		{
			return GetNearestObject(WorldObjectTypeEnum.GreedShrine);
		}

		public Vector3? GetNearestMagnetShrine()
		{
			return GetNearestObject(WorldObjectTypeEnum.MagnetShrine);
		}

		public Vector3? GetNearestChallengeShrine()
		{
			return GetNearestObject(WorldObjectTypeEnum.ChallengeShrine);
		}

		public Vector3? GetNearestChest()
		{
			return GetNearestObject(WorldObjectTypeEnum.Chest);
		}

		public Vector3? GetNearestOpenChest()
		{
			return GetNearestObject(WorldObjectTypeEnum.OpenChest);
		}

		public Vector3? GetNearestShadyGuy()
		{
			return GetNearestObject(WorldObjectTypeEnum.ShadyGuy);
		}

		public Vector3? GetNearestMicrowave()
		{
			return GetNearestObject(WorldObjectTypeEnum.Microwave);
		}

		public Vector3? GetNearestBossSpawner()
		{
			return GetNearestObject(WorldObjectTypeEnum.BossSpawner);
		}

		public Vector3? GetNearestBossSpawnerFinal()
		{
			return GetNearestObject(WorldObjectTypeEnum.BossSpawnerFinal);
		}

		public void KillAllEnemies()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (!BonkersAPI.Game.IsInGame)
				{
					return;
				}
				IEnumerable<Enemy> cachedObjects = this.GetCachedObjects<Enemy>(WorldObjectTypeEnum.Enemy);
				foreach (Enemy item in cachedObjects)
				{
					if (Object.op_Implicit((Object)(object)item))
					{
						item.DiedNextFrame();
					}
				}
			});
		}

		public void ToggleEnemySpawns()
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				if (Object.op_Implicit((Object)(object)_enemyManager))
				{
					_enemyManager.enabledWaves = !_enemyManager.enabledWaves;
					ModLogger.LogDebug($"[WorldService] Toggled enemy spawns to {_enemyManager.enabledWaves}");
				}
			});
		}

		public List<ItemData> GetEveryShadyItem()
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				List<ItemData> list = new List<ItemData>();
				IEnumerable<InteractableShadyGuy> shadyGuys = GetShadyGuys();
				foreach (InteractableShadyGuy item in shadyGuys)
				{
					if (Object.op_Implicit((Object)(object)item) && item.items != null)
					{
						Enumerator<ItemData> enumerator2 = item.items.GetEnumerator();
						while (enumerator2.MoveNext())
						{
							ItemData current2 = enumerator2.Current;
							if (Object.op_Implicit((Object)(object)current2))
							{
								list.Add(current2);
							}
						}
					}
				}
				return list;
			});
		}

		public IEnumerable<T> GetCachedObjects<T>(WorldObjectTypeEnum objectType) where T : Component
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				EnsureCacheValid();
				return _cache.GetCachedObjects<T>(objectType).ToList();
			});
		}

		public void InteractWithEvery(WorldObjectTypeEnum objectType)
		{
			MainThreadDispatcher.Enqueue(delegate
			{
				switch (objectType)
				{
				case WorldObjectTypeEnum.ChargeShrine:
				{
					foreach (ChargeShrine cachedObject in this.GetCachedObjects<ChargeShrine>(objectType))
					{
						cachedObject.Complete();
					}
					break;
				}
				case WorldObjectTypeEnum.GreedShrine:
				{
					foreach (InteractableShrineGreed cachedObject2 in this.GetCachedObjects<InteractableShrineGreed>(objectType))
					{
						((BaseInteractable)cachedObject2).Interact();
					}
					break;
				}
				case WorldObjectTypeEnum.ChallengeShrine:
				{
					foreach (InteractableShrineChallenge cachedObject3 in this.GetCachedObjects<InteractableShrineChallenge>(objectType))
					{
						((BaseInteractable)cachedObject3).Interact();
					}
					break;
				}
				case WorldObjectTypeEnum.CursedShrine:
				{
					foreach (InteractableShrineCursed cachedObject4 in this.GetCachedObjects<InteractableShrineCursed>(objectType))
					{
						((BaseInteractable)cachedObject4).Interact();
					}
					break;
				}
				case WorldObjectTypeEnum.MoaiShrine:
				{
					foreach (InteractableShrineMoai cachedObject5 in this.GetCachedObjects<InteractableShrineMoai>(objectType))
					{
						((BaseInteractable)cachedObject5).Interact();
					}
					break;
				}
				default:
					ModLogger.LogDebug($"[InteractAction] Component type {objectType} has no interaction handler");
					break;
				}
			});
		}

		public Vector3? GetNearestObject(WorldObjectTypeEnum objectType)
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				EnsureCacheValid();
				return _cache.GetNearestObject(objectType, BonkersAPI.Player.Position);
			});
		}

		private void EnsureCacheValid()
		{
			if (!_cache.IsValid && BonkersAPI.Game.IsInGame)
			{
				ModLogger.LogDebug("[WorldService] Cache invalid, rebuilding...");
				_cache.BuildCache();
			}
		}
	}
}
namespace BonkersLib.Services.World
{
	public class ItemService
	{
		private readonly List<ItemData> _cachedRawItems = new List<ItemData>();

		internal void CacheAllRawItems()
		{
			MainThreadDispatcher.Enqueue(BuildCache);
		}

		public List<ItemData> GetAllRawItems()
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				if (_cachedRawItems.Count == 0)
				{
					BuildCache();
				}
				return new List<ItemData>(_cachedRawItems);
			});
		}

		private void BuildCache()
		{
			_cachedRawItems.Clear();
			Dictionary<EItem, ItemData> itemData = BonkersAPI.Data.ItemData;
			if (itemData != null)
			{
				Enumerator<EItem, ItemData> enumerator = itemData.GetEnumerator();
				while (enumerator.MoveNext())
				{
					KeyValuePair<EItem, ItemData> current = enumerator.Current;
					ItemData value = current.Value;
					if (Object.op_Implicit((Object)(object)value))
					{
						_cachedRawItems.Add(value);
					}
				}
			}
			ModLogger.LogDebug($"[ItemService] {_cachedRawItems.Count} raw items cached");
		}
	}
	public class WorldObjectCache
	{
		private class SafeObjectData
		{
			public Component ComponentRef;

			public Vector3 Position;

			public int InstanceId;
		}

		private readonly Dictionary<WorldObjectTypeEnum, List<SafeObjectData>> _cachedObjects = new Dictionary<WorldObjectTypeEnum, List<SafeObjectData>>();

		private readonly Dictionary<int, Component> _instanceIdLookup = new Dictionary<int, Component>();

		public bool IsValid { get; private set; }

		internal void BuildCache()
		{
			if (!BonkersAPI.Game.IsInGame)
			{
				ModLogger.LogDebug("[WorldObjectCache] Cannot build cache - not in game");
				return;
			}
			_cachedObjects.Clear();
			_instanceIdLookup.Clear();
			RefreshCacheForType<ChargeShrine>(WorldObjectTypeEnum.ChargeShrine);
			RefreshCacheForType<InteractableShrineMoai>(WorldObjectTypeEnum.MoaiShrine);
			RefreshCacheForType<InteractableShrineCursed>(WorldObjectTypeEnum.CursedShrine);
			RefreshCacheForType<InteractableShrineGreed>(WorldObjectTypeEnum.GreedShrine);
			RefreshCacheForType<InteractableShrineMagnet>(WorldObjectTypeEnum.MagnetShrine);
			RefreshCacheForType<InteractableShrineChallenge>(WorldObjectTypeEnum.ChallengeShrine);
			RefreshCacheForType<InteractableChest>(WorldObjectTypeEnum.Chest);
			RefreshCacheForType<InteractableShadyGuy>(WorldObjectTypeEnum.ShadyGuy);
			RefreshCacheForType<InteractableMicrowave>(WorldObjectTypeEnum.Microwave);
			RefreshCacheForType<InteractableBossSpawner>(WorldObjectTypeEnum.BossSpawner);
			RefreshCacheForType<InteractableBossSpawnerFinal>(WorldObjectTypeEnum.BossSpawnerFinal);
			RefreshCacheForType<OpenChest>(WorldObjectTypeEnum.OpenChest);
			RefreshCacheForType<Enemy>(WorldObjectTypeEnum.Enemy);
			IsValid = true;
			ModLogger.LogDebug($"[WorldObjectCache] Built cache with {_cachedObjects.Count} categories");
		}

		internal void UpdateDynamicObjects()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			RefreshCacheForType<OpenChest>(WorldObjectTypeEnum.OpenChest);
			RefreshCacheForType<Enemy>(WorldObjectTypeEnum.Enemy);
			if (_cachedObjects.TryGetValue(WorldObjectTypeEnum.Enemy, out var value))
			{
				List<SafeObjectData> value2 = value.Where((SafeObjectData e) => Object.op_Implicit((Object)(object)e.ComponentRef) && ((Enemy)e.ComponentRef).IsBoss()).ToList();
				_cachedObjects[WorldObjectTypeEnum.Boss] = value2;
			}
			foreach (List<SafeObjectData> value3 in _cachedObjects.Values)
			{
				foreach (SafeObjectData item in value3)
				{
					if (Object.op_Implicit((Object)(object)item.ComponentRef))
					{
						item.Position = item.ComponentRef.transform.position;
					}
				}
			}
		}

		internal void CleanupCompleted()
		{
			foreach (WorldObjectTypeEnum item in _cachedObjects.Keys.ToList())
			{
				_cachedObjects[item].RemoveAll((SafeObjectData x) => (Object)(object)x.ComponentRef == (Object)null);
			}
			CleanupSpecificShrines<ChargeShrine>(WorldObjectTypeEnum.ChargeShrine, (Func<ChargeShrine, bool>)((ChargeShrine s) => s.completed), "completed charge shrines");
			CleanupSpecificShrines<InteractableShrineGreed>(WorldObjectTypeEnum.GreedShrine, (Func<InteractableShrineGreed, bool>)((InteractableShrineGreed s) => s.done), "done greed shrines");
			List<int> list = (from kvp in _instanceIdLookup
				where !Object.op_Implicit((Object)(object)kvp.Value)
				select kvp.Key).ToList();
			foreach (int item2 in list)
			{
				_instanceIdLookup.Remove(item2);
			}
		}

		internal void Invalidate()
		{
			IsValid = false;
			_cachedObjects.Clear();
			_instanceIdLookup.Clear();
		}

		private void RefreshCacheForType<T>(WorldObjectTypeEnum type) where T : Component
		{
			//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)
			Il2CppArrayBase<T> val = Object.FindObjectsOfType<T>();
			List<SafeObjectData> list = new List<SafeObjectData>();
			foreach (T item in val)
			{
				if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)((Component)item).gameObject))
				{
					int instanceID = ((Object)((Component)item).gameObject).GetInstanceID();
					list.Add(new SafeObjectData
					{
						ComponentRef = (Component)(object)item,
						Position = ((Component)item).transform.position,
						InstanceId = instanceID
					});
					_instanceIdLookup[instanceID] = (Component)(object)item;
				}
			}
			_cachedObjects[type] = list;
		}

		private void CleanupSpecificShrines<T>(WorldObjectTypeEnum type, Func<T, bool> isCompletedCondition, string logName) where T : Component
		{
			if (!_cachedObjects.TryGetValue(type, out var value))
			{
				return;
			}
			List<SafeObjectData> list = value.Where(delegate(SafeObjectData safeObj)
			{
				if (!Object.op_Implicit((Object)(object)safeObj.ComponentRef))
				{
					return true;
				}
				Component componentRef = safeObj.ComponentRef;
				T val = (T)(object)((componentRef is T) ? componentRef : null);
				return Object.op_Implicit((Object)(object)val) && isCompletedCondition(val);
			}).ToList();
			foreach (SafeObjectData item in list)
			{
				value.Remove(item);
				_instanceIdLookup.Remove(item.InstanceId);
			}
			if (list.Count > 0)
			{
				ModLogger.LogDebug($"[WorldObjectCache] Removed {list.Count} {logName}");
			}
		}

		public T GetComponentByInstanceId<T>(int instanceId) where T : Component
		{
			if (!_instanceIdLookup.TryGetValue(instanceId, out var value))
			{
				return default(T);
			}
			if (Object.op_Implicit((Object)(object)value))
			{
				return (T)(object)((value is T) ? value : null);
			}
			_instanceIdLookup.Remove(instanceId);
			return default(T);
		}

		public IEnumerable<T> GetCachedObjects<T>(WorldObjectTypeEnum objectType) where T : Component
		{
			if (_cachedObjects.TryGetValue(objectType, out var value))
			{
				return value.Where((SafeObjectData x) => Object.op_Implicit((Object)(object)x.ComponentRef)).Select(delegate(SafeObjectData x)
				{
					Component componentRef = x.ComponentRef;
					return (T)(object)((componentRef is T) ? componentRef : null);
				});
			}
			return Enumerable.Empty<T>();
		}

		public Vector3? GetNearestObject(WorldObjectTypeEnum objectType, Vector3 referencePosition)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (!_cachedObjects.TryGetValue(objectType, out var value) || value.Count == 0)
			{
				return null;
			}
			return (from obj in value
				where Object.op_Implicit((Object)(object)obj.ComponentRef)
				orderby Vector3.Distance(referencePosition, obj.Position)
				select obj).FirstOrDefault()?.Position;
		}
	}
}
namespace BonkersLib.Services.Player
{
	public class TomeService
	{
		private PlayerInventory _playerInventory => BonkersAPI.Player.Inventory;

		public TomeInventory TomeInventory => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerInventory playerInventory = _playerInventory;
			return (playerInventory != null) ? playerInventory.tomeInventory : null;
		});

		public Dictionary<ETome, StatModifier> CurrentTomes => MainThreadDispatcher.Evaluate(delegate
		{
			TomeInventory tomeInventory = TomeInventory;
			return (tomeInventory != null) ? tomeInventory.tomeUpgrade.ToSafeCopy<ETome, StatModifier>() : null;
		});

		public Dictionary<ETome, int> TomeLevel => MainThreadDispatcher.Evaluate(delegate
		{
			TomeInventory tomeInventory = TomeInventory;
			return (tomeInventory != null) ? tomeInventory.tomeLevels.ToSafeCopy<ETome, int>() : null;
		});

		public TomeData GetTomeDataFromEnum(ETome eTome)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ETome, TomeData> tomeData = BonkersAPI.Data.TomeData;
			return tomeData.ContainsKey(eTome) ? tomeData[eTome] : null;
		}

		public int GetTomeLevel(ETome eTome)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return MainThreadDispatcher.Evaluate(delegate
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				TomeInventory tomeInventory = TomeInventory;
				Dictionary<ETome, int> val = ((tomeInventory != null) ? tomeInventory.tomeLevels : null);
				return (val != null && val.ContainsKey(eTome)) ? val[eTome] : 0;
			});
		}

		public List<StatModifier> GetTomeUpgradeOffer(TomeData td, ERarity rarity)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return MainThreadDispatcher.Evaluate(() => td.GetUpgradeOffer(rarity));
		}

		public void AddTomeWithStats(TomeData td, List<StatModifier> statModifiers, ERarity rarity)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				if (BonkersAPI.Game.IsInGame && TomeInventory != null)
				{
					TomeInventory.AddTome(td, statModifiers, rarity);
					ModLogger.LogDebug("[TomeService] Added tome: " + ((Object)td).name);
				}
			});
		}

		public void AddTome(ETome eTome)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: 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)
				if (BonkersAPI.Game.IsInGame)
				{
					TomeData tomeDataFromEnum = GetTomeDataFromEnum(eTome);
					if (!Object.op_Implicit((Object)(object)tomeDataFromEnum))
					{
						ModLogger.LogDebug($"[TomeService] Could not find data for tome: {eTome}");
					}
					else
					{
						List<StatModifier> upgradeOffer = tomeDataFromEnum.GetUpgradeOffer((ERarity)0);
						if (TomeInventory != null)
						{
							TomeInventory.AddTome(tomeDataFromEnum, upgradeOffer, (ERarity)0);
							ModLogger.LogDebug($"[TomeService] Added tome via enum: {eTome}");
						}
					}
				}
			});
		}

		public bool RemoveTome(ETome eTome)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return MainThreadDispatcher.Evaluate(delegate
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				if (!BonkersAPI.Game.IsInGame || TomeInventory == null)
				{
					return false;
				}
				Dictionary<ETome, StatModifier> tomeUpgrade = TomeInventory.tomeUpgrade;
				Dictionary<ETome, int> tomeLevels = TomeInventory.tomeLevels;
				bool flag = tomeUpgrade.Remove(eTome);
				bool flag2 = tomeLevels.Remove(eTome);
				if (flag || flag2)
				{
					BonkersAPI.Ui.RefreshUi();
					ModLogger.LogDebug($"[TomeService] Removed tome: {eTome}");
					return true;
				}
				return false;
			});
		}

		public void UpgradeWithRandomStats(ETome eTome, ERarity rarity)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: 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)
				TomeData tomeDataFromEnum = GetTomeDataFromEnum(eTome);
				if (!Object.op_Implicit((Object)(object)tomeDataFromEnum))
				{
					ModLogger.LogDebug($"[TomeService] Could not find TomeData for {eTome}");
				}
				else
				{
					List<StatModifier> tomeUpgradeOffer = GetTomeUpgradeOffer(tomeDataFromEnum, rarity);
					AddTomeWithStats(tomeDataFromEnum, tomeUpgradeOffer, rarity);
					ModLogger.LogDebug($"[TomeService] Upgraded tome {eTome} with rarity {rarity}");
				}
			});
		}
	}
	public class WeaponService
	{
		private PlayerInventory _playerInventory => BonkersAPI.Player.Inventory;

		public WeaponInventory WeaponInventory => MainThreadDispatcher.Evaluate(delegate
		{
			PlayerInventory playerInventory = _playerInventory;
			return (playerInventory != null) ? playerInventory.weaponInventory : null;
		});

		public Dictionary<EWeapon, WeaponBase> CurrentWeapons => MainThreadDispatcher.Evaluate(delegate
		{
			WeaponInventory weaponInventory = WeaponInventory;
			return (weaponInventory != null) ? weaponInventory.weapons.ToSafeCopy<EWeapon, WeaponBase>() : null;
		});

		public WeaponData GetWeaponDataFromEnum(EWeapon eWeapon)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<EWeapon, WeaponData> weaponData = BonkersAPI.Data.WeaponData;
			return weaponData.ContainsKey(eWeapon) ? weaponData[eWeapon] : null;
		}

		public WeaponData GetWeaponDataFromWeaponBase(WeaponBase wb)
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				WeaponBase obj = wb;
				return (obj != null) ? obj.weaponData : null;
			});
		}

		public string GetWeaponNameFromWeaponBase(WeaponBase wb)
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				WeaponBase obj = wb;
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					WeaponData weaponData = obj.weaponData;
					obj2 = ((weaponData != null) ? weaponData.damageSourceName : null);
				}
				if (obj2 == null)
				{
					obj2 = "WeaponData not found";
				}
				return (string)obj2;
			});
		}

		public List<StatModifier> GetWeaponUpgradeOffer(WeaponData wd, ERarity rarity)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return MainThreadDispatcher.Evaluate(() => Object.op_Implicit((Object)(object)wd) ? wd.GetUpgradeOffer(rarity) : null);
		}

		public List<EStat> GetValidUpgradeStats(EWeapon eWeapon)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return MainThreadDispatcher.Evaluate((Func<List<EStat>>)delegate
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				WeaponData weaponDataFromEnum = GetWeaponDataFromEnum(eWeapon);
				if (!Object.op_Implicit((Object)(object)weaponDataFromEnum))
				{
					return new List<EStat>();
				}
				UpgradeData upgradeData = weaponDataFromEnum.upgradeData;
				List<StatModifier> val = ((upgradeData != null) ? upgradeData.upgradeModifiers : null);
				List<EStat> val2 = new List<EStat>();
				if (val == null || val.Count == 0)
				{
					return val2;
				}
				for (int i = 0; i < val.Count; i++)
				{
					StatModifier val3 = val[i];
					if (val3 != null)
					{
						EStat stat = val3.stat;
						if (!val2.Contains(stat))
						{
							val2.Add(stat);
						}
					}
				}
				return val2;
			});
		}

		public bool AddWeaponWithStats(WeaponData wd, List<StatModifier> stats)
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				if (!BonkersAPI.Game.IsInGame || WeaponInventory == null)
				{
					return false;
				}
				if (!Object.op_Implicit((Object)(object)wd))
				{
					return false;
				}
				List<EStat> validUpgradeStats = GetValidUpgradeStats(wd.eWeapon);
				Enumerator<StatModifier> enumerator = stats.GetEnumerator();
				while (enumerator.MoveNext())
				{
					StatModifier current = enumerator.Current;
					if (!validUpgradeStats.Contains(current.stat))
					{
						return false;
					}
				}
				WeaponInventory.AddWeapon(wd, stats);
				return true;
			});
		}

		public void AddWeapon(EWeapon eWeapon)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: 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)
				WeaponData weaponDataFromEnum = GetWeaponDataFromEnum(eWeapon);
				if (!Object.op_Implicit((Object)(object)weaponDataFromEnum))
				{
					ModLogger.LogDebug($"[WeaponService] WeaponData not found for {eWeapon}");
				}
				else
				{
					List<StatModifier> weaponUpgradeOffer = GetWeaponUpgradeOffer(weaponDataFromEnum, (ERarity)0);
					AddWeaponWithStats(weaponDataFromEnum, weaponUpgradeOffer);
					ModLogger.LogDebug($"[WeaponService] Added weapon: {eWeapon}");
				}
			});
		}

		public bool RemoveWeapon(EWeapon eWeapon)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return MainThreadDispatcher.Evaluate(delegate
			{
				//IL_001e: 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)
				WeaponInventory weaponInventory = WeaponInventory;
				Dictionary<EWeapon, WeaponBase> val = ((weaponInventory != null) ? weaponInventory.weapons : null);
				if (val == null || !val.Remove(eWeapon))
				{
					return false;
				}
				BonkersAPI.Ui.RefreshUi();
				ModLogger.LogDebug($"[WeaponService] Removed weapon: {eWeapon}");
				return true;
			});
		}

		public void UpgradeWithRandomStats(WeaponBase wb, ERarity rarity)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			MainThreadDispatcher.Enqueue(delegate
			{
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				if (wb != null && Object.op_Implicit((Object)(object)wb.weaponData))
				{
					WeaponData weaponData = wb.weaponData;
					List<StatModifier> weaponUpgradeOffer = GetWeaponUpgradeOffer(weaponData, rarity);
					AddWeaponWithStats(weaponData, weaponUpgradeOffer);
					ModLogger.LogDebug("[WeaponService] Upgraded weapon: " + ((Object)weaponData).name);
				}
			});
		}

		public bool DowngradeWeapon(WeaponBase wb)
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				WeaponBase obj = wb;
				if (((obj != null) ? obj.upgrades : null) == null || wb.upgrades.Count <= 1)
				{
					return false;
				}
				wb.upgrades.RemoveAt(wb.upgrades.Count - 1);
				WeaponBase obj2 = wb;
				int level = obj2.level;
				obj2.level = level - 1;
				BonkersAPI.Ui.RefreshUi();
				ModLogger.LogDebug("[WeaponService] Downgraded weapon: " + GetWeaponNameFromWeaponBase(wb));
				return true;
			});
		}

		public bool ClearWeaponUpgrades(WeaponBase wb)
		{
			return MainThreadDispatcher.Evaluate(delegate
			{
				WeaponBase obj = wb;
				List<List<StatModifier>> val = ((obj != null) ? obj.upgrades : null);
				if (val == null || val.Count <= 1)
				{
					return false;
				}
				wb.upgrades.RemoveRange(1, wb.upgrades.Count - 1);
				wb.level = 1;
				BonkersAPI.Ui.RefreshUi();
				ModLogger.LogDebug("[WeaponService] Cleared upgrades for weapon: " + GetWeaponNameFromWeaponBase(wb));
				return true;
			});
		}
	}
}
namespace BonkersLib.Enums
{
	public enum GameStateEnum
	{
		MainMenu,
		Loading,
		WaitingForWorldLoad,
		InGame
	}
	public enum WorldObjectTypeEnum
	{
		ChargeShrine,
		MoaiShrine,
		CursedShrine,
		GreedShrine,
		MagnetShrine,
		ChallengeShrine,
		Chest,
		OpenChest,
		ShadyGuy,
		Microwave,
		BossSpawner,
		BossSpawnerFinal,
		Boss,
		Enemy
	}
}
namespace BonkersLib.Core
{
	public static class BonkersAPI
	{
		public static GameStateService Game { get; private set; }

		public static WorldService World { get; private set; }

		public static PlayerService Player { get; private set; }

		public static ItemService Item { get; private set; }

		public static WeaponService Weapon { get; private set; }

		public static TomeService Tome { get; private set; }

		public static UiService Ui { get; private set; }

		public static DataService Data { get; private set; }

		public static AchievementService Achievements { get; private set; }

		internal static void Initialize()
		{
			Game = new GameStateService();
			Data = new DataService();
			World = new WorldService();
			Player = new PlayerService();
			Item = new ItemService();
			Weapon = new WeaponService();
			Tome = new TomeService();
			Ui = new UiService();
			Achievements = new AchievementService();
			Game.SceneChanged += Data.SetDataManager;
			Game.GameStarted += Ui.OnGameStarted;
			Game.SceneChanged += Item.CacheAllRawItems;
		}

		internal static void Update()
		{
			Game.Update();
			World.Update();
			Player.Update();
		}

		internal static void Internal_OnSceneChanged(Scene oldScene, Scene newScene)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Game?.OnSceneChanged(newScene);
		}
	}
	public class LibUpdater : MonoBehaviour
	{
		private void Update()
		{
			BonkersAPI.Update();
			MainThreadDispatcher.Update();
		}

		public void Initialize()
		{
			BonkersAPI.Initialize();
			SceneManager.activeSceneChanged += UnityAction<Scene, Scene>.op_Implicit((Action<Scene, Scene>)BonkersAPI.Internal_OnSceneChanged);
		}
	}
	public static class MainThreadDispatcher
	{
		private static readonly ConcurrentQueue<Action> _executionQueue = new ConcurrentQueue<Action>();

		private static int _mainThreadId;

		public static void Initialize()
		{
			_mainThreadId = Thread.CurrentThread.ManagedThreadId;
		}

		public static T Evaluate<T>(Func<T> action)
		{
			if (Thread.CurrentThread.ManagedThreadId == _mainThreadId)
			{
				return action();
			}
			TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
			_executionQueue.Enqueue(delegate
			{
				try
				{
					T result = action();
					tcs.SetResult(result);
				}
				catch (Exception exception)
				{
					tcs.SetException(exception);
				}
			});
			return tcs.Task.Result;
		}

		public static void Enqueue(Action action)
		{
			_executionQueue.Enqueue(action);
		}

		internal static void Update()
		{
			Action result;
			while (_executionQueue.TryDequeue(out result))
			{
				try
				{
					result();
				}
				catch (Exception value)
				{
					ModLogger.LogDebug($"Dispatcher Error: {value}");
				}
			}
		}
	}
	internal static class ModConfig
	{
		public static ConfigEntry<bool> IsDebugLoggingEnabled { get; private set; }

		internal static void Initialize(ConfigFile config)
		{
			IsDebugLoggingEnabled = config.Bind<bool>("1. General", "DebugLogging", false, "Enables detailed Debug-Logs");
		}
	}
	[BepInPlugin("com.kss.bonkerslib", "BonkersLib", "1.0.4")]
	public class Plugin : BasePlugin
	{
		public override void Load()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			MainThreadDispatcher.Initialize();
			string text = Path.Combine(Paths.ConfigPath, "com.kss.bonkerslib.cfg");
			ConfigFile config = new ConfigFile(text, true);
			ModConfig.Initialize(config);
			ModLogger.InitLog(((BasePlugin)this).Log);
			ClassInjector.RegisterTypeInIl2Cpp<LibUpdater>();
			GameObject val = new GameObject("BonkersLibUpdater");
			LibUpdater libUpdater = val.AddComponent<LibUpdater>();
			libUpdater.Initialize();
			Object.DontDestroyOnLoad((Object)(object)libUpdater);
			ModLogger.LogInfo("BonkersLib Initialized");
			ModLogger.LogInfo("Debug-Logging: " + (ModConfig.IsDebugLoggingEnabled.Value ? "ENABLED" : "DISABLED"));
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.kss.bonkerslib";

		public const string PLUGIN_NAME = "BonkersLib";

		public const string PLUGIN_VERSION = "1.0.4";
	}
}