using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG.Reflection;
using Microsoft.CodeAnalysis;
using On.RoR2;
using On.RoR2.Networking;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RoR2;
using RoR2.Artifacts;
using RoR2.Networking;
using RoR2.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CatchupLoot")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+54de05d8639907e57a333aaccea732a1ae8f557e")]
[assembly: AssemblyProduct("CatchupLoot")]
[assembly: AssemblyTitle("CatchupLoot")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace CatchupLoot
{
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("zerocodehero.CatchupLoot", "CatchupLoot", "2.2.0")]
public class CatchupLootPlugin : BaseUnityPlugin
{
[CompilerGenerated]
private static class <>O
{
public static hook_GetExpAdjustedDropChancePercent <0>__Util_GetExpAdjustedDropChancePercent;
public static NetworkMessageDelegate <1>__HandlePickupMessage;
}
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static hook_DropRewards <>9__40_0;
public static Func<PlayerCharacterMasterController, bool> <>9__56_0;
internal void <OnEnable>b__40_0(orig_DropRewards orig, BossGroup self)
{
if (EnablePlayerDropRateScaling.Value && IsModHooked)
{
self.scaleRewardsByPlayerCount = false;
}
orig.Invoke(self);
}
internal bool <GetPlayerCount>b__56_0(PlayerCharacterMasterController pc)
{
return pc.isConnected;
}
}
public const string PluginGUID = "zerocodehero.CatchupLoot";
public const string PluginAuthor = "zerocodehero";
public const string PluginName = "CatchupLoot";
public const string PluginVersion = "2.2.0";
public static float dropChance = 5f;
private static bool IsModHooked = false;
private bool forceDisabled;
private static bool useManualDropRate = false;
private static DropRateManager dropRateManager;
private static ConfigEntry<float> DropChanceMultiplier { get; set; }
private static ConfigEntry<float> MinimumDropChance { get; set; }
private static ConfigEntry<float> BaseDropChance { get; set; }
private static ConfigEntry<bool> EnablePlayerDropRateScaling { get; set; }
private static ConfigEntry<bool> EnableSwarmsScaling { get; set; }
private static ConfigEntry<bool> EnableBadLuckProtection { get; set; }
private static ConfigEntry<KeyCode> PullItemsHotKey { get; set; }
public void Awake()
{
Log.Init(((BaseUnityPlugin)this).Logger);
DropChanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DropChanceMultiplier", 1f, "Manipulate drop rate. Use `0.5` to halve or `2` to double.");
MinimumDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MinimumDropChance", 1f, "The lowest possible drop chance when player count scaling is active.");
EnablePlayerDropRateScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePlayerBasedDropRateScaling", true, "Enabling this will reduce drop rates to account for shared loot.");
EnableSwarmsScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableSwarmsScaling", true, "Enabling this will (correctly) reduce drop rates for Artifact of Swarms.");
EnableBadLuckProtection = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableBadLuckProtection", true, "Enabling this will increase drop rate consistency with low drop rates.");
PullItemsHotKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "PullItemsHotkey", (KeyCode)284, "Hotkey to use to pull items to yourself.");
BaseDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BaseDropChance", 5f, "Base item drop chance. It is recommended to leave this at the default value.");
dropChance = BaseDropChance.Value;
dropRateManager = new DropRateManager(EnableBadLuckProtection, EnableSwarmsScaling, DropChanceMultiplier, BaseDropChance, MinimumDropChance);
Log.Info("CatchupLoot loaded");
}
private void Update()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
if (!Input.GetKeyDown(PullItemsHotKey.Value) || !IsModHooked)
{
return;
}
try
{
Object.FindObjectsOfType<RuleBookViewer>();
PickupDisplay[] array = Object.FindObjectsOfType<PickupDisplay>();
Vector3 position = ((MPEventSystem)EventSystem.current).localUser.cachedMaster.GetBodyObject().transform.position;
float num = 10f;
Vector3 position2 = default(Vector3);
for (int i = 0; i < array.Length; i++)
{
PickupDisplay val = array[i];
if (((Object)val.highlight).name.StartsWith("CommandCube"))
{
float num2 = (float)i * MathF.PI * 2f / (float)array.Length;
((Vector3)(ref position2))..ctor(position.x + Mathf.Cos(num2) * num, position.y, position.z + Mathf.Sin(num2) * num);
((Component)val).gameObject.transform.position = position2;
}
}
}
catch (NullReferenceException)
{
((BaseUnityPlugin)this).Logger.LogDebug((object)"Failed to pull CommandCubes with F3 - most likely because there were none.");
}
}
private void OnApplicationFocus(bool hasFocus)
{
if (hasFocus)
{
ReevaluateLifecycle();
}
}
private void OnEnable()
{
//IL_0014: 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)
//IL_001f: Expected O, but got Unknown
object obj = <>c.<>9__40_0;
if (obj == null)
{
hook_DropRewards val = delegate(orig_DropRewards orig, BossGroup self)
{
if (EnablePlayerDropRateScaling.Value && IsModHooked)
{
self.scaleRewardsByPlayerCount = false;
}
orig.Invoke(self);
};
<>c.<>9__40_0 = val;
obj = (object)val;
}
BossGroup.DropRewards += (hook_DropRewards)obj;
SceneManager.activeSceneChanged += delegate(Scene oldScene, Scene newScene)
{
bool flag = ((Scene)(ref newScene)).name == "loadingbasic" || ((Scene)(ref newScene)).name == "intro" || ((Scene)(ref newScene)).name == "splash" || ((Scene)(ref newScene)).name == "title" || ((Scene)(ref newScene)).name == "eclipseworld" || ((Scene)(ref newScene)).name == "infinitetowerworld" || ((Scene)(ref newScene)).name == "lobby";
forceDisabled = ((Scene)(ref newScene)).name == "artifactworld" || flag;
if (flag)
{
useManualDropRate = false;
DropRateTracker.ResetTracker();
}
ReevaluateLifecycle();
};
NetworkingAPI.RegisterMessageType<SpawnCustomMessage2>();
}
private void ReevaluateLifecycle()
{
if (EnablePlayerDropRateScaling.Value && IsSacrificeEnabled() && !useManualDropRate)
{
dropChance = dropRateManager.GetPlayerAwareBaseDropChance(GetPlayerCount(), dropChance);
}
if (forceDisabled)
{
if (IsModHooked)
{
Log.Warning("Force Disabled: Will remove hooks, even if Artifact of Command is enabled.");
UnHook();
}
else
{
Log.Debug("Force Disabled: Will not hook.");
}
return;
}
bool flag = IsCommandEnabled();
if (IsModHooked && !flag)
{
UnHook();
}
else if (!IsModHooked && flag)
{
Hook();
}
}
private void Hook()
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Expected O, but got Unknown
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Expected O, but got Unknown
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading hooks");
object obj = <>O.<0>__Util_GetExpAdjustedDropChancePercent;
if (obj == null)
{
hook_GetExpAdjustedDropChancePercent val = Util_GetExpAdjustedDropChancePercent;
<>O.<0>__Util_GetExpAdjustedDropChancePercent = val;
obj = (object)val;
}
Util.GetExpAdjustedDropChancePercent += (hook_GetExpAdjustedDropChancePercent)obj;
NetworkMessageHandlerAttribute.RegisterClientMessages += new hook_RegisterClientMessages(NetworkMessageHandlerAttribute_RegisterClientMessages);
PickupDropletController.CreateCommandCube += new hook_CreateCommandCube(PickupDropletController_CreateCommandCube);
Interactor.AttemptInteraction += new hook_AttemptInteraction(Interactor_AttemptInteraction);
PickupPickerController.SubmitChoice += new hook_SubmitChoice(PickupPickerController_SubmitChoice);
GenericPickupController.CreatePickup += new hook_CreatePickup(GenericPickupController_CreatePickup);
IsModHooked = true;
}
private void UnHook()
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Expected O, but got Unknown
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Expected O, but got Unknown
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
((BaseUnityPlugin)this).Logger.LogInfo((object)"Unloading hooks");
object obj = <>O.<0>__Util_GetExpAdjustedDropChancePercent;
if (obj == null)
{
hook_GetExpAdjustedDropChancePercent val = Util_GetExpAdjustedDropChancePercent;
<>O.<0>__Util_GetExpAdjustedDropChancePercent = val;
obj = (object)val;
}
Util.GetExpAdjustedDropChancePercent -= (hook_GetExpAdjustedDropChancePercent)obj;
NetworkMessageHandlerAttribute.RegisterClientMessages -= new hook_RegisterClientMessages(NetworkMessageHandlerAttribute_RegisterClientMessages);
PickupDropletController.CreateCommandCube -= new hook_CreateCommandCube(PickupDropletController_CreateCommandCube);
Interactor.AttemptInteraction -= new hook_AttemptInteraction(Interactor_AttemptInteraction);
PickupPickerController.SubmitChoice -= new hook_SubmitChoice(PickupPickerController_SubmitChoice);
GenericPickupController.CreatePickup -= new hook_CreatePickup(GenericPickupController_CreatePickup);
IsModHooked = false;
}
private GenericPickupController GenericPickupController_CreatePickup(orig_CreatePickup orig, ref CreatePickupInfo createPickupInfo)
{
return null;
}
private void PickupPickerController_SubmitChoice(orig_SubmitChoice orig, PickupPickerController self, int choiceIndex)
{
//IL_0031: 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_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
if ((ulong)choiceIndex >= (ulong)self.options.Length)
{
return;
}
ref Option reference = ref self.options[choiceIndex];
if (reference.available)
{
PickupIndexUnityEvent onPickupSelected = self.onPickupSelected;
if (onPickupSelected != null)
{
((UnityEvent<int>)(object)onPickupSelected).Invoke(((Option)(ref reference)).pickupIndex.value);
Log.Info($"Sending CreatePickup {((Option)(ref self.options[choiceIndex])).pickupIndex}");
NetMessageExtensions.Send((INetMessage)(object)new SpawnCustomMessage2(((Option)(ref self.options[choiceIndex])).pickupIndex, ((MPEventSystem)EventSystem.current).localUser.cachedMaster.GetBodyObject().transform.position), (NetworkDestination)2);
self.OnDisplayEnd((NetworkUIPromptController)null, (LocalUser)null, (CameraRigController)null);
Object.Destroy((Object)(object)((Component)self).gameObject);
}
}
}
private void Interactor_AttemptInteraction(orig_AttemptInteraction orig, Interactor self, GameObject interactableObject)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
if (((Object)interactableObject).name.StartsWith("CommandCube"))
{
interactableObject.GetComponent<PickupPickerController>().OnDisplayBegin((NetworkUIPromptController)null, (LocalUser)null, ((MPEventSystem)EventSystem.current).localUser.cameraRigController);
}
else
{
orig.Invoke(self, interactableObject);
}
}
private void PickupDropletController_CreateCommandCube(orig_CreateCommandCube orig, PickupDropletController self)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
DropRateTracker.RegisterItemDrop(self.createPickupInfo);
NetworkServer.SendToAll((short)969, (MessageBase)(object)new SpawnCustomMessage
{
position = self.createPickupInfo.position,
pickupIndex = ((CreatePickupInfo)(ref self.createPickupInfo)).pickupIndex
});
if (!NetworkServer.active)
{
return;
}
ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
if (readOnlyInstancesList == null)
{
return;
}
Vector3 val = default(Vector3);
foreach (NetworkUser item in readOnlyInstancesList)
{
if ((Object)(object)item == (Object)null || ((NetworkBehaviour)item).connectionToClient == null || !((NetworkBehaviour)item).connectionToClient.isReady || (Object)(object)item.master == (Object)null || !item.master.hasBody)
{
continue;
}
ItemTier? catchupTier = PlayerCatchupManager.GetCatchupTier(item);
if (!catchupTier.HasValue)
{
continue;
}
int deficit = PlayerCatchupManager.GetDeficit(item, catchupTier.Value);
float catchupChance = PlayerCatchupManager.GetCatchupChance(deficit, catchupTier.Value);
if (Random.value < catchupChance)
{
PickupIndex randomPickupForTier = PlayerCatchupManager.GetRandomPickupForTier(catchupTier.Value);
if (((PickupIndex)(ref randomPickupForTier)).isValid)
{
((Vector3)(ref val))..ctor(Random.Range(-1.5f, 1.5f), 0f, Random.Range(-1.5f, 1.5f));
SpawnCustomMessage spawnCustomMessage = new SpawnCustomMessage
{
position = self.createPickupInfo.position + val,
pickupIndex = randomPickupForTier
};
((NetworkBehaviour)item).connectionToClient.Send((short)969, (MessageBase)(object)spawnCustomMessage);
Log.Info($"Catchup drop for {item.userName}: tier={catchupTier.Value} deficit={deficit} chance={catchupChance:P} pickup={randomPickupForTier.value}");
}
}
}
}
private void NetworkMessageHandlerAttribute_RegisterClientMessages(orig_RegisterClientMessages orig, NetworkClient client)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
orig.Invoke(client);
object obj = <>O.<1>__HandlePickupMessage;
if (obj == null)
{
NetworkMessageDelegate val = SpawnCustomController.HandlePickupMessage;
<>O.<1>__HandlePickupMessage = val;
obj = (object)val;
}
client.RegisterHandler((short)969, (NetworkMessageDelegate)obj);
}
private static float Util_GetExpAdjustedDropChancePercent(orig_GetExpAdjustedDropChancePercent orig, float nativeBaseDropChance, GameObject characterBodyObject)
{
float num = orig.Invoke(nativeBaseDropChance, characterBodyObject);
float num2 = dropRateManager.ComputeDropChance(IsSwarmEnabled(), num, nativeBaseDropChance, dropChance);
Log.Debug($"DropChance: original_base={nativeBaseDropChance} original_final={num}; plugin_base={dropChance}; plugin_final={num2} (Character={((Object)characterBodyObject).name})");
DropRateTracker.RegisterDropOpportunity(num2);
if (dropRateManager.NeedsBadLuckProtection(num2, Run.instance.GetRunStopwatch()))
{
return dropRateManager.GetBadLuckProtectedDropChance(num2);
}
return num2;
}
[ConCommand(/*Could not decode attribute arguments.*/)]
private static void CCSetDropRate(ConCommandArgs args)
{
dropChance = ((ConCommandArgs)(ref args)).GetArgFloat(0);
useManualDropRate = true;
Log.Info("Drop rate set to: " + ((ConCommandArgs)(ref args)).GetArgString(0) + "%");
}
[ConCommand(/*Could not decode attribute arguments.*/)]
private static void CCGetDropRateReport(ConCommandArgs args)
{
if (IsModHooked)
{
DropRateTracker.LogReport();
}
}
private static bool IsSacrificeEnabled()
{
if (RunArtifactManager.instance != null && ((Behaviour)RunArtifactManager.instance).isActiveAndEnabled)
{
return RunArtifactManager.instance.IsArtifactEnabled(Artifacts.sacrificeArtifactDef);
}
return false;
}
[ConCommand(/*Could not decode attribute arguments.*/)]
private static void CCSetHotkey(ConCommandArgs args)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (IsModHooked)
{
string argString = ((ConCommandArgs)(ref args)).GetArgString(0);
if (Enum.TryParse<KeyCode>(argString, ignoreCase: true, out KeyCode result))
{
PullItemsHotKey.Value = result;
}
else
{
Log.Warning("Failed to set hotkey to " + argString);
}
}
}
private static bool IsCommandEnabled()
{
if (RunArtifactManager.instance != null && ((Behaviour)RunArtifactManager.instance).isActiveAndEnabled)
{
return RunArtifactManager.instance.IsArtifactEnabled(Artifacts.commandArtifactDef);
}
return false;
}
private static bool IsSwarmEnabled()
{
if (RunArtifactManager.instance != null && ((Behaviour)RunArtifactManager.instance).isActiveAndEnabled)
{
return RunArtifactManager.instance.IsArtifactEnabled(Artifacts.swarmsArtifactDef);
}
return false;
}
private int GetPlayerCount()
{
return PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController pc) => pc.isConnected);
}
}
public class DropRateManager
{
private ConfigEntry<bool> EnableBadLuckProtection;
private ConfigEntry<bool> EnableSwarmsScaling;
private ConfigEntry<float> DropChanceMultiplier;
private ConfigEntry<float> BaseDropChance;
private ConfigEntry<float> MinimumDropChance;
public DropRateManager(ConfigEntry<bool> enableBadLuckProtection, ConfigEntry<bool> enableSwarmsScaling, ConfigEntry<float> dropChanceMultiplier, ConfigEntry<float> baseDropChance, ConfigEntry<float> minimumDropChance)
{
EnableBadLuckProtection = enableBadLuckProtection;
EnableSwarmsScaling = enableSwarmsScaling;
DropChanceMultiplier = dropChanceMultiplier;
BaseDropChance = baseDropChance;
MinimumDropChance = minimumDropChance;
}
public float GetPlayerAwareBaseDropChance(int playerCount, float dropChance)
{
float num = 1f / (float)playerCount * DropChanceMultiplier.Value;
float num2 = Math.Max(BaseDropChance.Value * num, MinimumDropChance.Value);
if (!dropChance.Equals(num2))
{
dropChance = num2;
Log.Debug($"Using dropRate of {dropChance}% (base={BaseDropChance.Value}, multiplier={DropChanceMultiplier.Value}, playerCount={playerCount}, minimumDropChance={MinimumDropChance.Value}");
}
return dropChance;
}
public float ComputeDropChance(bool isSwarmEnabled, float nativeDropChance, float nativeBaseDropChance, float dropChance)
{
float num = ((!(EnableSwarmsScaling.Value && isSwarmEnabled) || nativeDropChance == 0f) ? nativeDropChance : ((nativeDropChance - nativeBaseDropChance) * 0.6f + nativeBaseDropChance));
float num2 = nativeBaseDropChance / 5f;
float num3 = num / nativeBaseDropChance;
return dropChance * num2 * num3;
}
public bool NeedsBadLuckProtection(float actualDropChance, float time)
{
if (EnableBadLuckProtection.Value && DropRateTracker.cumulativeDropChance >= 100f && actualDropChance > 0f)
{
bool num = DropRateTracker.expectedItems > (float)DropRateTracker.totalItemDrops;
float num2 = (float)DropRateTracker.totalItemDrops / (time / 60f);
if (!num)
{
return (double)num2 < 0.8;
}
return true;
}
return false;
}
public float GetBadLuckProtectedDropChance(float dropChance)
{
float num = DropRateTracker.cumulativeDropChance - 100f;
float num2 = Math.Min(dropChance + num, 90f);
Log.Debug($"Bad Luck Protection triggered! ({dropChance}% => {num2}%)");
return num2;
}
}
public static class DropRateTracker
{
private static Dictionary<float, long> DropRateReport = new Dictionary<float, long>();
public static long totalItemDrops { get; private set; } = 0L;
public static float cumulativeDropChance { get; private set; } = 0f;
public static float expectedItems { get; private set; } = 0f;
public static void ResetTracker()
{
DropRateReport = new Dictionary<float, long>();
totalItemDrops = 0L;
cumulativeDropChance = 0f;
expectedItems = 0f;
}
public static void RegisterDropOpportunity(float dropChance)
{
cumulativeDropChance += dropChance;
expectedItems += (float)Math.Round(dropChance / 100f, 2);
if (DropRateReport.TryGetValue(dropChance, out var _))
{
DropRateReport[dropChance]++;
}
else
{
DropRateReport.Add(dropChance, 1L);
}
}
public static void RegisterItemDrop(CreatePickupInfo createPickupInfo)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
PickupIndex pickupIndex = ((CreatePickupInfo)(ref createPickupInfo)).pickupIndex;
if (((PickupIndex)(ref pickupIndex)).pickupDef != null)
{
pickupIndex = ((CreatePickupInfo)(ref createPickupInfo)).pickupIndex;
PickupDef pickupDef = ((PickupIndex)(ref pickupIndex)).pickupDef;
if (pickupDef.coinValue == 0 && pickupDef.nameToken != "PICKUP_LUNAR_COIN")
{
cumulativeDropChance = 0f;
totalItemDrops++;
}
}
}
public static void LogReport()
{
if (Run.instance == null || !((Behaviour)Run.instance).isActiveAndEnabled)
{
return;
}
long num = DropRateReport.Values.Aggregate(0L, (long i, long l) => i + l);
if (num != 0L)
{
string text = DropRateReport.Keys.OrderByDescending((float f) => f).Aggregate("Kills by Drop Rate", (string s, float f) => $"{s}\n {f}%: {DropRateReport[f]} kills");
float runStopwatch = Run.instance.GetRunStopwatch();
float num2 = runStopwatch / 60f;
float num3 = DropRateReport.Keys.Aggregate(0f, (float f, float f1) => f + (float)DropRateReport[f1] * f1) / (float)num;
Log.Info(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat("------ DROP RATE RUN REPORT -----\n" + $"Stage: {Run.instance.stageClearCount + 1}\n", $"Run Duration: {runStopwatch}s\n"), $"Total kills: {num}\n"), $"Total items: {totalItemDrops}\n"), $"Theoretical Average Drop Rate: {num3}%\n"), $"Actual Average Drop Rate: {(float)totalItemDrops / (float)num * 100f}%\n"), $"Drops per Minute: {Math.Round((float)totalItemDrops / num2, 2)}\n"), text, "\n"), "------ END OF REPORT -----"));
}
}
}
internal static class Log
{
private static ManualLogSource _logSource;
internal static void Init(ManualLogSource logSource)
{
_logSource = logSource;
}
internal static void Debug(object data)
{
_logSource.LogDebug(data);
}
internal static void Error(object data)
{
_logSource.LogError(data);
}
internal static void Fatal(object data)
{
_logSource.LogFatal(data);
}
internal static void Info(object data)
{
_logSource.LogInfo(data);
}
internal static void Message(object data)
{
_logSource.LogMessage(data);
}
internal static void Warning(object data)
{
_logSource.LogWarning(data);
}
}
public static class PlayerCatchupManager
{
private static readonly Dictionary<ItemTier, float> TierWeights = new Dictionary<ItemTier, float>
{
[(ItemTier)0] = 1f,
[(ItemTier)1] = 3f,
[(ItemTier)2] = 10f,
[(ItemTier)4] = 15f
};
private static readonly HashSet<ItemTier> IgnoredTiers = new HashSet<ItemTier>
{
(ItemTier)3,
(ItemTier)6,
(ItemTier)7,
(ItemTier)8,
(ItemTier)9,
(ItemTier)5
};
public static ItemTier? GetCatchupTier(NetworkUser user)
{
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
List<NetworkUser> players = GetPlayers();
if (players.Count <= 1)
{
return null;
}
Dictionary<uint, Dictionary<ItemTier, int>> dictionary = new Dictionary<uint, Dictionary<ItemTier, int>>();
NetworkInstanceId netId;
foreach (NetworkUser item in players)
{
object obj;
if (item == null)
{
obj = null;
}
else
{
CharacterMaster master = item.master;
obj = ((master != null) ? master.inventory : null);
}
if ((Object)obj != (Object)null)
{
netId = ((NetworkBehaviour)item).netId;
dictionary[((NetworkInstanceId)(ref netId)).Value] = CountItemsByTier(item);
}
}
if (dictionary.Count <= 1)
{
return null;
}
netId = ((NetworkBehaviour)user).netId;
if (!dictionary.TryGetValue(((NetworkInstanceId)(ref netId)).Value, out var value))
{
return null;
}
Dictionary<ItemTier, int> dictionary2 = new Dictionary<ItemTier, int>();
foreach (ItemTier tier in TierWeights.Keys)
{
dictionary2[tier] = dictionary.Values.Select((Dictionary<ItemTier, int> c) => c.TryGetValue(tier, out var value3) ? value3 : 0).Max();
}
ItemTier? result = null;
float num = 0f;
foreach (ItemTier key in TierWeights.Keys)
{
int value2;
int num2 = dictionary2[key] - (value.TryGetValue(key, out value2) ? value2 : 0);
if (num2 > 0)
{
float num3 = (float)num2 * TierWeights[key];
if (num3 > num)
{
num = num3;
result = key;
}
}
}
return result;
}
public static int GetDeficit(NetworkUser user, ItemTier tier)
{
//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_0091: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
List<NetworkUser> players = GetPlayers();
if (players.Count <= 1)
{
return 0;
}
Dictionary<uint, Dictionary<ItemTier, int>> dictionary = new Dictionary<uint, Dictionary<ItemTier, int>>();
NetworkInstanceId netId;
foreach (NetworkUser item in players)
{
object obj;
if (item == null)
{
obj = null;
}
else
{
CharacterMaster master = item.master;
obj = ((master != null) ? master.inventory : null);
}
if ((Object)obj != (Object)null)
{
netId = ((NetworkBehaviour)item).netId;
dictionary[((NetworkInstanceId)(ref netId)).Value] = CountItemsByTier(item);
}
}
netId = ((NetworkBehaviour)user).netId;
if (!dictionary.TryGetValue(((NetworkInstanceId)(ref netId)).Value, out var value))
{
return 0;
}
int value2;
int num = (value.TryGetValue(tier, out value2) ? value2 : 0);
int value3;
int num2 = dictionary.Values.Select((Dictionary<ItemTier, int> dict) => dict.TryGetValue(tier, out value3) ? value3 : 0).Max();
return Math.Max(0, num2 - num);
}
public static float GetCatchupChance(int deficit, ItemTier tier)
{
if (deficit <= 0)
{
return 0f;
}
return Math.Min((float)deficit * 0.05f, 0.5f);
}
public static PickupIndex GetRandomPickupForTier(ItemTier tier)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected I4, but got Unknown
//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_0094: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Run.instance == (Object)null)
{
return PickupIndex.none;
}
try
{
List<PickupIndex> list = (int)tier switch
{
0 => Run.instance.availableTier1DropList,
1 => Run.instance.availableTier2DropList,
2 => Run.instance.availableTier3DropList,
4 => Run.instance.availableBossDropList,
_ => null,
};
if (list != null && list.Count > 0)
{
return list[Random.Range(0, list.Count)];
}
}
catch
{
}
return PickupIndex.none;
}
private static List<NetworkUser> GetPlayers()
{
if (NetworkUser.readOnlyInstancesList != null && NetworkUser.readOnlyInstancesList.Count > 0)
{
return NetworkUser.readOnlyInstancesList.ToList();
}
return (from p in PlayerCharacterMasterController.instances
where (Object)(object)((p != null) ? p.networkUser : null) != (Object)null
select p.networkUser).ToList();
}
private static Dictionary<ItemTier, int> CountItemsByTier(NetworkUser user)
{
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
Dictionary<ItemTier, int> dictionary = new Dictionary<ItemTier, int>();
object obj;
if (user == null)
{
obj = null;
}
else
{
CharacterMaster master = user.master;
obj = ((master != null) ? master.inventory : null);
}
Inventory val = (Inventory)obj;
if ((Object)(object)val == (Object)null)
{
return dictionary;
}
foreach (ItemTier value in Enum.GetValues(typeof(ItemTier)))
{
if (!IgnoredTiers.Contains(value))
{
try
{
dictionary[value] = val.GetTotalItemCountOfTier(value);
}
catch
{
dictionary[value] = 0;
}
}
}
return dictionary;
}
}
public class SpawnCustomController : NetworkBehaviour
{
[NetworkMessageHandler(msgType = 969, client = true)]
public static void HandlePickupMessage(NetworkMessage netMsg)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
SpawnCustomMessage spawnCustomMessage = new SpawnCustomMessage();
netMsg.ReadMessage<SpawnCustomMessage>(spawnCustomMessage);
Log.Info($"HandlePickupMessage {spawnCustomMessage.pickupIndex.value}");
CreatePickupDroplet(spawnCustomMessage.pickupIndex, spawnCustomMessage.position);
}
public static void CreatePickupDroplet(PickupIndex pickupIndex, Vector3 position)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: 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_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
CreatePickupInfo val = default(CreatePickupInfo);
val.rotation = Quaternion.identity;
((CreatePickupInfo)(ref val)).pickupIndex = pickupIndex;
CreatePickupInfo val2 = val;
UniquePickup val3 = default(UniquePickup);
((UniquePickup)(ref val3))..ctor(pickupIndex);
GameObject obj = Object.Instantiate<GameObject>(CommandArtifactManager.commandCubePrefab, position, val2.rotation);
PickupIndexNetworker component = obj.GetComponent<PickupIndexNetworker>();
PickupPickerController component2 = obj.GetComponent<PickupPickerController>();
component2.SetOptionsInternal(PickupPickerController.GetOptionsFromPickupState(val3));
if (!NetworkServer.active)
{
((NetworkBehaviour)component2).SetDirtyBit(PickupPickerController.optionsDirtyBit);
}
component.NetworkpickupState = val3;
if (Object.op_Implicit((Object)(object)component.pickupDisplay))
{
component.pickupDisplay.SetPickup(ref val3, false);
}
}
public static void CreatePickupItem(PickupIndex pickupIndex, Vector3 position)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: 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)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: 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_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
if (NetworkServer.active)
{
CreatePickupInfo val = default(CreatePickupInfo);
val.rotation = Quaternion.identity;
val.position = position;
((CreatePickupInfo)(ref val)).pickupIndex = pickupIndex;
CreatePickupInfo val2 = val;
UniquePickup val3 = default(UniquePickup);
((UniquePickup)(ref val3))..ctor(pickupIndex);
GameObject obj = Object.Instantiate<GameObject>(val2.prefabOverride ?? GenericPickupController.pickupPrefab, position, val2.rotation);
GenericPickupController component = obj.GetComponent<GenericPickupController>();
if (Object.op_Implicit((Object)(object)component))
{
component.Network_pickupState = val3;
}
PickupIndexNetworker component2 = obj.GetComponent<PickupIndexNetworker>();
if (Object.op_Implicit((Object)(object)component2))
{
component2.NetworkpickupState = val3;
}
PickupPickerController component3 = obj.GetComponent<PickupPickerController>();
if (Object.op_Implicit((Object)(object)component3) && val2.pickerOptions != null)
{
component3.SetOptionsServer(val2.pickerOptions);
}
NetworkServer.Spawn(obj);
}
}
}
public class SpawnCustomMessage : MessageBase, INetMessage, ISerializableObject
{
public Vector3 position;
public PickupIndex pickupIndex;
public override void Serialize(NetworkWriter writer)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
writer.Write(position);
writer.Write(pickupIndex.value);
}
public override void Deserialize(NetworkReader reader)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
position = reader.ReadVector3();
pickupIndex = new PickupIndex(reader.ReadInt32());
}
public void OnReceived()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
SpawnCustomController.CreatePickupItem(pickupIndex, position);
}
}
public struct SpawnCustomMessage2 : INetMessage, ISerializableObject
{
public Vector3 position;
public PickupIndex pickupIndex;
public void Serialize(NetworkWriter writer)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
writer.Write(position);
writer.Write(pickupIndex.value);
}
public void Deserialize(NetworkReader reader)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
position = reader.ReadVector3();
pickupIndex = new PickupIndex(reader.ReadInt32());
}
public void OnReceived()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
SpawnCustomController.CreatePickupItem(pickupIndex, position);
}
public SpawnCustomMessage2(PickupIndex pickupIndex, Vector3 position)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: 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_0009: Unknown result type (might be due to invalid IL or missing references)
this.position = position;
this.pickupIndex = pickupIndex;
}
}
}