Decompiled source of DiceCup v1.0.0

DiceCup.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.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace DiceCup
{
	public sealed class DiceCupInteractable : MonoBehaviour, Hoverable, Interactable
	{
		private ZNetView? _nview;

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
		}

		public string GetHoverName()
		{
			if (Localization.instance == null)
			{
				return "$piece_dicecup";
			}
			return Localization.instance.Localize("$piece_dicecup");
		}

		public string GetHoverText()
		{
			if (Localization.instance == null)
			{
				return "$piece_dicecup\n[<color=yellow><b>$KEY_Use</b></color>] $dicecup_roll_action";
			}
			return Localization.instance.Localize("$piece_dicecup\n[<color=yellow><b>$KEY_Use</b></color>] $dicecup_roll_action");
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!(hold || alt))
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Object)(object)_nview == (Object)null) && _nview.IsValid())
				{
					ZDO zDO = _nview.GetZDO();
					if (zDO == null)
					{
						return false;
					}
					DiceCupNetwork.RequestRoll(zDO.m_uid);
					return true;
				}
			}
			return false;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	public enum RollMessageMode
	{
		Global,
		Nearby
	}
	internal static class DiceCupConfig
	{
		private const string GeneralSection = "General";

		private const string MessagesSection = "Messages";

		internal static ConfigEntry<float> CooldownSeconds { get; private set; }

		internal static ConfigEntry<RollMessageMode> MessageMode { get; private set; }

		internal static ConfigEntry<float> MessageRadius { get; private set; }

		internal static ConfigEntry<float> WorldTextDurationSeconds { get; private set; }

		internal static void Bind(ConfigFile config)
		{
			AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f);
			CooldownSeconds = ConfigFileExtensions.BindConfig<float>(config, "General", "CooldownSeconds", 5f, "Cooldown, in seconds, applied to a player after a successful roll. The cooldown is shared across every Dice Cup and is enforced by the server.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			MessageMode = ConfigFileExtensions.BindConfig<RollMessageMode>(config, "Messages", "RollMessageMode", RollMessageMode.Nearby, "Controls who receives successful roll results. Nearby sends the result only to players within RollMessageRadius of the Dice Cup; Global sends it to every connected player. The player who rolled always receives the result.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f);
			MessageRadius = ConfigFileExtensions.BindConfig<float>(config, "Messages", "RollMessageRadius", 20f, "Maximum distance, in metres, at which other players receive a successful roll result when RollMessageMode is Nearby. This setting is ignored in Global mode.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f);
			WorldTextDurationSeconds = ConfigFileExtensions.BindConfig<float>(config, "Messages", "WorldTextDurationSeconds", 0f, "Duration, in seconds, of the floating roll text shown above a loaded Dice Cup. Set to 0 to use Valheim's normal world-text duration.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
		}
	}
	internal static class DiceCupConstants
	{
		internal const string PrefabName = "DiceCup";

		internal const string PieceNameToken = "$piece_dicecup";

		internal const string PieceDescriptionToken = "$piece_dicecup_description";

		internal const string RollActionToken = "$dicecup_roll_action";

		internal const string RollFormatToken = "$dicecup_roll_format";

		internal const string CooldownFormatToken = "$dicecup_cooldown_format";

		internal const string RollSoundPrefabName = "sfx_bones_pick";

		internal const float MaxUseDistance = 4f;

		internal const long LocalSenderKey = long.MinValue;
	}
	[BepInPlugin("xnolde.dicecup", "Dice Cup", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class DiceCupPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "xnolde.dicecup";

		public const string PluginName = "Dice Cup";

		public const string PluginVersion = "1.0.0";

		internal static DiceCupPlugin Instance { get; private set; }

		internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

		internal DiceCupUnlockTracker UnlockTracker { get; private set; }

		private void Awake()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			DiceCupConfig.Bind(((BaseUnityPlugin)this).Config);
			DiceCupLocalization.Register();
			UnlockTracker = ((Component)this).gameObject.AddComponent<DiceCupUnlockTracker>();
			UnlockTracker.Initialize(((BaseUnityPlugin)this).Logger);
			DiceCupNetwork.Initialize(((BaseUnityPlugin)this).Logger);
			DiceCupPresentation.Initialize(this, ((BaseUnityPlugin)this).Logger);
			DiceCupPieceRegistry.Initialize(((BaseUnityPlugin)this).Logger);
			new Harmony("xnolde.dicecup").PatchAll();
			PrefabManager.OnVanillaPrefabsAvailable += DiceCupPieceRegistry.Register;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Dice Cup 1.0.0 loaded. " + $"Cooldown={DiceCupConfig.CooldownSeconds.Value:0.##}s, " + $"MessageMode={DiceCupConfig.MessageMode.Value}, " + $"MessageRadius={DiceCupConfig.MessageRadius.Value:0.##}m, " + $"WorldTextDuration={DiceCupConfig.WorldTextDurationSeconds.Value:0.##}s"));
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= DiceCupPieceRegistry.Register;
			DiceCupNetwork.Shutdown();
			DiceCupPresentation.Shutdown();
			if (Instance == this)
			{
				Instance = null;
			}
		}
	}
	internal static class DiceCupResources
	{
		private const string Prefix = "DiceCup.Assets.";

		private static readonly Assembly Assembly = typeof(DiceCupResources).Assembly;

		internal static string GetText(string relativeName)
		{
			using Stream stream = GetRequiredStream(relativeName);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}

		internal static byte[] GetBytes(string relativeName)
		{
			using Stream stream = GetRequiredStream(relativeName);
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		internal static Texture2D LoadTexture(string relativeName)
		{
			Texture2D obj = AssetUtils.LoadImage(GetBytes(relativeName));
			if ((Object)(object)obj == (Object)null)
			{
				throw new InvalidOperationException("Could not decode embedded DiceCup texture '" + relativeName + "'.");
			}
			((Object)obj).name = Path.GetFileNameWithoutExtension(relativeName);
			((Texture)obj).filterMode = (FilterMode)0;
			((Texture)obj).wrapMode = (TextureWrapMode)0;
			((Texture)obj).anisoLevel = 0;
			return obj;
		}

		private static Stream GetRequiredStream(string relativeName)
		{
			string text = "DiceCup.Assets." + relativeName.Replace('\\', '.').Replace('/', '.');
			Stream manifestResourceStream = Assembly.GetManifestResourceStream(text);
			if (manifestResourceStream != null)
			{
				return manifestResourceStream;
			}
			throw new FileNotFoundException("Embedded DiceCup resource was not found: " + text);
		}
	}
	internal static class DiceCupUtility
	{
		internal static bool IsWithinDistance(Vector3 a, Vector3 b, float distance)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			float num = Mathf.Max(0f, distance);
			Vector3 val = a - b;
			return ((Vector3)(ref val)).sqrMagnitude <= num * num;
		}

		internal static string SanitizePlayerName(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return string.Empty;
			}
			string text = value.Replace('<', '<').Replace('>', '>').Trim();
			if (text.Length > 64)
			{
				return text.Substring(0, 64);
			}
			return text;
		}
	}
	internal static class DiceCupLocalization
	{
		internal static void Register()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			localization.AddJsonFile("English", DiceCupResources.GetText("Translations.English.dicecup.json"));
			localization.AddJsonFile("Spanish", DiceCupResources.GetText("Translations.Spanish.dicecup.json"));
		}
	}
	internal static class DiceCupNetwork
	{
		private const string RpcRollRequest = "xnolde.dicecup.RollRequest";

		private const string RpcRollResult = "xnolde.dicecup.RollResult";

		private const string RpcCooldown = "xnolde.dicecup.Cooldown";

		private static readonly Dictionary<long, float> NextRollAt = new Dictionary<long, float>();

		private static ManualLogSource _log = null;

		private static RandomNumberGenerator? _rng;

		private static readonly byte[] RandomByte = new byte[1];

		private static ZNet? _cooldownSession;

		internal static void Initialize(ManualLogSource log)
		{
			_log = log;
			_rng = RandomNumberGenerator.Create();
		}

		internal static void Shutdown()
		{
			NextRollAt.Clear();
			_cooldownSession = null;
			_rng?.Dispose();
			_rng = null;
		}

		internal static void RegisterPeerRpc(ZNet znet, ZNetPeer peer)
		{
			if (peer == null || peer.m_rpc == null)
			{
				return;
			}
			EnsureCooldownSession(znet);
			if (znet.IsServer())
			{
				NextRollAt.Remove(peer.m_uid);
				peer.m_rpc.Register<ZDOID>("xnolde.dicecup.RollRequest", (Action<ZRpc, ZDOID>)delegate(ZRpc rpc, ZDOID cupId)
				{
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					ReceiveRemoteRollRequest(peer, rpc, cupId);
				});
			}
			else
			{
				peer.m_rpc.Register<ZPackage>("xnolde.dicecup.RollResult", (Action<ZRpc, ZPackage>)ReceiveServerRollResult);
				peer.m_rpc.Register<int>("xnolde.dicecup.Cooldown", (Action<ZRpc, int>)ReceiveServerCooldown);
			}
		}

		internal static void RequestRoll(ZDOID cupId)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			EnsureCooldownSession(ZNet.instance);
			if (ZNet.instance.IsServer())
			{
				ProcessRoll(null, cupId);
				return;
			}
			ZRpc serverRPC = ZNet.instance.GetServerRPC();
			if (serverRPC == null || !serverRPC.IsConnected())
			{
				_log.LogWarning((object)"DiceCup roll request aborted: direct server RPC is unavailable.");
				return;
			}
			serverRPC.Invoke("xnolde.dicecup.RollRequest", new object[1] { cupId });
			_log.LogDebug((object)$"DiceCup roll request sent for {cupId}.");
		}

		private static void ReceiveRemoteRollRequest(ZNetPeer peer, ZRpc rpc, ZDOID cupId)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				if (peer == null || peer.m_rpc == null || peer.m_rpc != rpc || !peer.IsReady())
				{
					_log.LogWarning((object)"DiceCup rejected a roll request from an invalid/unready connection.");
				}
				else
				{
					ProcessRoll(peer, cupId);
				}
			}
		}

		private static void ProcessRoll(ZNetPeer? remoteRoller, ZDOID cupId)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				_log.LogWarning((object)"DiceCup rejected a roll: required network state is unavailable.");
				return;
			}
			EnsureCooldownSession(ZNet.instance);
			ZDO zDO = ZDOMan.instance.GetZDO(cupId);
			if (!IsValidDiceCup(zDO))
			{
				_log.LogWarning((object)$"DiceCup rejected an invalid cup ZDO: {cupId}.");
				return;
			}
			if (!TryResolveRoller(remoteRoller, out long cooldownKey, out string playerName, out Vector3 position, out string positionSource))
			{
				_log.LogWarning((object)$"DiceCup could not resolve the roller for {cupId}.");
				return;
			}
			Vector3 position2 = zDO.GetPosition();
			float num = Vector3.Distance(position, position2);
			if (num > 4f)
			{
				_log.LogDebug((object)("DiceCup roll rejected by distance: player=" + playerName + ", " + $"distance={num:0.000}m, source={positionSource}."));
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			float num2 = Mathf.Max(0f, DiceCupConfig.CooldownSeconds.Value);
			if (NextRollAt.TryGetValue(cooldownKey, out var value) && value > realtimeSinceStartup)
			{
				float num3 = value - realtimeSinceStartup;
				_log.LogDebug((object)("DiceCup roll rejected by cooldown: player=" + playerName + ", " + $"remaining={num3:0.000}s."));
				SendCooldown(remoteRoller, num3);
				return;
			}
			NextRollAt[cooldownKey] = realtimeSinceStartup + num2;
			int num4 = RollD6();
			int num5 = RollD6();
			_log.LogDebug((object)("DiceCup roll accepted: player=" + playerName + ", " + $"{num4},{num5}, distance={num:0.000}m, source={positionSource}."));
			BroadcastRoll(cupId, position2, remoteRoller, playerName, num4, num5);
		}

		private static void EnsureCooldownSession(ZNet znet)
		{
			if (_cooldownSession != znet)
			{
				_cooldownSession = znet;
				NextRollAt.Clear();
			}
		}

		private static bool IsValidDiceCup(ZDO? cupZdo)
		{
			if (cupZdo == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return false;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(cupZdo.GetPrefab());
			if ((Object)(object)prefab != (Object)null)
			{
				return string.Equals(((Object)prefab).name, "DiceCup", StringComparison.Ordinal);
			}
			return false;
		}

		private static bool TryResolveRoller(ZNetPeer? remoteRoller, out long cooldownKey, out string playerName, out Vector3 position, out string positionSource)
		{
			//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)
			//IL_004d: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			cooldownKey = long.MinValue;
			playerName = string.Empty;
			position = Vector3.zero;
			positionSource = "unresolved";
			if (remoteRoller == null)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return false;
				}
				playerName = DiceCupUtility.SanitizePlayerName(localPlayer.GetPlayerName());
				position = ((Component)localPlayer).transform.position;
				positionSource = "local-player-transform";
				return playerName.Length > 0;
			}
			if (!remoteRoller.IsReady() || remoteRoller.m_uid == 0L)
			{
				return false;
			}
			cooldownKey = remoteRoller.m_uid;
			playerName = DiceCupUtility.SanitizePlayerName(remoteRoller.m_playerName);
			if (playerName.Length == 0)
			{
				return false;
			}
			if (TryGetPeerCharacterPosition(remoteRoller, out position))
			{
				positionSource = "player-zdo";
			}
			else
			{
				position = remoteRoller.m_refPos;
				positionSource = "peer-refpos-fallback";
			}
			return true;
		}

		private static bool TryGetPeerCharacterPosition(ZNetPeer peer, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			if (peer == null || !peer.IsReady() || peer.m_characterID == ZDOID.None || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return false;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
			if (zDO == null)
			{
				return false;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab());
			if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<Player>() == (Object)null)
			{
				return false;
			}
			long owner = zDO.GetOwner();
			if (owner != 0L && owner != peer.m_uid)
			{
				return false;
			}
			position = zDO.GetPosition();
			return true;
		}

		private static Vector3 GetPeerPositionForPresentation(ZNetPeer peer)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetPeerCharacterPosition(peer, out var position))
			{
				return peer.m_refPos;
			}
			return position;
		}

		private static int RollD6()
		{
			if (_rng == null)
			{
				_rng = RandomNumberGenerator.Create();
			}
			byte b;
			do
			{
				_rng.GetBytes(RandomByte);
				b = RandomByte[0];
			}
			while (b >= 252);
			return b % 6 + 1;
		}

		private static void BroadcastRoll(ZDOID cupId, Vector3 cupPosition, ZNetPeer? remoteRoller, string playerName, int die1, int die2)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(cupId);
			val.Write(playerName);
			val.Write(die1);
			val.Write(die2);
			bool flag = DiceCupConfig.MessageMode.Value == RollMessageMode.Global;
			float distance = Mathf.Max(1f, DiceCupConfig.MessageRadius.Value);
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer != null && peer.m_rpc != null && peer.IsReady())
				{
					bool flag2 = remoteRoller != null && peer == remoteRoller;
					bool flag3 = DiceCupUtility.IsWithinDistance(GetPeerPositionForPresentation(peer), cupPosition, distance);
					if (flag || flag2 || flag3)
					{
						peer.m_rpc.Invoke("xnolde.dicecup.RollResult", new object[1] { val });
					}
				}
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				bool flag4 = remoteRoller == null;
				if (flag || flag4 || DiceCupUtility.IsWithinDistance(((Component)localPlayer).transform.position, cupPosition, distance))
				{
					DiceCupPresentation.ShowRollMessage(cupId, playerName, die1, die2);
				}
			}
		}

		private static void SendCooldown(ZNetPeer? remoteRoller, float remainingSeconds)
		{
			int num = Math.Max(1, (int)Math.Ceiling(remainingSeconds));
			if (remoteRoller == null)
			{
				DiceCupPresentation.ShowCooldownMessage(num);
			}
			else if (remoteRoller.m_rpc != null && remoteRoller.IsReady())
			{
				remoteRoller.m_rpc.Invoke("xnolde.dicecup.Cooldown", new object[1] { num });
			}
		}

		private static void ReceiveServerRollResult(ZRpc rpc, ZPackage package)
		{
			//IL_000e: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			if (!IsCurrentServerRpc(rpc) || package == null)
			{
				return;
			}
			try
			{
				ZDOID cupId = package.ReadZDOID();
				string text = DiceCupUtility.SanitizePlayerName(package.ReadString());
				int num = package.ReadInt();
				int num2 = package.ReadInt();
				if (text.Length == 0 || num < 1 || num > 6 || num2 < 1 || num2 > 6)
				{
					_log.LogWarning((object)"DiceCup discarded a malformed roll result.");
				}
				else
				{
					DiceCupPresentation.ShowRollMessage(cupId, text, num, num2);
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("DiceCup discarded an invalid roll result: " + ex.GetBaseException().Message));
			}
		}

		private static void ReceiveServerCooldown(ZRpc rpc, int seconds)
		{
			if (IsCurrentServerRpc(rpc))
			{
				DiceCupPresentation.ShowCooldownMessage(Math.Max(1, seconds));
			}
		}

		private static bool IsCurrentServerRpc(ZRpc rpc)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				return false;
			}
			ZRpc serverRPC = ZNet.instance.GetServerRPC();
			if (serverRPC != null)
			{
				return serverRPC == rpc;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Chat), "UpdateWorldTexts", new Type[] { typeof(float) })]
	internal static class DiceCupWorldTextPatch
	{
		[HarmonyPrefix]
		private static void Prefix(Chat __instance, float dt)
		{
			DiceCupWorldText.AdjustTimers(__instance, dt);
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class DiceCupNetworkConnectionPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ZNet __instance, ZNetPeer peer)
		{
			DiceCupNetwork.RegisterPeerRpc(__instance, peer);
		}
	}
	internal sealed class DiceCupModel
	{
		internal GameObject Visuals { get; }

		internal Bounds Bounds { get; }

		internal DiceCupModel(GameObject visuals, Bounds bounds)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Visuals = visuals;
			Bounds = bounds;
		}
	}
	internal static class DiceCupModelBuilder
	{
		private const float ColliderHorizontalPadding = 0.01f;

		private const float ColliderTopPadding = 0.005f;

		private const float VisualSink = 0.016f;

		private const float GroundTolerance = 0.001f;

		private const float TextureTiles = 3f;

		internal static DiceCupModel Build(GameObject prefab, ManualLogSource log)
		{
			//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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			Material sourceMaterial = StripSourcePresentation(prefab);
			Texture2D texture = DiceCupResources.LoadTexture("leather.png");
			Texture2D texture2 = DiceCupResources.LoadTexture("leather_band.png");
			Texture2D texture3 = DiceCupResources.LoadTexture("bone.png");
			GameObject val = new GameObject("DiceCupVisuals");
			val.transform.SetParent(prefab.transform, false);
			val.layer = prefab.layer;
			AddVisualPart(val.transform, "cup.obj", "Cup", texture, new Color(0.86f, 0.82f, 0.78f, 1f), sourceMaterial);
			AddVisualPart(val.transform, "band.obj", "LeatherBand", texture2, Color.white, sourceMaterial);
			AddVisualPart(val.transform, "die01.obj", "Die01", texture3, new Color(0.82f, 0.78f, 0.66f, 1f), sourceMaterial);
			AddVisualPart(val.transform, "die02.obj", "Die02", texture3, new Color(0.82f, 0.78f, 0.66f, 1f), sourceMaterial);
			Bounds val2 = CalculateLocalVisualBounds(val.transform);
			ValidateGrounding(val2);
			AddGroundedCollider(prefab, val2);
			AddSpeechAnchor(prefab, val2);
			ApplyVisualSink(val.transform);
			log.LogDebug((object)($"DiceCup visual sink: all parts y=-{0.016f:0.000}m; " + "collider bottom remains y=0."));
			return new DiceCupModel(val, val2);
		}

		private static Material? StripSourcePresentation(GameObject prefab)
		{
			Material val = null;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (val == null)
				{
					val = val2.sharedMaterial;
				}
				val2.enabled = false;
			}
			LODGroup[] componentsInChildren2 = prefab.GetComponentsInChildren<LODGroup>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Chair[] componentsInChildren3 = prefab.GetComponentsInChildren<Chair>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			EffectArea[] componentsInChildren4 = prefab.GetComponentsInChildren<EffectArea>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren4[i]);
			}
			Collider[] componentsInChildren5 = prefab.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren5[i]);
			}
			return val;
		}

		private static void ApplyVisualSink(Transform visualRoot)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			string[] array = new string[4] { "Cup", "LeatherBand", "Die01", "Die02" };
			foreach (string text in array)
			{
				Transform obj = visualRoot.Find(text);
				if ((Object)(object)obj == (Object)null)
				{
					throw new InvalidOperationException("DiceCup visual part '" + text + "' was not found.");
				}
				Vector3 localPosition = obj.localPosition;
				localPosition.y -= 0.016f;
				obj.localPosition = localPosition;
			}
		}

		private static void AddGroundedCollider(GameObject prefab, Bounds visualBounds)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			float num = ((Bounds)(ref visualBounds)).min.x - 0.01f;
			float num2 = ((Bounds)(ref visualBounds)).max.x + 0.01f;
			float num3 = ((Bounds)(ref visualBounds)).min.z - 0.01f;
			float num4 = ((Bounds)(ref visualBounds)).max.z + 0.01f;
			float num5 = Mathf.Max(((Bounds)(ref visualBounds)).max.y + 0.005f, 0.01f);
			BoxCollider obj = prefab.AddComponent<BoxCollider>();
			obj.center = new Vector3((num + num2) * 0.5f, num5 * 0.5f, (num3 + num4) * 0.5f);
			obj.size = new Vector3(num2 - num, num5, num4 - num3);
		}

		private static void AddSpeechAnchor(GameObject prefab, Bounds visualBounds)
		{
			//IL_0005: 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_0023: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DiceCupSpeechAnchor");
			val.transform.SetParent(prefab.transform, false);
			val.transform.localPosition = new Vector3(((Bounds)(ref visualBounds)).center.x, ((Bounds)(ref visualBounds)).max.y + 0.1f, ((Bounds)(ref visualBounds)).center.z);
		}

		private static void ValidateGrounding(Bounds visualBounds)
		{
			//IL_0002: 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)
			if (Mathf.Abs(((Bounds)(ref visualBounds)).min.y) <= 0.001f)
			{
				return;
			}
			throw new InvalidOperationException("DiceCup authored geometry is not grounded at y=0. " + $"minY={((Bounds)(ref visualBounds)).min.y:0.0000}.");
		}

		private static Bounds CalculateLocalVisualBounds(Transform visualRoot)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			Bounds result = default(Bounds);
			MeshFilter[] componentsInChildren = ((Component)visualRoot).GetComponentsInChildren<MeshFilter>(true);
			Vector3 val3 = default(Vector3);
			foreach (MeshFilter val in componentsInChildren)
			{
				Mesh sharedMesh = val.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					continue;
				}
				Matrix4x4 val2 = visualRoot.worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
				Bounds bounds = sharedMesh.bounds;
				Vector3 min = ((Bounds)(ref bounds)).min;
				Vector3 max = ((Bounds)(ref bounds)).max;
				for (int j = 0; j < 2; j++)
				{
					for (int k = 0; k < 2; k++)
					{
						for (int l = 0; l < 2; l++)
						{
							((Vector3)(ref val3))..ctor((j == 0) ? min.x : max.x, (k == 0) ? min.y : max.y, (l == 0) ? min.z : max.z);
							Vector3 val4 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3);
							if (!flag)
							{
								((Bounds)(ref result))..ctor(val4, Vector3.zero);
								flag = true;
							}
							else
							{
								((Bounds)(ref result)).Encapsulate(val4);
							}
						}
					}
				}
			}
			if (!flag)
			{
				throw new InvalidOperationException("DiceCup contains no visual mesh bounds.");
			}
			return result;
		}

		private static void AddVisualPart(Transform parent, string objResource, string objectName, Texture2D texture, Color tint, Material? sourceMaterial)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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)
			Mesh val = LoadObjMeshInvariant(objResource, objectName);
			Bounds bounds = val.bounds;
			Vector3 size = ((Bounds)(ref bounds)).size;
			if (size.x > 2f || size.y > 2f || size.z > 2f)
			{
				throw new InvalidOperationException($"DiceCup mesh {objectName} has implausible bounds {size}.");
			}
			GameObject val2 = new GameObject(objectName);
			val2.transform.SetParent(parent, false);
			val2.layer = ((Component)parent).gameObject.layer;
			val2.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = MakeMaterial(objectName + "_Material", texture, tint, sourceMaterial);
		}

		private static Mesh LoadObjMeshInvariant(string objResource, string meshName)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			string text = DiceCupResources.GetText(objResource);
			List<Vector3> list = new List<Vector3>();
			List<int> list2 = new List<int>();
			using StringReader stringReader = new StringReader(text);
			string text2;
			while ((text2 = stringReader.ReadLine()) != null)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0 || text3[0] == '#')
				{
					continue;
				}
				string[] array = text3.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length == 0)
				{
					continue;
				}
				if (array[0] == "v")
				{
					if (array.Length < 4)
					{
						throw new FormatException("Invalid OBJ vertex in " + objResource + ": " + text2);
					}
					list.Add(new Vector3(ParseInvariantFloat(array[1]), ParseInvariantFloat(array[2]), ParseInvariantFloat(array[3])));
				}
				else if (array[0] == "f" && array.Length >= 4)
				{
					int item = ParseObjVertexIndex(array[1], list.Count);
					for (int i = 2; i < array.Length - 1; i++)
					{
						list2.Add(item);
						list2.Add(ParseObjVertexIndex(array[i], list.Count));
						list2.Add(ParseObjVertexIndex(array[i + 1], list.Count));
					}
				}
			}
			if (list.Count == 0 || list2.Count == 0)
			{
				throw new FormatException("OBJ contains no usable geometry: " + objResource);
			}
			return BuildFaceProjectedMesh(list, list2, meshName);
		}

		private static float ParseInvariantFloat(string value)
		{
			return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
		}

		private static int ParseObjVertexIndex(string token, int vertexCount)
		{
			int num = int.Parse(token.Split(new char[1] { '/' })[0], NumberStyles.Integer, CultureInfo.InvariantCulture);
			int num2 = ((num > 0) ? (num - 1) : (vertexCount + num));
			if (num2 < 0 || num2 >= vertexCount)
			{
				throw new IndexOutOfRangeException($"OBJ vertex index {num} is outside 1..{vertexCount}.");
			}
			return num2;
		}

		private static Mesh BuildFaceProjectedMesh(List<Vector3> sourceVertices, List<int> sourceTriangles, string meshName)
		{
			//IL_0004: 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)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_00e8: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			Bounds bounds = default(Bounds);
			((Bounds)(ref bounds))..ctor(sourceVertices[0], Vector3.zero);
			for (int i = 1; i < sourceVertices.Count; i++)
			{
				((Bounds)(ref bounds)).Encapsulate(sourceVertices[i]);
			}
			float sx = Mathf.Max(((Bounds)(ref bounds)).size.x, 0.001f);
			float sy = Mathf.Max(((Bounds)(ref bounds)).size.y, 0.001f);
			float sz = Mathf.Max(((Bounds)(ref bounds)).size.z, 0.001f);
			List<Vector3> list = new List<Vector3>(sourceTriangles.Count);
			List<int> list2 = new List<int>(sourceTriangles.Count);
			List<Vector2> list3 = new List<Vector2>(sourceTriangles.Count);
			for (int j = 0; j < sourceTriangles.Count; j += 3)
			{
				Vector3 val = sourceVertices[sourceTriangles[j]];
				Vector3 val2 = sourceVertices[sourceTriangles[j + 1]];
				Vector3 val3 = sourceVertices[sourceTriangles[j + 2]];
				Vector3 val4 = Vector3.Cross(val2 - val, val3 - val);
				Vector3 normalized = ((Vector3)(ref val4)).normalized;
				int count = list.Count;
				list.Add(val);
				list.Add(val2);
				list.Add(val3);
				list2.Add(count);
				list2.Add(count + 1);
				list2.Add(count + 2);
				list3.Add(ProjectFaceUv(val, normalized, bounds, sx, sy, sz));
				list3.Add(ProjectFaceUv(val2, normalized, bounds, sx, sy, sz));
				list3.Add(ProjectFaceUv(val3, normalized, bounds, sx, sy, sz));
			}
			Mesh val5 = new Mesh
			{
				name = meshName,
				vertices = list.ToArray(),
				triangles = list2.ToArray(),
				uv = list3.ToArray()
			};
			val5.RecalculateNormals();
			val5.RecalculateBounds();
			return val5;
		}

		private static Vector2 ProjectFaceUv(Vector3 point, Vector3 normal, Bounds bounds, float sx, float sy, float sz)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0028: 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_0078: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_0046: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(Mathf.Abs(normal.x), Mathf.Abs(normal.y), Mathf.Abs(normal.z));
			Vector2 val2 = default(Vector2);
			if (val.y >= val.x && val.y >= val.z)
			{
				((Vector2)(ref val2))..ctor((point.x - ((Bounds)(ref bounds)).min.x) / sx, (point.z - ((Bounds)(ref bounds)).min.z) / sz);
			}
			else if (val.x >= val.z)
			{
				((Vector2)(ref val2))..ctor((point.z - ((Bounds)(ref bounds)).min.z) / sz, (point.y - ((Bounds)(ref bounds)).min.y) / sy);
			}
			else
			{
				((Vector2)(ref val2))..ctor((point.x - ((Bounds)(ref bounds)).min.x) / sx, (point.y - ((Bounds)(ref bounds)).min.y) / sy);
			}
			return val2 * 3f;
		}

		private static Material MakeMaterial(string name, Texture2D texture, Color tint, Material? sourceMaterial)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			Material val;
			if ((Object)(object)sourceMaterial != (Object)null)
			{
				val = new Material(sourceMaterial);
			}
			else
			{
				Shader obj = Shader.Find("Custom/Piece") ?? Shader.Find("Standard");
				if ((Object)(object)obj == (Object)null)
				{
					throw new InvalidOperationException("No usable shader/material found for Dice Cup.");
				}
				val = new Material(obj);
			}
			((Object)val).name = name;
			if (val.HasProperty("_MainTex"))
			{
				val.SetTexture("_MainTex", (Texture)(object)texture);
				val.SetTextureScale("_MainTex", Vector2.one);
				val.SetTextureOffset("_MainTex", Vector2.zero);
			}
			if (val.HasProperty("_Color"))
			{
				val.SetColor("_Color", tint);
			}
			if (val.HasProperty("_BaseColor"))
			{
				val.SetColor("_BaseColor", tint);
			}
			if (val.HasProperty("_Metallic"))
			{
				val.SetFloat("_Metallic", 0f);
			}
			if (val.HasProperty("_Glossiness"))
			{
				val.SetFloat("_Glossiness", 0.12f);
			}
			if (val.HasProperty("_Cutoff"))
			{
				val.SetFloat("_Cutoff", 0f);
			}
			if (val.HasProperty("_BumpMap"))
			{
				val.SetTexture("_BumpMap", (Texture)null);
			}
			if (val.HasProperty("_MetallicGlossMap"))
			{
				val.SetTexture("_MetallicGlossMap", (Texture)null);
			}
			if (val.HasProperty("_EmissionMap"))
			{
				val.SetTexture("_EmissionMap", (Texture)null);
			}
			if (val.HasProperty("_EmissionColor"))
			{
				val.SetColor("_EmissionColor", Color.black);
			}
			if (val.HasProperty("_Cull"))
			{
				val.SetFloat("_Cull", 0f);
			}
			val.DisableKeyword("_ALPHATEST_ON");
			val.DisableKeyword("_ALPHABLEND_ON");
			val.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			val.DisableKeyword("_NORMALMAP");
			val.DisableKeyword("_METALLICGLOSSMAP");
			val.DisableKeyword("_EMISSION");
			val.renderQueue = -1;
			return val;
		}
	}
	internal static class DiceCupPieceRegistry
	{
		private static ManualLogSource _log;

		private static bool _registered;

		internal static void Initialize(ManualLogSource log)
		{
			_log = log;
		}

		internal static void Register()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			if (_registered)
			{
				return;
			}
			try
			{
				PieceConfig val = new PieceConfig();
				val.Name = "$piece_dicecup";
				val.Description = "$piece_dicecup_description";
				val.PieceTable = PieceTables.Hammer;
				val.CraftingStation = CraftingStations.Workbench;
				val.Category = PieceCategories.Furniture;
				val.Usage = new string[2]
				{
					PieceUsages.Furniture,
					PieceUsages.Decor
				};
				PieceConfig val2 = val;
				val2.AddRequirement("BoneFragments", 4, true);
				val2.AddRequirement("DeerHide", 2, true);
				val2.AddRequirement("Resin", 1, true);
				CustomPiece val3 = new CustomPiece("DiceCup", "piece_chair", val2);
				GameObject piecePrefab = val3.PiecePrefab;
				val3.Piece.m_comfort = 0;
				DiceCupModel diceCupModel = DiceCupModelBuilder.Build(piecePrefab, _log);
				RenderIcon(val3, diceCupModel.Visuals);
				if ((Object)(object)piecePrefab.GetComponent<DiceCupInteractable>() == (Object)null)
				{
					piecePrefab.AddComponent<DiceCupInteractable>();
				}
				PieceManager.Instance.AddPiece(val3);
				_registered = true;
				_log.LogInfo((object)"Dice Cup piece registered.");
				DiceCupPlugin.Instance.UnlockTracker.RequestRefresh("piece registered");
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Could not register Dice Cup: {arg}");
			}
		}

		private static void RenderIcon(CustomPiece customPiece, GameObject visuals)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (GUIManager.IsHeadless())
			{
				return;
			}
			try
			{
				Sprite val = RenderManager.Instance.Render(visuals, RenderManager.IsometricRotation);
				if ((Object)(object)val == (Object)null)
				{
					_log.LogWarning((object)"DiceCup icon render returned null; cloned source icon retained.");
					return;
				}
				customPiece.Piece.m_icon = val;
				_log.LogDebug((object)"DiceCup build icon rendered from the actual prefab visuals.");
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("DiceCup runtime icon render failed; cloned source icon retained: " + ex.GetBaseException().Message));
			}
		}
	}
	internal static class DiceCupPresentation
	{
		private const string OfficialChatColor = "#E6B65A";

		private static readonly BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly MethodInfo? ChatAddStringMethod = typeof(Chat).GetMethod("AddString", AnyInstance, null, new Type[3]
		{
			typeof(string),
			typeof(string),
			typeof(Type)
		}, null);

		private static readonly MethodInfo? ChatAddStringSimpleMethod = typeof(Chat).GetMethod("AddString", AnyInstance, null, new Type[1] { typeof(string) }, null);

		private static readonly FieldInfo? ChatHideTimerField = typeof(Chat).GetField("m_hideTimer", AnyInstance);

		private static readonly FieldInfo? ChatWindowField = typeof(Chat).GetField("m_chatWindow", AnyInstance) ?? typeof(Terminal).GetField("m_chatWindow", AnyInstance);

		private static DiceCupPlugin _plugin = null;

		private static ManualLogSource _log = null;

		private static bool _chatFallbackLogged;

		private static bool _soundFallbackLogged;

		private static GameObject? _rollSoundPrefab;

		internal static void Initialize(DiceCupPlugin plugin, ManualLogSource log)
		{
			_plugin = plugin;
			_log = log;
		}

		internal static void Shutdown()
		{
			_rollSoundPrefab = null;
			_chatFallbackLogged = false;
			_soundFallbackLogged = false;
		}

		internal static void ShowRollMessage(ZDOID cupId, string playerName, int die1, int die2)
		{
			//IL_0044: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			string speaker = Localize("$piece_dicecup");
			string text = LocalizeFormat("$dicecup_roll_format", playerName, die1, die2, die1 + die2);
			ShowChatHistoryLine(speaker, text);
			GameObject val = FindLoadedCup(cupId);
			if (!((Object)(object)val == (Object)null))
			{
				DiceCupWorldText.Show(val, speaker, text);
				((MonoBehaviour)_plugin).StartCoroutine(PlayRollSoundSequence(cupId, val.transform.position));
			}
		}

		internal static void ShowCooldownMessage(int seconds)
		{
			string text = LocalizeFormat("$dicecup_cooldown_format", seconds);
			MessageHud instance = MessageHud.instance;
			if (instance != null)
			{
				instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
			}
		}

		private static string Localize(string token)
		{
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}

		private static string LocalizeFormat(string token, params object[] values)
		{
			string text = Localize(token);
			try
			{
				return string.Format(CultureInfo.CurrentCulture, text, values);
			}
			catch
			{
				return text;
			}
		}

		private static void ShowChatHistoryLine(string speaker, string text)
		{
			string text2 = "<color=#E6B65A>" + speaker + ":</color> " + text;
			if ((Object)(object)Chat.instance != (Object)null && ChatAddStringSimpleMethod != null)
			{
				try
				{
					ChatAddStringSimpleMethod.Invoke(Chat.instance, new object[1] { text2 });
					WakeChatPanel();
					return;
				}
				catch (Exception ex)
				{
					LogChatFallbackOnce(ex);
				}
			}
			if ((Object)(object)Chat.instance != (Object)null && ChatAddStringMethod != null)
			{
				try
				{
					ChatAddStringMethod.Invoke(Chat.instance, new object[3]
					{
						speaker,
						text,
						(object)(Type)2
					});
					WakeChatPanel();
				}
				catch (Exception ex2)
				{
					LogChatFallbackOnce(ex2);
				}
			}
		}

		private static void WakeChatPanel()
		{
			Chat instance = Chat.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				ChatHideTimerField?.SetValue(instance, 0f);
				object? obj = ChatWindowField?.GetValue(instance);
				RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
				if (val != null)
				{
					((Component)val).gameObject.SetActive(true);
				}
			}
			catch
			{
			}
		}

		private static void LogChatFallbackOnce(Exception ex)
		{
			if (!_chatFallbackLogged)
			{
				_chatFallbackLogged = true;
				_log.LogWarning((object)("DiceCup could not add its chat-history line: " + ex.GetBaseException().Message));
			}
		}

		private static IEnumerator PlayRollSoundSequence(ZDOID cupId, Vector3 initialPosition)
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			PlayVanillaRollSound(initialPosition);
			float num = Random.Range(0.1f, 0.13f);
			yield return (object)new WaitForSecondsRealtime(num);
			GameObject val = FindLoadedCup(cupId);
			if ((Object)(object)val != (Object)null)
			{
				PlayVanillaRollSound(val.transform.position);
			}
		}

		private static GameObject? FindLoadedCup(ZDOID cupId)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ZNetScene.instance != (Object)null))
			{
				return null;
			}
			return ZNetScene.instance.FindInstance(cupId);
		}

		private static void PlayVanillaRollSound(Vector3 position)
		{
			//IL_004b: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_rollSoundPrefab == null)
				{
					_rollSoundPrefab = PrefabManager.Instance.GetPrefab("sfx_bones_pick");
				}
				if ((Object)(object)_rollSoundPrefab == (Object)null)
				{
					if (!_soundFallbackLogged)
					{
						_soundFallbackLogged = true;
						_log.LogWarning((object)"DiceCup could not find vanilla roll sound prefab.");
					}
				}
				else
				{
					Object.Instantiate<GameObject>(_rollSoundPrefab, position + Vector3.up * 0.1f, Quaternion.identity);
				}
			}
			catch (Exception ex)
			{
				if (!_soundFallbackLogged)
				{
					_soundFallbackLogged = true;
					_log.LogWarning((object)("DiceCup could not play its roll sound: " + ex.GetBaseException().Message));
				}
			}
		}
	}
	internal static class DiceCupWorldText
	{
		private static readonly BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly MethodInfo? AddInworldTextMethod = typeof(Chat).GetMethod("AddInworldText", AnyInstance, null, new Type[6]
		{
			typeof(GameObject),
			typeof(long),
			typeof(Vector3),
			typeof(Type),
			typeof(UserInfo),
			typeof(string)
		}, null);

		private static readonly FieldInfo? WorldTextsField = typeof(Chat).GetField("m_worldTexts", AnyInstance);

		private static readonly FieldInfo? WorldTextTtlField = typeof(Chat).GetField("m_worldTextTTL", AnyInstance);

		private static readonly Dictionary<long, GameObject> Anchors = new Dictionary<long, GameObject>();

		private static FieldInfo? _talkerIdField;

		private static FieldInfo? _timerField;

		private static FieldInfo? _sourceObjectField;

		private static bool _displayWarningLogged;

		private static bool _timingWarningLogged;

		internal static void Show(GameObject cup, string speaker, string text)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Chat.instance == (Object)null || AddInworldTextMethod == null)
			{
				return;
			}
			Transform val = cup.transform.Find("DiceCupSpeechAnchor");
			GameObject val2 = (GameObject)(((Object)(object)val != (Object)null) ? ((object)((Component)val).gameObject) : ((object)cup));
			UserInfo localUser = UserInfo.GetLocalUser();
			localUser.Name = speaker;
			long num = ((Object)val2).GetInstanceID();
			Anchors[num] = val2;
			try
			{
				AddInworldTextMethod.Invoke(Chat.instance, new object[6]
				{
					val2,
					num,
					val2.transform.position,
					(object)(Type)1,
					localUser,
					text
				});
			}
			catch (Exception ex)
			{
				if (!_displayWarningLogged)
				{
					_displayWarningLogged = true;
					DiceCupPlugin.Log.LogWarning((object)("DiceCup could not display world text: " + ex.GetBaseException().Message));
				}
			}
		}

		internal static void AdjustTimers(Chat chat, float dt)
		{
			if (dt <= 0f || Anchors.Count == 0 || WorldTextsField == null || WorldTextTtlField == null)
			{
				return;
			}
			float num = Mathf.Max(0f, DiceCupConfig.WorldTextDurationSeconds.Value);
			if (num <= 0f)
			{
				Anchors.Clear();
				return;
			}
			try
			{
				if (!(WorldTextTtlField.GetValue(chat) is float num2) || num2 <= 0.001f || !(WorldTextsField.GetValue(chat) is IEnumerable enumerable))
				{
					return;
				}
				HashSet<long> hashSet = new HashSet<long>();
				foreach (object item in enumerable)
				{
					if (item == null)
					{
						continue;
					}
					Type type = item.GetType();
					if ((object)_talkerIdField == null)
					{
						_talkerIdField = type.GetField("m_talkerID", AnyInstance);
					}
					if ((object)_timerField == null)
					{
						_timerField = type.GetField("m_timer", AnyInstance);
					}
					if ((object)_sourceObjectField == null)
					{
						_sourceObjectField = type.GetField("m_go", AnyInstance);
					}
					if (_talkerIdField == null || _timerField == null || _sourceObjectField == null)
					{
						LogTimingWarningOnce("required WorldTextInstance fields are unavailable");
						return;
					}
					if (_talkerIdField.GetValue(item) is long num3 && Anchors.TryGetValue(num3, out GameObject value))
					{
						hashSet.Add(num3);
						if (!((Object)(object)value == (Object)null) && _sourceObjectField.GetValue(item) == value && _timerField.GetValue(item) is float num4)
						{
							float num5 = num2 / Mathf.Max(0.05f, num);
							_timerField.SetValue(item, num4 + dt * (num5 - 1f));
						}
					}
				}
				RemoveStaleAnchors(hashSet);
			}
			catch (Exception ex)
			{
				LogTimingWarningOnce(ex.GetBaseException().Message);
			}
		}

		private static void RemoveStaleAnchors(HashSet<long> activeIds)
		{
			if (activeIds.Count >= Anchors.Count)
			{
				return;
			}
			List<long> list = new List<long>();
			foreach (KeyValuePair<long, GameObject> anchor in Anchors)
			{
				if ((Object)(object)anchor.Value == (Object)null || !activeIds.Contains(anchor.Key))
				{
					list.Add(anchor.Key);
				}
			}
			foreach (long item in list)
			{
				Anchors.Remove(item);
			}
		}

		private static void LogTimingWarningOnce(string reason)
		{
			if (!_timingWarningLogged)
			{
				_timingWarningLogged = true;
				DiceCupPlugin.Log.LogWarning((object)("DiceCup could not apply custom world-text duration; Valheim's normal duration will be used. " + reason));
			}
		}
	}
	public sealed class DiceCupUnlockTracker : MonoBehaviour
	{
		private const float CheckInterval = 0.5f;

		private static readonly BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly MethodInfo? UpdateKnownRecipesMethod = typeof(Player).GetMethod("UpdateKnownRecipesList", AnyInstance, null, Type.EmptyTypes, null);

		private static readonly MethodInfo? UpdateAvailablePiecesMethod = typeof(Player).GetMethod("UpdateAvailablePiecesList", AnyInstance, null, Type.EmptyTypes, null);

		private static readonly FieldInfo? KnownMaterialField = typeof(Player).GetField("m_knownMaterial", AnyInstance);

		private static readonly FieldInfo? KnownStationsField = typeof(Player).GetField("m_knownStations", AnyInstance);

		private ManualLogSource _log;

		private Player? _trackedPlayer;

		private int _lastMaterialCount = -1;

		private int _lastStationCount = -1;

		private float _nextCheckAt;

		private bool _refreshRunning;

		private bool _reflectionWarningLogged;

		internal void Initialize(ManualLogSource log)
		{
			_log = log;
		}

		internal void RequestRefresh(string reason)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !_refreshRunning)
			{
				((MonoBehaviour)this).StartCoroutine(RefreshRoutine(localPlayer, reason));
			}
		}

		private void Update()
		{
			if (Time.unscaledTime < _nextCheckAt)
			{
				return;
			}
			_nextCheckAt = Time.unscaledTime + 0.5f;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				ResetTracking();
				return;
			}
			int collectionCount = GetCollectionCount(KnownMaterialField, localPlayer);
			int collectionCount2 = GetCollectionCount(KnownStationsField, localPlayer);
			bool flag = localPlayer != _trackedPlayer;
			bool flag2 = collectionCount != _lastMaterialCount || collectionCount2 != _lastStationCount;
			if (flag || flag2)
			{
				_trackedPlayer = localPlayer;
				_lastMaterialCount = collectionCount;
				_lastStationCount = collectionCount2;
				RequestRefresh(flag ? "local player initialized" : "known materials/stations changed");
			}
		}

		private IEnumerator RefreshRoutine(Player player, string reason)
		{
			_refreshRunning = true;
			yield return null;
			bool invoked = InvokeRefreshMethods(player);
			yield return null;
			invoked |= InvokeRefreshMethods(player);
			_log.LogDebug((object)$"DiceCup unlock refresh ({reason}): refreshInvoked={invoked}.");
			_refreshRunning = false;
		}

		private bool InvokeRefreshMethods(Player player)
		{
			if (player != Player.m_localPlayer)
			{
				return false;
			}
			bool flag = false;
			try
			{
				if (UpdateKnownRecipesMethod != null)
				{
					UpdateKnownRecipesMethod.Invoke(player, null);
					flag = true;
				}
				if (UpdateAvailablePiecesMethod != null)
				{
					UpdateAvailablePiecesMethod.Invoke(player, null);
					flag = true;
				}
			}
			catch (Exception ex)
			{
				LogReflectionWarningOnce("Could not refresh the local player's known/buildable piece lists: " + ex.GetBaseException().Message);
			}
			if (!flag)
			{
				LogReflectionWarningOnce("Could not find Player.UpdateKnownRecipesList() or Player.UpdateAvailablePiecesList().");
			}
			return flag;
		}

		private void LogReflectionWarningOnce(string message)
		{
			if (!_reflectionWarningLogged)
			{
				_reflectionWarningLogged = true;
				_log.LogWarning((object)("DiceCup " + message));
			}
		}

		private static int GetCollectionCount(FieldInfo? field, object owner)
		{
			if (field == null)
			{
				return -1;
			}
			try
			{
				object value = field.GetValue(owner);
				if (value == null)
				{
					return -1;
				}
				return (value.GetType().GetProperty("Count", AnyInstance)?.GetValue(value, null) is int num) ? num : (-1);
			}
			catch
			{
				return -1;
			}
		}

		private void ResetTracking()
		{
			_trackedPlayer = null;
			_lastMaterialCount = -1;
			_lastStationCount = -1;
			_refreshRunning = false;
		}
	}
}