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";
}
}