Decompiled source of PersonalLoot v0.1.1

plugins/PersonalLoot.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Serialization;
using BepInEx;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace PersonalLoot;

[Serializable]
public class LootEntry
{
	public string Key;

	public string Name;

	public int ItemId;

	public int Quantity;

	public string SaveData;

	public bool Silver;
}
[Serializable]
public class LootSource
{
	public string Key;

	public int CapturedSilver;

	public List<LootEntry> Entries = new List<LootEntry>();
}
[Serializable]
public class LootClaim
{
	public string Key;

	public string CreatedItemUid;

	public bool Complete;
}
[Serializable]
public class LootLedger
{
	public int Version = 1;

	public List<LootSource> Sources = new List<LootSource>();

	public List<LootClaim> Claims = new List<LootClaim>();

	public static string Hash(string value)
	{
		using SHA256 sHA = SHA256.Create();
		return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(value))).Replace("-", "").ToLowerInvariant();
	}

	public static string ClaimKey(string player, string source, string entry)
	{
		return Hash(player.Length + ":" + player + source.Length + ":" + source + entry);
	}

	public LootClaim Find(string player, string source, string entry)
	{
		string key = ClaimKey(player, source, entry);
		return Claims.FirstOrDefault((LootClaim c) => c.Key == key);
	}

	public LootClaim Reserve(string player, string source, string entry)
	{
		LootClaim lootClaim = Find(player, source, entry);
		if (lootClaim != null)
		{
			return lootClaim;
		}
		LootClaim lootClaim2 = new LootClaim
		{
			Key = ClaimKey(player, source, entry),
			CreatedItemUid = "PL_" + Guid.NewGuid().ToString("N")
		};
		Claims.Add(lootClaim2);
		return lootClaim2;
	}

	public static LootLedger Load(string path)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (!File.Exists(path))
		{
			return new LootLedger();
		}
		using FileStream fileStream = File.OpenRead(path);
		LootLedger obj = (LootLedger)new XmlSerializer(typeof(LootLedger)).Deserialize((Stream)fileStream);
		if (obj.Version != 1)
		{
			throw new InvalidDataException("Unsupported personal loot ledger version.");
		}
		return obj;
	}

	public void Save(string path)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		Directory.CreateDirectory(Path.GetDirectoryName(path));
		string text = path + ".tmp";
		using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None))
		{
			new XmlSerializer(typeof(LootLedger)).Serialize((Stream)fileStream, (object)this);
			fileStream.Flush(flushToDisk: true);
		}
		if (File.Exists(path))
		{
			File.Replace(text, path, path + ".bak");
		}
		else
		{
			File.Move(text, path);
		}
	}
}
public class LootMessage
{
	public string Operation;

	public string Player;

	public string Container;

	public string Entry;

	public string Request;

	public string Error;

	public List<LootEntry> Entries = new List<LootEntry>();
}
public static class LootWire
{
	public const string Protocol = "local.personal_loot.v2";

	public static string[] Encode(LootMessage message)
	{
		List<string> list = new List<string>
		{
			"local.personal_loot.v2",
			message.Operation ?? "",
			message.Player ?? "",
			message.Container ?? "",
			message.Entry ?? "",
			message.Request ?? "",
			message.Error ?? "",
			message.Entries.Count.ToString(CultureInfo.InvariantCulture)
		};
		foreach (LootEntry entry in message.Entries)
		{
			list.Add(entry.Key ?? "");
			list.Add(entry.Name ?? "");
			list.Add(entry.ItemId.ToString(CultureInfo.InvariantCulture));
			list.Add(entry.Quantity.ToString(CultureInfo.InvariantCulture));
			list.Add(entry.Silver ? "1" : "0");
		}
		return list.ToArray();
	}

	public static LootMessage Decode(string[] fields)
	{
		if (fields == null || fields.Length < 8 || fields[0] != "local.personal_loot.v2")
		{
			throw new InvalidDataException("Unsupported Personal Loot packet. Install 0.1.1 on every computer.");
		}
		if (!int.TryParse(fields[7], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result > 10000 || fields.Length != 8 + result * 5)
		{
			throw new InvalidDataException("Incomplete personal loot list.");
		}
		LootMessage lootMessage = new LootMessage
		{
			Operation = fields[1],
			Player = fields[2],
			Container = fields[3],
			Entry = fields[4],
			Request = fields[5],
			Error = fields[6]
		};
		for (int i = 0; i < result; i++)
		{
			int num = 8 + i * 5;
			if (string.IsNullOrEmpty(fields[num]) || !int.TryParse(fields[num + 2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(fields[num + 3], NumberStyles.None, CultureInfo.InvariantCulture, out var result3) || result3 < 1 || (fields[num + 4] != "0" && fields[num + 4] != "1"))
			{
				throw new InvalidDataException("Invalid personal loot item.");
			}
			lootMessage.Entries.Add(new LootEntry
			{
				Key = fields[num],
				Name = fields[num + 1],
				ItemId = result2,
				Quantity = result3,
				Silver = (fields[num + 4] == "1")
			});
		}
		return lootMessage;
	}
}
[BepInPlugin("local.personal_loot", "Personal Loot", "0.1.1")]
public sealed class PersonalLootPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "local.personal_loot";

	internal static PersonalLootPlugin Instance;

	private Harmony harmony;

	private byte eventCode;

	private LootLedger ledger;

	private string ledgerPath;

	private string worldId;

	private readonly HashSet<string> busyClaims = new HashSet<string>();

	private Character viewingPlayer;

	private ItemContainer viewingContainer;

	private LootMessage displayed;

	private string requestId;

	private string status;

	private float requestedAt;

	private bool waiting;

	private Vector2 scroll;

	private CanvasGroup inventoryInput;

	private bool previousInteractable;

	private bool previousRaycasts;

	private static bool IsHost => !PhotonNetwork.isNonMasterClientInRoom;

	private void Awake()
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Expected O, but got Unknown
		Instance = this;
		eventCode = ((BaseUnityPlugin)this).Config.Bind<byte>("Network", "EventCode", (byte)182, "Custom Photon event code (1-199). All players must use the same free code. Kyazh Power uses 181.").Value;
		if (eventCode < 1 || eventCode > 199)
		{
			eventCode = 182;
		}
		PhotonNetwork.OnEventCall += new EventCallback(OnEvent);
		SceneManager.sceneLoaded += OnScene;
		harmony = new Harmony("local.personal_loot");
		harmony.PatchAll(typeof(PersonalLootPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Personal Loot 0.1.1 loaded. Install on host and every client.");
	}

	internal static bool Supported(ItemContainer container)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Invalid comparison between Unknown and I4
		if (!Object.op_Implicit((Object)(object)container))
		{
			return false;
		}
		if (container is TreasureChest)
		{
			return (int)container.SpecialType == 0;
		}
		Character ownerCharacter = ((EffectSynchronizer)container).OwnerCharacter;
		if (Object.op_Implicit((Object)(object)ownerCharacter) && ownerCharacter.IsAI && ownerCharacter.IsDead && Object.op_Implicit((Object)(object)ownerCharacter.Inventory))
		{
			return (Object)(object)ownerCharacter.Inventory.Pouch == (Object)(object)container;
		}
		return false;
	}

	internal void Open(ItemContainer container, Character player)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)player) || !player.IsLocalPlayer || !Supported(container))
		{
			return;
		}
		Close();
		viewingPlayer = player;
		viewingContainer = container;
		displayed = null;
		scroll = Vector2.zero;
		player.CharacterUI.ShowMenu((MenuScreens)2);
		if (Object.op_Implicit((Object)(object)player.CharacterUI.InventoryPanel))
		{
			inventoryInput = ((Component)player.CharacterUI.InventoryPanel).GetComponent<CanvasGroup>();
			if (!Object.op_Implicit((Object)(object)inventoryInput))
			{
				inventoryInput = ((Component)player.CharacterUI.InventoryPanel).gameObject.AddComponent<CanvasGroup>();
			}
			previousInteractable = inventoryInput.interactable;
			previousRaycasts = inventoryInput.blocksRaycasts;
			inventoryInput.interactable = false;
			inventoryInput.blocksRaycasts = false;
		}
		Request("open", null);
	}

	private void Request(string operation, string entry)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Expected O, but got Unknown
		if (Object.op_Implicit((Object)(object)viewingPlayer) && Object.op_Implicit((Object)(object)viewingContainer))
		{
			requestId = Guid.NewGuid().ToString("N");
			LootMessage message = new LootMessage
			{
				Operation = operation,
				Player = UID.op_Implicit(viewingPlayer.UID),
				Container = ((Item)viewingContainer).UID,
				Entry = entry,
				Request = requestId
			};
			waiting = true;
			requestedAt = Time.unscaledTime;
			status = ((operation == "open") ? "Loading your loot…" : "Taking item…");
			if (IsHost)
			{
				HandleRequest(message, (PhotonNetwork.player != null) ? PhotonNetwork.player.ID : 0);
			}
			else if (!PhotonNetwork.RaiseEvent(eventCode, (object)LootWire.Encode(message), true, new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)2
			}))
			{
				waiting = false;
				status = "Could not send the loot request. Reconnect and press Refresh.";
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Request " + operation + " " + requestId + " host=" + IsHost + " event=" + eventCode));
		}
	}

	private void OnEvent(byte code, object payload, int sender)
	{
		if (code != eventCode)
		{
			return;
		}
		try
		{
			LootMessage lootMessage = LootWire.Decode(payload as string[]);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Received " + lootMessage.Operation + " " + lootMessage.Request + " from actor=" + sender + " entries=" + lootMessage.Entries.Count));
			if (lootMessage.Operation == "result")
			{
				if (PhotonNetwork.masterClient != null && sender == PhotonNetwork.masterClient.ID)
				{
					ShowResult(lootMessage);
				}
			}
			else if (IsHost)
			{
				HandleRequest(lootMessage, sender);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Personal loot message rejected: " + ex.Message));
			if (waiting && PhotonNetwork.masterClient != null && sender == PhotonNetwork.masterClient.ID)
			{
				waiting = false;
				status = "Could not read host loot. Install Personal Loot 0.1.1 on every computer, then restart.";
			}
		}
	}

	private Character Validate(LootMessage message, int sender, out ItemContainer source)
	{
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		source = null;
		if (string.IsNullOrEmpty(message.Player) || string.IsNullOrEmpty(message.Container) || !Object.op_Implicit((Object)(object)CharacterManager.Instance) || !Object.op_Implicit((Object)(object)ItemManager.Instance))
		{
			return null;
		}
		Character character = CharacterManager.Instance.GetCharacter(message.Player);
		if (!Object.op_Implicit((Object)(object)character) || character.IsAI || character.IsDead || !Object.op_Implicit((Object)(object)character.OwnerPlayerSys))
		{
			return null;
		}
		PhotonPlayer photonOwner = character.OwnerPlayerSys.PhotonOwner;
		if (PhotonNetwork.inRoom && photonOwner != null && photonOwner.ID != sender)
		{
			return null;
		}
		if (PhotonNetwork.inRoom && photonOwner == null && !character.IsPhotonPlayerLocal)
		{
			return null;
		}
		Item item = ItemManager.Instance.GetItem(message.Container);
		source = (ItemContainer)(object)((item is ItemContainer) ? item : null);
		if (!Supported(source))
		{
			return null;
		}
		if (Vector3.Distance(((Component)character).transform.position, ((Component)source).transform.position) > 12f)
		{
			return null;
		}
		return character;
	}

	private void EnsureLedger()
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		Character worldHostCharacter = CharacterManager.Instance.GetWorldHostCharacter();
		if (!Object.op_Implicit((Object)(object)worldHostCharacter))
		{
			throw new InvalidOperationException("The world host is not ready.");
		}
		string text = UID.op_Implicit(worldHostCharacter.UID);
		if (ledger == null || !(text == worldId))
		{
			string path = Path.Combine(Paths.ConfigPath, "PersonalLoot", LootLedger.Hash(text) + ".xml");
			LootLedger lootLedger = LootLedger.Load(path);
			ledger = lootLedger;
			worldId = text;
			ledgerPath = path;
		}
	}

	private static string SourceKey(ItemContainer source)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		return ((Scene)(ref activeScene)).name + "|" + ((Item)source).UID;
	}

	private LootSource Capture(ItemContainer source)
	{
		EnsureLedger();
		TreasureChest val = (TreasureChest)(object)((source is TreasureChest) ? source : null);
		if (Object.op_Implicit((Object)(object)val) && !val.HasGeneratedContent)
		{
			((SelfFilledItemContainer)val).GenerateContents();
		}
		List<Item> list = (from i in source.GetContainedItems()
			where Object.op_Implicit((Object)(object)i) && ((EffectSynchronizer)i).FullyInitialized
			select i).ToList();
		string key = SourceKey(source);
		LootSource lootSource = ledger.Sources.FirstOrDefault((LootSource s) => s.Key == key);
		if (lootSource != null)
		{
			HashSet<string> oldIds = new HashSet<string>(from e in lootSource.Entries
				where !e.Silver
				select e.Key);
			if (oldIds.Count > 0 && list.Count > 0 && !list.Any((Item i) => oldIds.Contains(i.UID)))
			{
				ledger.Sources.Remove(lootSource);
				lootSource = null;
			}
		}
		if (lootSource == null)
		{
			lootSource = new LootSource
			{
				Key = key
			};
			ledger.Sources.Add(lootSource);
		}
		bool flag = false;
		foreach (Item item in list)
		{
			if (!lootSource.Entries.Any((LootEntry e) => e.Key == item.UID))
			{
				lootSource.Entries.Add(new LootEntry
				{
					Key = item.UID,
					ItemId = item.ItemID,
					Name = item.Name,
					Quantity = Math.Max(1, item.RemainingAmount),
					SaveData = item.ToSaveData()
				});
				flag = true;
			}
		}
		if (source.ContainedSilver > lootSource.CapturedSilver)
		{
			lootSource.Entries.Add(new LootEntry
			{
				Key = "silver_" + Guid.NewGuid().ToString("N"),
				Name = "Silver",
				Silver = true,
				Quantity = source.ContainedSilver - lootSource.CapturedSilver
			});
			lootSource.CapturedSilver = source.ContainedSilver;
			flag = true;
		}
		if (flag)
		{
			ledger.Save(ledgerPath);
		}
		return lootSource;
	}

	internal void ResetChest(TreasureChest chest)
	{
		if (!IsHost || !Supported((ItemContainer)(object)chest) || !Object.op_Implicit((Object)(object)CharacterManager.Instance))
		{
			return;
		}
		try
		{
			EnsureLedger();
			string key = SourceKey((ItemContainer)(object)chest);
			if (ledger.Sources.RemoveAll((LootSource s) => s.Key == key) > 0)
			{
				ledger.Save(ledgerPath);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not reset personal chest snapshot: " + ex));
		}
	}

	private void HandleRequest(LootMessage message, int sender)
	{
		try
		{
			ItemContainer source;
			Character val = Validate(message, sender, out source);
			if (!Object.op_Implicit((Object)(object)val))
			{
				Reply(message, sender, null, "This loot source is unavailable or too far away.");
				return;
			}
			TreasureChest val2 = (TreasureChest)(object)((source is TreasureChest) ? source : null);
			if (Object.op_Implicit((Object)(object)val2) && !val2.HasGeneratedContent)
			{
				((SelfFilledItemContainer)val2).GenerateContents();
			}
			if (source.GetContainedItems().Any((Item i) => Object.op_Implicit((Object)(object)i) && !((EffectSynchronizer)i).FullyInitialized))
			{
				((MonoBehaviour)this).StartCoroutine(WaitForLoot(message, sender, source));
				return;
			}
			LootSource lootSource = Capture(source);
			if (message.Operation == "open")
			{
				Reply(message, sender, lootSource, null);
			}
			else
			{
				if (message.Operation != "take")
				{
					return;
				}
				LootEntry lootEntry = lootSource.Entries.FirstOrDefault((LootEntry e) => e.Key == message.Entry);
				if (lootEntry == null)
				{
					Reply(message, sender, lootSource, "That item is no longer available.");
					return;
				}
				LootClaim lootClaim = ledger.Reserve(message.Player, lootSource.Key, lootEntry.Key);
				if (lootClaim.Complete)
				{
					Reply(message, sender, lootSource, null);
					return;
				}
				if (!busyClaims.Add(lootClaim.Key))
				{
					Reply(message, sender, lootSource, "This item is already being delivered.");
					return;
				}
				try
				{
					ledger.Save(ledgerPath);
				}
				catch
				{
					busyClaims.Remove(lootClaim.Key);
					throw;
				}
				((MonoBehaviour)this).StartCoroutine(Deliver(message, sender, val, lootSource, lootEntry, lootClaim, ledger, ledgerPath));
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Personal loot request failed: " + ex));
			Reply(message, sender, null, "Could not load or save personal loot. Check BepInEx/LogOutput.log.");
		}
	}

	private IEnumerator WaitForLoot(LootMessage request, int sender, ItemContainer source)
	{
		float deadline = Time.realtimeSinceStartup + 5f;
		while (Object.op_Implicit((Object)(object)source) && Time.realtimeSinceStartup < deadline)
		{
			if (!source.GetContainedItems().Any((Item i) => Object.op_Implicit((Object)(object)i) && !((EffectSynchronizer)i).FullyInitialized))
			{
				HandleRequest(request, sender);
				yield break;
			}
			yield return null;
		}
		Reply(request, sender, null, "Loot is still loading. Press Refresh to try again.");
	}

	private IEnumerator Deliver(LootMessage request, int sender, Character player, LootSource source, LootEntry entry, LootClaim claim, LootLedger claimLedger, string path)
	{
		string error = null;
		if (entry.Silver)
		{
			try
			{
				claim.Complete = true;
				claimLedger.Save(path);
				player.Inventory.Pouch.AddSilver(entry.Quantity, true);
			}
			catch (Exception ex)
			{
				error = "Silver delivery failed; inspect the log before retrying.";
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}
		else
		{
			Item copy = ItemManager.Instance.GetItem(claim.CreatedItemUid);
			try
			{
				if (!Object.op_Implicit((Object)(object)copy))
				{
					string[] array = Item.GetSyncDataFromSaveData(entry.SaveData).Split(new char[1] { '|' });
					if (array.Length < 21)
					{
						throw new InvalidDataException("Incomplete saved item data.");
					}
					array[0] = claim.CreatedItemUid;
					array[2] = "0";
					array[4] = "1" + ((Item)player.Inventory.Pouch).UID + ";" + ((Item)player.Inventory.Pouch).ItemID;
					array[5] = "False";
					array[6] = "";
					array[7] = "";
					array[8] = "";
					array[11] = "-1";
					array[20] = "-";
					ItemManager.Instance.OnReceiveItemSync(string.Join("|", array), (ItemSyncType)0, request.Player);
				}
			}
			catch (Exception ex2)
			{
				error = "Item creation failed; check the log.";
				((BaseUnityPlugin)this).Logger.LogError((object)ex2);
			}
			float deadline = Time.realtimeSinceStartup + 12f;
			while (error == null && Object.op_Implicit((Object)(object)player) && Time.realtimeSinceStartup < deadline)
			{
				copy = ItemManager.Instance.GetItem(claim.CreatedItemUid);
				if (Object.op_Implicit((Object)(object)copy) && ((EffectSynchronizer)copy).FullyInitialized && copy.IsSynced && (Object)(object)((EffectSynchronizer)copy).OwnerCharacter == (Object)(object)player)
				{
					break;
				}
				yield return null;
			}
			if (error == null)
			{
				if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)copy) || !((EffectSynchronizer)copy).FullyInitialized || !copy.IsSynced || (Object)(object)((EffectSynchronizer)copy).OwnerCharacter != (Object)(object)player)
				{
					error = "Delivery is still pending. Reopen this source and retry; the same item ID will be reused.";
				}
				else
				{
					try
					{
						copy.SaveType = (SaveTypes)0;
						claim.Complete = true;
						claimLedger.Save(path);
						if (PhotonNetwork.inRoom && !PhotonNetwork.offlineMode)
						{
							Global.RPCManager.SendItemSync(copy.ToNetworkData((SyncType)2), (PhotonTargets)1);
						}
					}
					catch (Exception ex3)
					{
						error = "Could not finalize item delivery. Check the log.";
						((BaseUnityPlugin)this).Logger.LogError((object)ex3);
					}
				}
			}
		}
		busyClaims.Remove(claim.Key);
		Reply(request, sender, source, error);
	}

	private void Reply(LootMessage request, int sender, LootSource source, string error)
	{
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Expected O, but got Unknown
		LootMessage lootMessage = new LootMessage
		{
			Operation = "result",
			Player = request.Player,
			Container = request.Container,
			Request = request.Request,
			Error = error
		};
		if (source != null && ledger != null)
		{
			foreach (LootEntry entry in source.Entries)
			{
				LootClaim lootClaim = ledger.Find(request.Player, source.Key, entry.Key);
				if (lootClaim == null || !lootClaim.Complete)
				{
					lootMessage.Entries.Add(new LootEntry
					{
						Key = entry.Key,
						Name = entry.Name,
						ItemId = entry.ItemId,
						Quantity = entry.Quantity,
						Silver = entry.Silver
					});
				}
			}
		}
		if (!PhotonNetwork.inRoom || PhotonNetwork.offlineMode || (PhotonNetwork.player != null && sender == PhotonNetwork.player.ID))
		{
			ShowResult(lootMessage);
		}
		else
		{
			byte num = eventCode;
			string[] array = LootWire.Encode(lootMessage);
			RaiseEventOptions val = new RaiseEventOptions();
			val.TargetActors = new int[1] { sender };
			if (!PhotonNetwork.RaiseEvent(num, (object)array, true, val))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to send loot reply to actor=" + sender));
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Reply " + request.Request + " to actor=" + sender + " entries=" + lootMessage.Entries.Count + " error=" + error));
	}

	private void ShowResult(LootMessage response)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)viewingPlayer) && Object.op_Implicit((Object)(object)viewingContainer) && !(response.Request != requestId) && !(response.Player != UID.op_Implicit(viewingPlayer.UID)) && !(response.Container != ((Item)viewingContainer).UID))
		{
			displayed = response;
			waiting = false;
			status = ((!string.IsNullOrEmpty(response.Error)) ? response.Error : ((response.Entries.Count == 0) ? "No unclaimed loot here. Press Refresh if loot is still loading." : (response.Entries.Count + " loot entries. Other players have their own copies.")));
		}
	}

	private void Update()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)viewingPlayer))
		{
			if (!Object.op_Implicit((Object)(object)viewingContainer) || viewingPlayer.IsDead || !viewingPlayer.CharacterUI.IsInventoryPanelDisplayed || Vector3.Distance(((Component)viewingPlayer).transform.position, ((Component)viewingContainer).transform.position) > 12f)
			{
				Close();
			}
			else if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
			else if (waiting && Time.unscaledTime - requestedAt > 15f)
			{
				waiting = false;
				status = "No host response. Check that every player has Personal Loot enabled, then press Refresh.";
			}
		}
	}

	private void OnGUI()
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Expected O, but got Unknown
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)viewingPlayer) || !Object.op_Implicit((Object)(object)viewingContainer))
		{
			return;
		}
		float num = Mathf.Min(560, Screen.width - 32);
		float num2 = Mathf.Min(620, Screen.height - 32);
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(((float)Screen.width - num) / 2f, ((float)Screen.height - num2) / 2f, num, num2);
		GUI.depth = -1000;
		GUILayout.Window(197402, val, (WindowFunction)delegate
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("Personal Loot — " + ((Object)viewingPlayer).name, Array.Empty<GUILayoutOption>());
			GUILayout.Label(status ?? "Loading…", new GUIStyle(GUI.skin.label)
			{
				wordWrap = true
			}, Array.Empty<GUILayoutOption>());
			scroll = GUILayout.BeginScrollView(scroll, Array.Empty<GUILayoutOption>());
			if (displayed != null)
			{
				LootEntry[] array = displayed.Entries.ToArray();
				foreach (LootEntry lootEntry in array)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label(lootEntry.Name + "  ×" + lootEntry.Quantity, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
					GUI.enabled = !waiting;
					if (GUILayout.Button("Take", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(75f),
						GUILayout.Height(30f)
					}))
					{
						Request("take", lootEntry.Key);
					}
					GUI.enabled = true;
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.EndScrollView();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = !waiting;
			if (GUILayout.Button("Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
			{
				Request("open", null);
			}
			GUI.enabled = true;
			if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
			{
				Close();
			}
			GUILayout.EndHorizontal();
		}, "Personal Loot", (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(num),
			GUILayout.Height(num2)
		});
	}

	private void Close()
	{
		if (Object.op_Implicit((Object)(object)inventoryInput))
		{
			inventoryInput.interactable = previousInteractable;
			inventoryInput.blocksRaycasts = previousRaycasts;
			inventoryInput = null;
		}
		Character val = viewingPlayer;
		viewingPlayer = null;
		viewingContainer = null;
		displayed = null;
		waiting = false;
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.CharacterUI))
		{
			val.CharacterUI.HideMenu((MenuScreens)2, true);
		}
	}

	private void OnScene(Scene scene, LoadSceneMode mode)
	{
		Close();
	}

	private void OnDestroy()
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		Close();
		PhotonNetwork.OnEventCall -= new EventCallback(OnEvent);
		SceneManager.sceneLoaded -= OnScene;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		Instance = null;
	}
}
[HarmonyPatch(typeof(CharacterInventory), "TakeItem", new Type[]
{
	typeof(Item),
	typeof(bool)
})]
internal static class TakePersonalLootItem
{
	private static bool Prefix(Item takenItem, Character ___m_character)
	{
		if (!Object.op_Implicit((Object)(object)PersonalLootPlugin.Instance) || !Object.op_Implicit((Object)(object)takenItem) || !PersonalLootPlugin.Supported(takenItem.ParentContainer))
		{
			return true;
		}
		PersonalLootPlugin.Instance.Open(takenItem.ParentContainer, ___m_character);
		return false;
	}
}
[HarmonyPatch(typeof(ItemContainer), "ShowContent")]
internal static class OpenPersonalLoot
{
	private static bool Prefix(ItemContainer __instance, Character _character)
	{
		if (!Object.op_Implicit((Object)(object)PersonalLootPlugin.Instance) || !PersonalLootPlugin.Supported(__instance))
		{
			return true;
		}
		PersonalLootPlugin.Instance.Open(__instance, _character);
		return false;
	}
}
[HarmonyPatch(typeof(CharacterInventory), "TakeAllContent")]
internal static class TakeAllPersonalLoot
{
	private static bool Prefix(ItemContainer _container, Character ___m_character, ref bool __result)
	{
		if (!Object.op_Implicit((Object)(object)PersonalLootPlugin.Instance) || !PersonalLootPlugin.Supported(_container))
		{
			return true;
		}
		PersonalLootPlugin.Instance.Open(_container, ___m_character);
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(TreasureChest), "ResetDrop")]
internal static class ResetPersonalLoot
{
	private static void Postfix(TreasureChest __instance)
	{
		if (Object.op_Implicit((Object)(object)PersonalLootPlugin.Instance))
		{
			PersonalLootPlugin.Instance.ResetChest(__instance);
		}
	}
}