Decompiled source of RolledLootDistribution v1.0.1

Erenshor.RolledLootDistribution.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Erenshor.RolledLootDistribution")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("Erenshor.RolledLootDistribution")]
[assembly: AssemblyTitle("Erenshor.RolledLootDistribution")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace ErenshorRolledLoot;

[BepInPlugin("repdm.erenshor.rolledlootdistribution", "Rolled Loot Distribution", "1.0.1")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "repdm.erenshor.rolledlootdistribution";

	public const string PluginName = "Rolled Loot Distribution";

	public const string PluginVersion = "1.0.1";

	internal static ConfigEntry<bool> EnabledSetting;

	internal static ConfigEntry<int> RollMaximumSetting;

	internal static ConfigEntry<string> ChatColorSetting;

	internal static IRandomRollProvider RollProvider = new UnityRandomRollProvider();

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected O, but got Unknown
		EnabledSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Rolled Distribution", true, "Adds the Rolled Distribution target to the native loot distribution window.");
		RollMaximumSetting = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Roll Maximum", 100, new ConfigDescription("Inclusive maximum for loot rolls.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 100000), new object[0]));
		ChatColorSetting = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Chat Color", "#00B2B7", "HTML color used for roll messages.");
		_harmony = new Harmony("repdm.erenshor.rolledlootdistribution");
		_harmony.PatchAll(typeof(Plugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Rolled Loot Distribution 1.0.1 loaded.");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal interface IRandomRollProvider
{
	int Roll(int inclusiveMaximum);
}
internal sealed class UnityRandomRollProvider : IRandomRollProvider
{
	public int Roll(int inclusiveMaximum)
	{
		return Random.Range(1, inclusiveMaximum + 1);
	}
}
internal sealed class DistributionState
{
	internal RaidLootDist Distribution;

	internal ItemIcon RollSlot;

	internal Item RolledItem;

	internal SimPlayer Winner;

	internal RectTransform NativeSlotRect;

	internal RectTransform RollSlotRect;

	internal RectTransform NormalLabelRect;

	internal RectTransform RollLabelRect;

	internal float HorizontalOffset;

	internal readonly Dictionary<LootAwardSlot, Color> OriginalColors = new Dictionary<LootAwardSlot, Color>();
}
internal static class RolledLootController
{
	private const string WinnerMarker = "  [ROLL WINNER]";

	private static readonly Dictionary<RaidLootDist, DistributionState> States = new Dictionary<RaidLootDist, DistributionState>();

	internal static void Initialize(RaidLootDist distribution)
	{
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: 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_0183: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.EnabledSetting.Value || (Object)(object)distribution == (Object)null || (Object)(object)distribution.AwardSlot == (Object)null || States.ContainsKey(distribution))
		{
			return;
		}
		GameObject val = Object.Instantiate<GameObject>(((Component)distribution.AwardSlot).gameObject, ((Component)distribution.AwardSlot).transform.parent, false);
		((Object)val).name = "Rolled Distribution Slot";
		ItemIcon component = val.GetComponent<ItemIcon>();
		if ((Object)(object)component == (Object)null)
		{
			Object.Destroy((Object)(object)val);
			return;
		}
		component.MyItem = GameData.PlayerInv.Empty;
		component.DistSlot = true;
		component.DisplayOnly = false;
		component.UpdateSlotImage();
		Transform transform = ((Component)distribution.AwardSlot).transform;
		RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
		Transform transform2 = ((Component)component).transform;
		RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
		float num;
		if ((Object)(object)val2 != (Object)null)
		{
			Rect rect = val2.rect;
			if (((Rect)(ref rect)).width > 0f)
			{
				rect = val2.rect;
				num = ((Rect)(ref rect)).width;
				goto IL_00eb;
			}
		}
		num = 64f;
		goto IL_00eb;
		IL_00eb:
		float num2 = num;
		float num3 = num2 + 24f;
		IgnoreAutomaticLayout(((Component)distribution.AwardSlot).gameObject);
		IgnoreAutomaticLayout(val);
		if ((Object)(object)val3 != (Object)null && (Object)(object)val2 != (Object)null)
		{
			val3.anchoredPosition = val2.anchoredPosition + new Vector2(num3, 0f);
		}
		RectTransform val4 = (RectTransform)(((Object)(object)distribution.DistWindow != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val4 != (Object)null)
		{
			val4.sizeDelta += new Vector2(num2 + 22f, 0f);
		}
		RectTransform normalLabelRect = CreateLabel(distribution, ((Component)distribution.AwardSlot).transform, "Normal\nDistribution", new Vector2(0f, num2 * 0.78f));
		RectTransform rollLabelRect = CreateLabel(distribution, ((Component)component).transform, "Rolled\nDistribution", new Vector2(0f, num2 * 0.78f));
		States.Add(distribution, new DistributionState
		{
			Distribution = distribution,
			RollSlot = component,
			NativeSlotRect = val2,
			RollSlotRect = val3,
			NormalLabelRect = normalLabelRect,
			RollLabelRect = rollLabelRect,
			HorizontalOffset = num3
		});
	}

	private static void IgnoreAutomaticLayout(GameObject target)
	{
		LayoutElement val = target.GetComponent<LayoutElement>();
		if ((Object)(object)val == (Object)null)
		{
			val = target.AddComponent<LayoutElement>();
		}
		val.ignoreLayout = true;
	}

	private static RectTransform CreateLabel(RaidLootDist distribution, Transform slot, string text, Vector2 offset)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(text + " Label", new Type[2]
		{
			typeof(RectTransform),
			typeof(TextMeshProUGUI)
		});
		val.transform.SetParent(slot.parent, false);
		IgnoreAutomaticLayout(val);
		RectTransform val2 = (RectTransform)val.transform;
		RectTransform val3 = (RectTransform)(object)((slot is RectTransform) ? slot : null);
		val2.anchorMin = val3.anchorMin;
		val2.anchorMax = val3.anchorMax;
		val2.pivot = new Vector2(0.5f, 0.5f);
		val2.anchoredPosition = val3.anchoredPosition + offset;
		val2.sizeDelta = new Vector2(76f, 38f);
		TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).text = text;
		((TMP_Text)component).alignment = (TextAlignmentOptions)514;
		((TMP_Text)component).fontSize = 13f;
		((TMP_Text)component).enableWordWrapping = false;
		((TMP_Text)component).overflowMode = (TextOverflowModes)0;
		((Graphic)component).raycastTarget = false;
		if ((Object)(object)distribution.LootDistButton != (Object)null)
		{
			((TMP_Text)component).font = ((TMP_Text)distribution.LootDistButton).font;
			((Graphic)component).color = ((Graphic)distribution.LootDistButton).color;
		}
		return val2;
	}

	internal static void Tick(RaidLootDist distribution)
	{
		if (States.TryGetValue(distribution, out var value) && !((Object)(object)value.RollSlot == (Object)null))
		{
			EnforceLayout(value);
			Item val = (((Object)(object)GameData.PlayerInv != (Object)null) ? GameData.PlayerInv.Empty : null);
			Item myItem = value.RollSlot.MyItem;
			if ((Object)(object)myItem != (Object)null && (Object)(object)myItem != (Object)(object)val)
			{
				ClearWinner(value);
				ProcessItem(value, myItem, val);
			}
			if ((Object)(object)value.RolledItem != (Object)null && (Object)(object)distribution.AwardSlot.MyItem != (Object)(object)value.RolledItem)
			{
				ClearWinner(value);
				value.RolledItem = null;
			}
			ApplyWinnerHighlight(value);
		}
	}

	private static void EnforceLayout(DistributionState state)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: 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_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: 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)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//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)
		if (!((Object)(object)state.NativeSlotRect == (Object)null) && !((Object)(object)state.RollSlotRect == (Object)null))
		{
			Vector2 anchoredPosition = state.NativeSlotRect.anchoredPosition;
			state.RollSlotRect.anchoredPosition = anchoredPosition + new Vector2(state.HorizontalOffset, 0f);
			if ((Object)(object)state.NormalLabelRect != (Object)null)
			{
				state.NormalLabelRect.anchoredPosition = anchoredPosition + new Vector2(0f, 50f);
			}
			if ((Object)(object)state.RollLabelRect != (Object)null)
			{
				state.RollLabelRect.anchoredPosition = state.RollSlotRect.anchoredPosition + new Vector2(0f, 50f);
			}
		}
	}

	private static void ProcessItem(DistributionState state, Item item, Item empty)
	{
		state.RollSlot.MyItem = empty;
		state.RollSlot.UpdateSlotImage();
		state.Distribution.AwardSlot.MyItem = item;
		state.Distribution.AwardSlot.UpdateSlotImage();
		state.RolledItem = item;
		if (!IsSupportedGear(item))
		{
			AddChat("Rolled Distribution only supports equippable gear; " + item.ItemName + " was moved to Normal Distribution.");
			return;
		}
		List<SimPlayer> interestedPlayers = GetInterestedPlayers(state.Distribution, item);
		if (interestedPlayers.Count == 0)
		{
			AddChat("No SimPlayers are interested in " + item.ItemName + ". It remains available for Normal Distribution.");
			return;
		}
		if (interestedPlayers.Count == 1)
		{
			state.Winner = interestedPlayers[0];
			AddChat(GetName(state.Winner) + " is the only SimPlayer interested in " + item.ItemName + " and wins by default.");
			return;
		}
		AddChat("Rolling 1-" + Plugin.RollMaximumSetting.Value + " for " + item.ItemName + ".");
		List<SimPlayer> list = RollRound(interestedPlayers, tieBreak: false);
		while (list.Count > 1)
		{
			AddChat("Tie between " + JoinNames(list) + ". Rerolling tied leaders.");
			list = RollRound(list, tieBreak: true);
		}
		state.Winner = list[0];
		AddChat(GetName(state.Winner) + " wins " + item.ItemName + ". Use the highlighted native Give row to award it.");
	}

	private static List<SimPlayer> RollRound(List<SimPlayer> entrants, bool tieBreak)
	{
		int num = 0;
		List<SimPlayer> list = new List<SimPlayer>();
		for (int i = 0; i < entrants.Count; i++)
		{
			int num2 = Plugin.RollProvider.Roll(Plugin.RollMaximumSetting.Value);
			AddChat(GetName(entrants[i]) + " rolls " + num2 + (tieBreak ? " (tiebreak)." : "."));
			if (num2 > num)
			{
				num = num2;
				list.Clear();
				list.Add(entrants[i]);
			}
			else if (num2 == num)
			{
				list.Add(entrants[i]);
			}
		}
		return list;
	}

	private static List<SimPlayer> GetInterestedPlayers(RaidLootDist distribution, Item item)
	{
		List<SimPlayer> result = new List<SimPlayer>();
		if (distribution.UseGroup)
		{
			SimPlayerTracking[] groupMembers = GameData.GroupMembers;
			if (groupMembers != null)
			{
				for (int i = 0; i < groupMembers.Length; i++)
				{
					TryAddInterested(result, (groupMembers[i] != null) ? groupMembers[i].MyAvatar : null, item);
				}
			}
		}
		else if ((Object)(object)GameData.RaidManager != (Object)null && GameData.RaidManager.Raiders != null)
		{
			for (int j = 0; j < GameData.RaidManager.Raiders.Count; j++)
			{
				RaidMemberSlot val = GameData.RaidManager.Raiders[j];
				TryAddInterested(result, ((Object)(object)val != (Object)null) ? val.AssignedAvatar : null, item);
			}
		}
		return result;
	}

	private static void TryAddInterested(List<SimPlayer> result, SimPlayer player, Item item)
	{
		if ((Object)(object)player != (Object)null && !result.Contains(player) && player.IsThatAnUpgrade(item))
		{
			result.Add(player);
		}
	}

	private static bool IsSupportedGear(Item item)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)item == (Object)null || item.SimPlayersCantGet || Convert.ToInt32(item.RequiredSlot) == 0)
		{
			return false;
		}
		if ((Object)(object)item.TeachSpell != (Object)null || (Object)(object)item.TeachSkill != (Object)null || item.Stackable)
		{
			return false;
		}
		if ((Object)(object)GameData.GM != (Object)null && ((Object)(object)item == (Object)(object)GameData.GM.Sivak || (Object)(object)item == (Object)(object)GameData.GM.Planar))
		{
			return false;
		}
		return true;
	}

	private static void ApplyWinnerHighlight(DistributionState state)
	{
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)state.Winner == (Object)null || state.Distribution.Recipients == null)
		{
			return;
		}
		for (int i = 0; i < state.Distribution.Recipients.Count; i++)
		{
			LootAwardSlot val = state.Distribution.Recipients[i];
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.SP != (Object)(object)state.Winner) && ((Component)val).gameObject.activeInHierarchy && !((Object)(object)val.AwardButtonTxt == (Object)null))
			{
				if (!state.OriginalColors.ContainsKey(val))
				{
					state.OriginalColors.Add(val, ((Graphic)val.AwardButtonTxt).color);
				}
				if (!((TMP_Text)val.AwardButtonTxt).text.Contains("  [ROLL WINNER]"))
				{
					TextMeshProUGUI awardButtonTxt = val.AwardButtonTxt;
					((TMP_Text)awardButtonTxt).text = ((TMP_Text)awardButtonTxt).text + "  [ROLL WINNER]";
				}
				((Graphic)val.AwardButtonTxt).color = Color.yellow;
			}
		}
	}

	internal static void Clear(RaidLootDist distribution)
	{
		if (!States.TryGetValue(distribution, out var value))
		{
			return;
		}
		ClearWinner(value);
		value.RolledItem = null;
		if ((Object)(object)value.RollSlot != (Object)null && (Object)(object)GameData.PlayerInv != (Object)null)
		{
			Item myItem = value.RollSlot.MyItem;
			if ((Object)(object)myItem != (Object)null && (Object)(object)myItem != (Object)(object)GameData.PlayerInv.Empty && (Object)(object)distribution.AwardSlot != (Object)null && (Object)(object)distribution.AwardSlot.MyItem == (Object)(object)GameData.PlayerInv.Empty)
			{
				distribution.AwardSlot.MyItem = myItem;
				distribution.AwardSlot.UpdateSlotImage();
			}
			value.RollSlot.MyItem = GameData.PlayerInv.Empty;
			value.RollSlot.UpdateSlotImage();
		}
	}

	private static void ClearWinner(DistributionState state)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<LootAwardSlot, Color> originalColor in state.OriginalColors)
		{
			if ((Object)(object)originalColor.Key != (Object)null && (Object)(object)originalColor.Key.AwardButtonTxt != (Object)null)
			{
				((TMP_Text)originalColor.Key.AwardButtonTxt).text = ((TMP_Text)originalColor.Key.AwardButtonTxt).text.Replace("  [ROLL WINNER]", string.Empty);
				((Graphic)originalColor.Key.AwardButtonTxt).color = originalColor.Value;
			}
		}
		state.OriginalColors.Clear();
		state.Winner = null;
	}

	private static string GetName(SimPlayer player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return "Unknown SimPlayer";
		}
		NPC thisNPC = player.GetThisNPC();
		if (!((Object)(object)thisNPC != (Object)null) || string.IsNullOrEmpty(((Object)thisNPC).name))
		{
			return ((Object)player).name;
		}
		return ((Object)thisNPC).name;
	}

	private static string JoinNames(List<SimPlayer> players)
	{
		string[] array = new string[players.Count];
		for (int i = 0; i < players.Count; i++)
		{
			array[i] = GetName(players[i]);
		}
		return string.Join(", ", array);
	}

	private static void AddChat(string message)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		UpdateSocialLog.LogAdd(new ChatLogLine("[LOOT ROLL] " + message, (LogType)4194304, Plugin.ChatColorSetting.Value));
	}
}
[HarmonyPatch(typeof(RaidLootDist), "Start")]
internal static class RaidLootStartPatch
{
	private static void Postfix(RaidLootDist __instance)
	{
		RolledLootController.Initialize(__instance);
	}
}
[HarmonyPatch(typeof(RaidLootDist), "Update")]
internal static class RaidLootUpdatePatch
{
	private static void Postfix(RaidLootDist __instance)
	{
		RolledLootController.Tick(__instance);
	}
}
[HarmonyPatch(typeof(RaidLootDist), "CloseDistWindow")]
internal static class RaidLootClosePatch
{
	private static void Prefix(RaidLootDist __instance)
	{
		RolledLootController.Clear(__instance);
	}
}
[HarmonyPatch(typeof(RaidLootDist), "OpenCloseDistWindow")]
internal static class RaidLootTogglePatch
{
	private static void Prefix(RaidLootDist __instance)
	{
		if ((Object)(object)__instance.DistWindow != (Object)null && __instance.DistWindow.activeSelf)
		{
			RolledLootController.Clear(__instance);
		}
	}
}
[HarmonyPatch(typeof(LootAwardSlot), "AwardItemToSim")]
internal static class AwardItemPatch
{
	private static void Postfix()
	{
		if ((Object)(object)GameData.GroupLootDist != (Object)null)
		{
			RolledLootController.Clear(GameData.GroupLootDist);
		}
	}
}
[HarmonyPatch(typeof(LootAwardSlot), "AwardItemToSimPrim")]
internal static class AwardPrimaryPatch
{
	private static void Postfix()
	{
		if ((Object)(object)GameData.GroupLootDist != (Object)null)
		{
			RolledLootController.Clear(GameData.GroupLootDist);
		}
	}
}
[HarmonyPatch(typeof(LootAwardSlot), "AwardItemToSimSec")]
internal static class AwardSecondaryPatch
{
	private static void Postfix()
	{
		if ((Object)(object)GameData.GroupLootDist != (Object)null)
		{
			RolledLootController.Clear(GameData.GroupLootDist);
		}
	}
}