Decompiled source of RoboticInbox v1.2.0

RoboticInbox.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("RoboticInbox")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+9e93eaebfc77bdaed2d41d492483d337a0d8bb7b")]
[assembly: AssemblyProduct("RoboticInbox")]
[assembly: AssemblyTitle("RoboticInbox")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DarthJML.RoboticInbox
{
	internal static class Cybercrate
	{
		private const string ResourceName = "RoboticInbox.cybercrate";

		private const string VisualName = "Cybercrate";

		private static readonly string[,] TextureSlots = new string[4, 2]
		{
			{ "_MainTex", "cybercrate_v3_basecolor" },
			{ "_BumpMap", "cybercrate_v3_normal_gl" },
			{ "_EmissionMap", "cybercrate_v3_emission" },
			{ "_MetallicTex", "cybercrate_v3_metallic" }
		};

		private static AssetBundle _bundle;

		private static bool _loadFailed;

		private static Material _material;

		private static AssetBundle LoadBundle()
		{
			if ((Object)(object)_bundle != (Object)null || _loadFailed)
			{
				return _bundle;
			}
			try
			{
				using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("RoboticInbox.cybercrate"))
				{
					if (stream == null)
					{
						throw new Exception("embedded resource RoboticInbox.cybercrate missing");
					}
					byte[] array = new byte[stream.Length];
					int num;
					for (int i = 0; i < array.Length; i += num)
					{
						num = stream.Read(array, i, array.Length - i);
						if (num <= 0)
						{
							throw new EndOfStreamException();
						}
					}
					_bundle = AssetBundle.LoadFromMemory(array);
				}
				if ((Object)(object)_bundle == (Object)null)
				{
					throw new Exception("AssetBundle.LoadFromMemory returned null");
				}
				Debug.Log((object)("RoboticInbox: Cybercrate bundle loaded: " + string.Join(", ", _bundle.GetAllAssetNames())));
			}
			catch (Exception ex)
			{
				_loadFailed = true;
				Debug.LogError((object)("RoboticInbox: Cybercrate bundle failed to load, keeping the wood chest look: " + ex));
			}
			return _bundle;
		}

		internal static void Apply(GameObject clone)
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0482: Unknown result type (might be due to invalid IL or missing references)
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			//IL_0617: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Unknown result type (might be due to invalid IL or missing references)
			AssetBundle val = LoadBundle();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			GameObject val2 = val.LoadAsset<GameObject>("Cybercrate");
			if ((Object)(object)val2 == (Object)null)
			{
				Debug.LogError((object)"RoboticInbox: Cybercrate prefab missing from bundle, keeping the wood chest look.");
				return;
			}
			WearNTear component = clone.GetComponent<WearNTear>();
			Container component2 = clone.GetComponent<Container>();
			Piece component3 = clone.GetComponent<Piece>();
			List<GameObject> oldVisuals = new List<GameObject>();
			Transform obj = clone.transform.Find("New");
			AddOld((obj != null) ? ((Component)obj).gameObject : null);
			if ((Object)(object)component != (Object)null)
			{
				AddOld(component.m_new);
				AddOld(component.m_worn);
				AddOld(component.m_broken);
			}
			GameObject val3 = (((Object)(object)component != (Object)null && (Object)(object)component.m_new != (Object)null) ? component.m_new : ((oldVisuals.Count > 0) ? oldVisuals[0] : null));
			Material val4 = null;
			float num = 0f;
			int num2 = (((Object)(object)val3 != (Object)null) ? val3.layer : clone.layer);
			Bounds bounds = default(Bounds);
			bool flag = (Object)(object)val3 != (Object)null && Encapsulate(clone.transform, val3.transform, ref bounds);
			if ((Object)(object)val3 != (Object)null)
			{
				LODGroup component4 = val3.GetComponent<LODGroup>();
				if ((Object)(object)component4 != (Object)null && component4.lodCount > 0)
				{
					num = component4.GetLODs()[component4.lodCount - 1].screenRelativeTransitionHeight;
				}
			}
			MeshRenderer[] componentsInChildren;
			foreach (GameObject item in oldVisuals)
			{
				componentsInChildren = item.GetComponentsInChildren<MeshRenderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Material sharedMaterial = ((Renderer)componentsInChildren[i]).sharedMaterial;
					if (!((Object)(object)sharedMaterial == (Object)null))
					{
						if ((Object)(object)sharedMaterial.shader != (Object)null && ((Object)sharedMaterial.shader).name == "Custom/Piece")
						{
							val4 = sharedMaterial;
							break;
						}
						if ((Object)(object)val4 == (Object)null)
						{
							val4 = sharedMaterial;
						}
					}
				}
			}
			Material sharedMaterial2 = (_material = MakeMaterial(val4, val));
			GameObject val5 = Object.Instantiate<GameObject>(val2, clone.transform, false);
			((Object)val5).name = "Cybercrate";
			Transform[] componentsInChildren2 = val5.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				((Component)componentsInChildren2[i]).gameObject.layer = num2;
			}
			MeshRenderer[] componentsInChildren3 = val5.GetComponentsInChildren<MeshRenderer>(true);
			componentsInChildren = componentsInChildren3;
			foreach (MeshRenderer obj2 in componentsInChildren)
			{
				((Renderer)obj2).sharedMaterial = sharedMaterial2;
				((Renderer)obj2).shadowCastingMode = (ShadowCastingMode)1;
				((Renderer)obj2).receiveShadows = true;
			}
			Renderer[] array2;
			if (num > 0f)
			{
				LODGroup val6 = val5.AddComponent<LODGroup>();
				LOD[] array = new LOD[1];
				float num3 = num;
				array2 = (Renderer[])(object)componentsInChildren3;
				array[0] = new LOD(num3, array2);
				val6.SetLODs((LOD[])(object)array);
				val6.RecalculateBounds();
			}
			Bounds bounds2 = default(Bounds);
			Encapsulate(val5.transform, val5.transform, ref bounds2);
			BoxCollider val7 = val5.AddComponent<BoxCollider>();
			val7.center = ((Bounds)(ref bounds2)).center;
			val7.size = ((Bounds)(ref bounds2)).size;
			MeshRenderer val8 = (((Object)(object)component != (Object)null) ? component.m_snow : null);
			if ((Object)(object)val8 != (Object)null && flag && !IsUnderAny(((Component)val8).transform, oldVisuals))
			{
				Bounds bounds3 = default(Bounds);
				Encapsulate(clone.transform, val5.transform, ref bounds3);
				Transform transform = ((Component)val8).transform;
				Vector3 localScale = transform.localScale;
				if (((Bounds)(ref bounds)).size.x > 0.01f)
				{
					localScale.x *= ((Bounds)(ref bounds3)).size.x / ((Bounds)(ref bounds)).size.x;
				}
				if (((Bounds)(ref bounds)).size.z > 0.01f)
				{
					localScale.z *= ((Bounds)(ref bounds3)).size.z / ((Bounds)(ref bounds)).size.z;
				}
				transform.localScale = localScale;
				transform.localPosition += new Vector3(((Bounds)(ref bounds3)).center.x - ((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds3)).max.y - ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds3)).center.z - ((Bounds)(ref bounds)).center.z);
			}
			string text = string.Join(",", oldVisuals.ConvertAll((GameObject g) => ((Object)g).name));
			foreach (GameObject item2 in oldVisuals)
			{
				Object.DestroyImmediate((Object)(object)item2);
			}
			array2 = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val9 in array2)
			{
				if (!((Component)val9).transform.IsChildOf(val5.transform) && (!((Object)(object)val8 != (Object)null) || !((Object)(object)val9 == (Object)(object)val8)))
				{
					Debug.LogWarning((object)("RoboticInbox: hiding leftover chest renderer " + ((Object)val9).name));
					val9.enabled = false;
				}
			}
			if ((Object)(object)component != (Object)null)
			{
				component.m_new = (component.m_worn = (component.m_broken = val5));
			}
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_open = null;
				component2.m_closed = null;
			}
			Sprite val10 = val.LoadAsset<Sprite>("cybercrate_icon");
			if ((Object)(object)component3 != (Object)null && (Object)(object)val10 != (Object)null)
			{
				component3.m_icon = val10;
			}
			else
			{
				Debug.LogWarning((object)"RoboticInbox: Cybercrate icon not found in bundle.");
			}
			string text2 = $"RoboticInbox: Cybercrate visual applied: renderers={componentsInChildren3.Length} layer={LayerMask.LayerToName(num2)} lod={num:F3} ";
			object[] array3 = new object[5];
			Vector3 val11 = val7.center;
			array3[0] = ((Vector3)(ref val11)).ToString("F3");
			val11 = val7.size;
			array3[1] = ((Vector3)(ref val11)).ToString("F3");
			array3[2] = text;
			array3[3] = (Object)(object)val8 != (Object)null && flag;
			array3[4] = (Object)(object)val10 != (Object)null;
			Debug.Log((object)(text2 + string.Format("collider center={0} size={1} oldVisuals=[{2}] snowFitted={3} icon={4}", array3)));
			void AddOld(GameObject go)
			{
				if ((Object)(object)go != (Object)null && (Object)(object)go != (Object)(object)clone && !oldVisuals.Contains(go))
				{
					oldVisuals.Add(go);
				}
			}
		}

		private static Material MakeMaterial(Material source, AssetBundle bundle)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			Shader val = (((Object)(object)source != (Object)null) ? source.shader : Shader.Find("Custom/Piece"));
			Material val2 = (((Object)(object)source != (Object)null) ? new Material(source) : new Material(val));
			((Object)val2).name = "RoboticInbox_Cybercrate";
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			for (int i = 0; i < TextureSlots.GetLength(0); i++)
			{
				string text = TextureSlots[i, 0];
				string text2 = TextureSlots[i, 1];
				Texture2D val3 = bundle.LoadAsset<Texture2D>(text2);
				if ((Object)(object)val3 != (Object)null && val2.HasProperty(text))
				{
					val2.SetTexture(text, (Texture)(object)val3);
					list.Add(text + "=" + text2);
				}
				else
				{
					list2.Add(text + (((Object)(object)val3 == (Object)null) ? "(no texture)" : "(no property)"));
				}
			}
			if (val2.HasProperty("_MainTex"))
			{
				val2.mainTextureScale = Vector2.one;
				val2.mainTextureOffset = Vector2.zero;
			}
			SetFloat(val2, "_BumpScale", 1f, list, list2);
			SetFloat(val2, "_Metallic", 1f, list, list2);
			SetFloat(val2, "_Glossiness", 0.08f, list, list2);
			SetFloat(val2, "_MetallicAlphaGloss", 0.35f, list, list2);
			SetColor(val2, "_Color", Color.white, list, list2);
			SetColor(val2, "_MetalColor", Color.white, list, list2);
			UpdateGlow(val2);
			list.Add("_EmissionColor=white*" + RoboticInboxPlugin.GlowIntensity.Value);
			List<string> list3 = new List<string>();
			if ((Object)(object)val != (Object)null)
			{
				for (int j = 0; j < val.GetPropertyCount(); j++)
				{
					list3.Add(val.GetPropertyName(j) + ":" + ((object)val.GetPropertyType(j)/*cast due to .constrained prefix*/).ToString());
				}
			}
			Debug.Log((object)("RoboticInbox: Cybercrate material from '" + (((Object)(object)source != (Object)null) ? ((Object)source).name : "<none>") + "' shader='" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "<null>") + "' set=[" + string.Join(", ", list) + "] missing=[" + string.Join(", ", list2) + "] shaderProps=[" + string.Join(", ", list3) + "]"));
			if ((Object)(object)val == (Object)null || ((Object)val).name != "Custom/Piece")
			{
				Debug.LogWarning((object)("RoboticInbox: Cybercrate expected shader Custom/Piece, got " + (((Object)(object)val != (Object)null) ? ((Object)val).name : "null")));
			}
			return val2;
		}

		internal static void UpdateGlow(Material mat = null)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			mat = mat ?? _material;
			if ((Object)(object)mat != (Object)null && mat.HasProperty("_EmissionColor"))
			{
				mat.SetColor("_EmissionColor", Color.white * RoboticInboxPlugin.GlowIntensity.Value);
			}
		}

		private static void SetFloat(Material m, string p, float v, List<string> set, List<string> missing)
		{
			if (m.HasProperty(p))
			{
				m.SetFloat(p, v);
				set.Add(p + "=" + v);
			}
			else
			{
				missing.Add(p);
			}
		}

		private unsafe static void SetColor(Material m, string p, Color v, List<string> set, List<string> missing)
		{
			//IL_000b: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			if (m.HasProperty(p))
			{
				m.SetColor(p, v);
				Color val = v;
				set.Add(p + "=" + ((object)(*(Color*)(&val))/*cast due to .constrained prefix*/).ToString());
			}
			else
			{
				missing.Add(p);
			}
		}

		private static bool IsUnderAny(Transform t, List<GameObject> roots)
		{
			return roots.Exists((GameObject r) => t.IsChildOf(r.transform));
		}

		private static bool Encapsulate(Transform space, Transform of, ref Bounds bounds)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0084: 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)
			//IL_00a4: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00c6: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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)
			bool flag = false;
			MeshFilter[] componentsInChildren = ((Component)of).GetComponentsInChildren<MeshFilter>(true);
			Vector3 val2 = default(Vector3);
			foreach (MeshFilter val in componentsInChildren)
			{
				if ((Object)(object)val.sharedMesh == (Object)null || !ActiveWithin(((Component)val).transform, of))
				{
					continue;
				}
				Bounds bounds2 = val.sharedMesh.bounds;
				for (int j = 0; j < 8; j++)
				{
					((Vector3)(ref val2))..ctor(((j & 1) == 0) ? ((Bounds)(ref bounds2)).min.x : ((Bounds)(ref bounds2)).max.x, ((j & 2) == 0) ? ((Bounds)(ref bounds2)).min.y : ((Bounds)(ref bounds2)).max.y, ((j & 4) == 0) ? ((Bounds)(ref bounds2)).min.z : ((Bounds)(ref bounds2)).max.z);
					Vector3 val3 = space.InverseTransformPoint(((Component)val).transform.TransformPoint(val2));
					if (!flag)
					{
						bounds = new Bounds(val3, Vector3.zero);
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val3);
					}
				}
			}
			return flag;
		}

		private static bool ActiveWithin(Transform t, Transform root)
		{
			while ((Object)(object)t != (Object)null)
			{
				if (!((Component)t).gameObject.activeSelf)
				{
					return false;
				}
				if ((Object)(object)t == (Object)(object)root)
				{
					return true;
				}
				t = t.parent;
			}
			return true;
		}
	}
	[BepInPlugin("com.darthjml.roboticinbox", "RoboticInbox", "1.2.0")]
	public class RoboticInboxPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.darthjml.roboticinbox";

		public const string PluginName = "RoboticInbox";

		public const string PluginVersion = "1.2.0";

		public static ConfigEntry<float> ScanRadius;

		public static ConfigEntry<int> InboxWidth;

		public static ConfigEntry<int> InboxHeight;

		public static ConfigEntry<bool> DebugLog;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> GlowIntensity;

		public static ConfigEntry<bool> RequireMod;

		private float _timer;

		private bool _errorLogged;

		public const string PrefabName = "RoboticInbox";

		public static GameObject RoboticInboxPrefab;

		private static GameObject _prefabHolder;

		internal static readonly List<Container> Containers = new List<Container>();

		internal static float? SyncedRadius;

		internal static int? SyncedWidth;

		internal static int? SyncedHeight;

		private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

		private static readonly FieldRef<Container, uint> ContainerLastRevision = AccessTools.FieldRefAccess<Container, uint>("m_lastRevision");

		private static readonly Func<Container, long, bool> ContainerCheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null), (object)null, true);

		internal static float Radius => SyncedRadius ?? ScanRadius.Value;

		internal static int Width => SyncedWidth ?? InboxWidth.Value;

		internal static int Height => SyncedHeight ?? InboxHeight.Value;

		private void Awake()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			ScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ScanRadius", 20f, new ConfigDescription("How far (meters) the inbox looks for matching chests. One floor tile = 2 m. Server value is enforced on clients.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 64f), Array.Empty<object>()));
			InboxWidth = ((BaseUnityPlugin)this).Config.Bind<int>("Inbox", "Columns", 8, new ConfigDescription("Inbox slot columns (wood chest = 5, max 8). Applies on world load; server value is enforced on clients.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
			InboxHeight = ((BaseUnityPlugin)this).Config.Bind<int>("Inbox", "Rows", 4, new ConfigDescription("Inbox slot rows (wood chest = 2). Applies on world load; server value is enforced on clients.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Debug", false, "Enable debug logging.");
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable auto-dispersion.");
			GlowIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "GlowIntensity", 3f, new ConfigDescription("Brightness of the Cybercrate's cyan runes (0 = off). Client-only, applies live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			GlowIntensity.SettingChanged += delegate
			{
				Cybercrate.UpdateGlow();
			};
			RequireMod = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "RequireMod", true, "Server/host only: disconnect players who don't have RoboticInbox or have a different version. If false, they may join and only a warning is logged.");
			new Harmony("com.darthjml.roboticinbox").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"RoboticInbox v1.2.0 loaded.");
		}

		private void Update()
		{
			try
			{
				ConfigSync.Tick();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)ex);
			}
			if (!Enabled.Value)
			{
				return;
			}
			_timer += Time.deltaTime;
			if (_timer < 1f)
			{
				return;
			}
			_timer = 0f;
			try
			{
				ProcessInboxes();
			}
			catch (Exception ex2)
			{
				if (DebugLog.Value || !_errorLogged)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)ex2);
				}
				_errorLogged = true;
			}
		}

		internal static void RegisterPrefab(ZNetScene zns)
		{
			//IL_00af: 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_004e: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			if ((Object)(object)RoboticInboxPrefab == (Object)null)
			{
				GameObject prefab = zns.GetPrefab("piece_chest_wood");
				if ((Object)(object)prefab == (Object)null)
				{
					Debug.LogWarning((object)"RoboticInbox: could not find piece_chest_wood prefab.");
					return;
				}
				if ((Object)(object)_prefabHolder == (Object)null)
				{
					_prefabHolder = new GameObject("RoboticInbox_PrefabHolder");
					_prefabHolder.SetActive(false);
					Object.DontDestroyOnLoad((Object)(object)_prefabHolder);
				}
				GameObject val = Object.Instantiate<GameObject>(prefab, _prefabHolder.transform, false);
				((Object)val).name = "RoboticInbox";
				Piece component = val.GetComponent<Piece>();
				component.m_name = "Robotic Inbox";
				component.m_description = "Storage box that automatically disperses items to nearby containers containing matching items.";
				component.m_enabled = true;
				component.m_category = (PieceCategory)0;
				component.m_craftingStation = null;
				List<Requirement> list = new List<Requirement>();
				string[] array = new string[2] { "Wood", "Stone" };
				foreach (string text in array)
				{
					GameObject prefab2 = zns.GetPrefab(text);
					ItemDrop val2 = ((prefab2 != null) ? prefab2.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val2 != (Object)null)
					{
						list.Add(new Requirement
						{
							m_resItem = val2,
							m_amount = 10,
							m_recover = true
						});
					}
					else
					{
						Debug.LogWarning((object)("RoboticInbox: material not found: " + text));
					}
				}
				component.m_resources = list.ToArray();
				component.m_dlc = "";
				Container component2 = val.GetComponent<Container>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.m_name = "Robotic Inbox";
				}
				try
				{
					Cybercrate.Apply(val);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("RoboticInbox: Cybercrate visual failed, keeping the wood chest look: " + ex));
				}
				RoboticInboxPrefab = val;
			}
			ApplyInboxSize();
			int stableHashCode = StringExtensionMethods.GetStableHashCode("RoboticInbox");
			Dictionary<int, GameObject> dictionary = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs").Invoke(zns);
			if (!dictionary.ContainsKey(stableHashCode))
			{
				zns.m_prefabs.Add(RoboticInboxPrefab);
				dictionary.Add(stableHashCode, RoboticInboxPrefab);
			}
			GameObject prefab3 = zns.GetPrefab("Hammer");
			PieceTable val3 = ((!((Object)(object)prefab3 != (Object)null)) ? null : prefab3.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
			if ((Object)(object)val3 == (Object)null)
			{
				Debug.LogWarning((object)"RoboticInbox: hammer piece table not found.");
				return;
			}
			val3.m_pieces.RemoveAll((GameObject go) => (Object)(object)go == (Object)null);
			if (!val3.m_pieces.Contains(RoboticInboxPrefab))
			{
				val3.m_pieces.Add(RoboticInboxPrefab);
			}
			Debug.Log((object)"RoboticInbox: prefab registered and added to hammer.");
		}

		internal static void ApplyInboxSize()
		{
			Container val = (((Object)(object)RoboticInboxPrefab != (Object)null) ? RoboticInboxPrefab.GetComponent<Container>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.m_width = Width;
				val.m_height = Height;
			}
		}

		private static bool IsInbox(Container c)
		{
			return ((Object)c).name.StartsWith("RoboticInbox", StringComparison.Ordinal);
		}

		private static bool CanWrite(Container c)
		{
			if (!c.IsOwner() || c.IsInUse() || c.GetInventory() == null)
			{
				return false;
			}
			ZNetView val = ContainerNView.Invoke(c);
			if ((Object)(object)val != (Object)null && val.IsValid())
			{
				return ContainerLastRevision.Invoke(c) == val.GetZDO().DataRevision;
			}
			return false;
		}

		private void ProcessInboxes()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Containers.RemoveAll((Container c) => (Object)(object)c == (Object)null);
			float num = Radius * Radius;
			long playerID = localPlayer.GetPlayerID();
			foreach (Container container in Containers)
			{
				if (!IsInbox(container) || !CanWrite(container))
				{
					continue;
				}
				Inventory inventory = container.GetInventory();
				if (inventory.NrOfItems() == 0)
				{
					continue;
				}
				Vector3 pos = ((Component)container).transform.position;
				List<Container> list = new List<Container>();
				foreach (Container container2 in Containers)
				{
					if (!((Object)(object)container2 == (Object)(object)container) && !IsInbox(container2))
					{
						Vector3 val = ((Component)container2).transform.position - pos;
						if (!(((Vector3)(ref val)).sqrMagnitude > num) && CanWrite(container2) && ContainerCheckAccess(container2, playerID) && !((Object)(object)((Component)container2).GetComponentInParent<TombStone>() != (Object)null))
						{
							list.Add(container2);
						}
					}
				}
				if (list.Count == 0)
				{
					continue;
				}
				list.Sort(delegate(Container a, Container b)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_000c: 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_0027: Unknown result type (might be due to invalid IL or missing references)
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0037: Unknown result type (might be due to invalid IL or missing references)
					Vector3 val3 = ((Component)a).transform.position - pos;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					val3 = ((Component)b).transform.position - pos;
					return sqrMagnitude.CompareTo(((Vector3)(ref val3)).sqrMagnitude);
				});
				foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
				{
					if (item == null || item.m_shared == null)
					{
						continue;
					}
					foreach (Container item2 in list)
					{
						Inventory inventory2 = item2.GetInventory();
						if (!inventory2.ContainsItemByName(item.m_shared.m_name))
						{
							continue;
						}
						int num2 = item.m_stack;
						if (!inventory2.CanAddItem(item, num2))
						{
							num2 = inventory2.FindFreeStackSpace(item.m_shared.m_name, (float)item.m_worldLevel);
							if (num2 <= 0)
							{
								continue;
							}
							num2 = Math.Min(num2, item.m_stack);
						}
						string name = item.m_shared.m_name;
						int num3 = inventory2.CountItems(name, -1, false);
						ItemData val2 = item.Clone();
						val2.m_stack = num2;
						inventory2.AddItem(val2);
						num2 = inventory2.CountItems(name, -1, false) - num3;
						if (num2 > 0)
						{
							inventory.RemoveItem(item, num2);
							if (DebugLog.Value)
							{
								((BaseUnityPlugin)this).Logger.LogInfo((object)$"RoboticInbox: moved {num2}x {item.m_shared.m_name} -> {((Object)item2).name}");
							}
							if (item.m_stack <= 0 || !inventory.ContainsItem(item))
							{
								break;
							}
						}
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	public static class Container_Awake_Patch
	{
		private static void Postfix(Container __instance)
		{
			if (__instance.GetInventory() != null)
			{
				RoboticInboxPlugin.Containers.Add(__instance);
			}
		}
	}
	public static class ConfigSync
	{
		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class OnNewConnection_Patch
		{
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				peer.m_rpc.Register<ZPackage>("RoboticInbox_Config", (Action<ZRpc, ZPackage>)RPC_Config);
				peer.m_rpc.Register<string>("RoboticInbox_Version", (Action<ZRpc, string>)RPC_Version);
				if (!__instance.IsServer())
				{
					_serverVersion = null;
					_rejectMessage = null;
					_pendingHudWarning = null;
				}
				peer.m_rpc.Invoke("RoboticInbox_Version", new object[1] { Mine });
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private static class RPC_PeerInfo_Patch
		{
			private static bool Prefix(ZNet __instance, ZRpc rpc, ref bool __state)
			{
				__state = true;
				try
				{
					if (!__instance.IsServer() || rpc == null)
					{
						return true;
					}
					PeerVersions.TryGetValue(rpc, out var value);
					PeerVersions.Remove(rpc);
					if (value == Mine)
					{
						return true;
					}
					string text = Endpoint(rpc);
					string text2 = ((value == null) ? ("client " + text + " does not have RoboticInbox (server has v" + Mine + ")") : ("client " + text + " has RoboticInbox v" + value + ", server has v" + Mine));
					if (!RoboticInboxPlugin.RequireMod.Value)
					{
						Debug.LogWarning((object)("RoboticInbox: " + text2 + "; allowed because Server.RequireMod = false."));
						return true;
					}
					Debug.LogWarning((object)("RoboticInbox: " + text2 + "; disconnecting (Server.RequireMod = true)."));
					rpc.Invoke("Error", new object[1] { 3 });
					PendingKicks[rpc] = Time.time + 3f;
					__state = false;
					return false;
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("RoboticInbox: version check failed, letting client in: " + ex));
					return true;
				}
			}

			private static void Postfix(ZNet __instance, ZRpc rpc, bool __state)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				if (!__state || rpc == null)
				{
					return;
				}
				if (!__instance.IsServer())
				{
					if (_serverVersion == null)
					{
						Debug.Log((object)"RoboticInbox: this server does not run RoboticInbox. Sorting still works for you with your local settings; players without the mod won't see inboxes.");
					}
					return;
				}
				ZPackage val = new ZPackage();
				val.Write(RoboticInboxPlugin.ScanRadius.Value);
				val.Write(RoboticInboxPlugin.InboxWidth.Value);
				val.Write(RoboticInboxPlugin.InboxHeight.Value);
				rpc.Invoke("RoboticInbox_Config", new object[1] { val });
			}
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect", new Type[] { typeof(ZNetPeer) })]
		private static class Disconnect_Patch
		{
			private static void Prefix(ZNetPeer peer)
			{
				if (peer?.m_rpc != null)
				{
					PeerVersions.Remove(peer.m_rpc);
					PendingKicks.Remove(peer.m_rpc);
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
		private static class ShowConnectError_Patch
		{
			private static void Postfix(FejdStartup __instance)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Invalid comparison between Unknown and I4
				if (_rejectMessage != null && (int)ZNet.GetConnectionStatus() == 3)
				{
					if ((Object)(object)__instance.m_connectionFailedError != (Object)null)
					{
						__instance.m_connectionFailedError.text = _rejectMessage;
					}
					_rejectMessage = null;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static class OnDestroy_Patch
		{
			private static void Postfix()
			{
				RoboticInboxPlugin.SyncedRadius = null;
				RoboticInboxPlugin.SyncedWidth = (RoboticInboxPlugin.SyncedHeight = null);
				RoboticInboxPlugin.ApplyInboxSize();
				PeerVersions.Clear();
				PendingKicks.Clear();
				_serverVersion = null;
				_pendingHudWarning = null;
			}
		}

		private const string RpcName = "RoboticInbox_Config";

		private const string VersionRpcName = "RoboticInbox_Version";

		private const float KickDelay = 3f;

		private static readonly Dictionary<ZRpc, string> PeerVersions = new Dictionary<ZRpc, string>();

		private static readonly Dictionary<ZRpc, float> PendingKicks = new Dictionary<ZRpc, float>();

		private static string _serverVersion;

		private static string _rejectMessage;

		private static string _pendingHudWarning;

		private static readonly Func<ZNet, ZRpc, ZNetPeer> GetPeer = AccessTools.MethodDelegate<Func<ZNet, ZRpc, ZNetPeer>>(AccessTools.Method(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null), (object)null, true);

		private static string Mine => "1.2.0";

		private static string Endpoint(ZRpc rpc)
		{
			try
			{
				ISocket socket = rpc.GetSocket();
				return ((socket != null) ? socket.GetEndPointString() : null) ?? "?";
			}
			catch
			{
				return "?";
			}
		}

		private static void RPC_Version(ZRpc rpc, string version)
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || rpc == null)
			{
				return;
			}
			version = version ?? "";
			if (instance.IsServer())
			{
				PeerVersions[rpc] = version;
				if (version != Mine)
				{
					Debug.LogWarning((object)("RoboticInbox: client " + Endpoint(rpc) + " has RoboticInbox v" + version + ", server has v" + Mine + "."));
				}
				return;
			}
			_serverVersion = version;
			if (version == Mine)
			{
				Debug.Log((object)("RoboticInbox: server runs RoboticInbox v" + version + " (same as ours)."));
				return;
			}
			Debug.LogWarning((object)("RoboticInbox: VERSION MISMATCH - server has RoboticInbox v" + version + ", you have v" + Mine + "."));
			_rejectMessage = "This server requires Robotic Inbox v" + version + ".\nYou have v" + Mine + ".\n\nImport the server's r2modman profile code (or install Robotic Inbox v" + version + ") and try again.";
			_pendingHudWarning = "Robotic Inbox version mismatch!\nServer v" + version + ", you v" + Mine + ". Please update.";
		}

		internal static void Tick()
		{
			if (PendingKicks.Count > 0)
			{
				ZNet instance = ZNet.instance;
				foreach (ZRpc item in new List<ZRpc>(PendingKicks.Keys))
				{
					if (!((Object)(object)instance != (Object)null) || !(Time.time < PendingKicks[item]))
					{
						PendingKicks.Remove(item);
						ZNetPeer val = (((Object)(object)instance != (Object)null) ? GetPeer(instance, item) : null);
						if (val != null)
						{
							Debug.Log((object)("RoboticInbox: disconnecting rejected client " + Endpoint(item) + "."));
							instance.Disconnect(val);
						}
					}
				}
			}
			if (_pendingHudWarning != null && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)2, _pendingHudWarning, 0, (Sprite)null, false, true);
				_pendingHudWarning = null;
			}
		}

		private static void RPC_Config(ZRpc rpc, ZPackage pkg)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				RoboticInboxPlugin.SyncedRadius = Mathf.Clamp(pkg.ReadSingle(), 1f, 64f);
				RoboticInboxPlugin.SyncedWidth = Mathf.Clamp(pkg.ReadInt(), 1, 8);
				RoboticInboxPlugin.SyncedHeight = Mathf.Clamp(pkg.ReadInt(), 1, 8);
				RoboticInboxPlugin.ApplyInboxSize();
				Debug.Log((object)$"RoboticInbox: using server config radius={RoboticInboxPlugin.SyncedRadius} size={RoboticInboxPlugin.SyncedWidth}x{RoboticInboxPlugin.SyncedHeight}");
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	public static class ZNetScene_Awake_Patch
	{
		private static void Postfix(ZNetScene __instance)
		{
			try
			{
				RoboticInboxPlugin.RegisterPrefab(__instance);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("RoboticInbox: register failed " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")]
	public static class Player_UpdateKnownRecipesList_Patch
	{
		private static string _lastState;

		private static readonly FieldRef<Player, HashSet<string>> KnownRecipes = AccessTools.FieldRefAccess<Player, HashSet<string>>("m_knownRecipes");

		private static readonly MethodInfo UpdateAvailablePiecesList = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);

		private static void Postfix(Player __instance)
		{
			try
			{
				GameObject roboticInboxPrefab = RoboticInboxPlugin.RoboticInboxPrefab;
				if ((Object)(object)roboticInboxPrefab == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				Piece component = roboticInboxPrefab.GetComponent<Piece>();
				HashSet<string> hashSet = KnownRecipes.Invoke(__instance);
				List<PieceTable> list = new List<PieceTable>();
				((Humanoid)__instance).GetInventory().GetAllPieceTables(list);
				int num = 0;
				int num2 = 0;
				foreach (PieceTable item in list)
				{
					if (!((Object)(object)item == (Object)null) && item.m_pieces != null && item.m_pieces.Exists((GameObject g) => (Object)(object)g != (Object)null && ((Object)g).name == "piece_chest_wood"))
					{
						num++;
						if (!item.m_pieces.Contains(roboticInboxPrefab))
						{
							item.m_pieces.Add(roboticInboxPrefab);
							num2++;
						}
					}
				}
				bool flag = hashSet.Contains(component.m_name);
				if (num > 0 && !flag)
				{
					hashSet.Add(component.m_name);
				}
				if (num2 > 0 || (num > 0 && !flag))
				{
					UpdateAvailablePiecesList.Invoke(__instance, null);
				}
				string text = $"tables={list.Count} hammerTables={num} added={num2} wasKnown={flag}";
				if (text != _lastState)
				{
					_lastState = text;
					Debug.Log((object)("RoboticInbox: " + text));
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("RoboticInbox: known-list patch failed: " + ex));
			}
		}
	}
}