Decompiled source of SymmetricalBuildingPieces v1.0.0

plugins/SymmetricalBuildingPieces.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.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 SymmetricalBuildingPieces
{
	internal static class MeshSymmetrizer
	{
		private sealed class Vtx
		{
			public Vector3 P;

			public Vector3 N;

			public Vector4 T;

			public Color C;

			public readonly Vector4[] Uv = (Vector4[])(object)new Vector4[4];

			public float D;
		}

		private const float InsideEps = 1E-05f;

		private const float OnPlaneEps = 0.0001f;

		private const int UvChannels = 4;

		public static void Build(Mesh src, Mesh dst, Matrix4x4 meshToRoot, Vector3 planePoint, Vector3 keepNormal)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: 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_000c: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: 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_01b1: 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)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Invalid comparison between Unknown and I4
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			((Vector3)(ref keepNormal)).Normalize();
			Matrix4x4 rootToMesh = ((Matrix4x4)(ref meshToRoot)).inverse;
			Matrix4x4 transpose = ((Matrix4x4)(ref rootToMesh)).transpose;
			Matrix4x4 normalToMesh = ((Matrix4x4)(ref meshToRoot)).transpose;
			List<Vector3> list = new List<Vector3>();
			src.GetVertices(list);
			List<Vector3> list2 = new List<Vector3>();
			src.GetNormals(list2);
			List<Vector4> list3 = new List<Vector4>();
			src.GetTangents(list3);
			List<Color> list4 = new List<Color>();
			src.GetColors(list4);
			int count = list.Count;
			bool hasN = list2.Count == count;
			bool hasT = list3.Count == count;
			bool hasC = list4.Count == count;
			List<Vector4>[] array = new List<Vector4>[4];
			bool[] hasUv = new bool[4];
			int[] array2 = new int[4];
			for (int i = 0; i < 4; i++)
			{
				array[i] = new List<Vector4>();
				VertexAttribute val = (VertexAttribute)(4 + i);
				hasUv[i] = src.HasVertexAttribute(val);
				if (hasUv[i])
				{
					src.GetUVs(i, array[i]);
					hasUv[i] = array[i].Count == count;
					array2[i] = src.GetVertexAttributeDimension(val);
				}
			}
			Vtx[] array3 = new Vtx[count];
			for (int j = 0; j < count; j++)
			{
				Vtx vtx = new Vtx
				{
					P = ((Matrix4x4)(ref meshToRoot)).MultiplyPoint3x4(list[j])
				};
				Vector3 val2;
				if (hasN)
				{
					val2 = ((Matrix4x4)(ref transpose)).MultiplyVector(list2[j]);
					vtx.N = ((Vector3)(ref val2)).normalized;
				}
				if (hasT)
				{
					val2 = ((Matrix4x4)(ref meshToRoot)).MultiplyVector(Vector4.op_Implicit(list3[j]));
					Vector3 normalized = ((Vector3)(ref val2)).normalized;
					vtx.T = new Vector4(normalized.x, normalized.y, normalized.z, list3[j].w);
				}
				if (hasC)
				{
					vtx.C = list4[j];
				}
				for (int k = 0; k < 4; k++)
				{
					if (hasUv[k])
					{
						vtx.Uv[k] = array[k][j];
					}
				}
				vtx.D = Vector3.Dot(vtx.P - planePoint, keepNormal);
				array3[j] = vtx;
			}
			List<Vector3> oPos = new List<Vector3>();
			List<Vector3> oNrm = new List<Vector3>();
			List<Vector4> oTan = new List<Vector4>();
			List<Color> oCol = new List<Color>();
			List<Vector4>[] oUv = new List<Vector4>[4];
			for (int l = 0; l < 4; l++)
			{
				oUv[l] = new List<Vector4>();
			}
			int subMeshCount = src.subMeshCount;
			List<int>[] array4 = new List<int>[subMeshCount];
			List<int> list5 = new List<int>();
			List<Vtx> list6 = new List<Vtx>(4);
			for (int m = 0; m < subMeshCount; m++)
			{
				List<int> list7 = (array4[m] = new List<int>());
				if ((int)src.GetTopology(m) > 0)
				{
					continue;
				}
				list5.Clear();
				src.GetTriangles(list5, m);
				for (int n = 0; n + 2 < list5.Count; n += 3)
				{
					Vtx vtx2 = array3[list5[n]];
					Vtx vtx3 = array3[list5[n + 1]];
					Vtx vtx4 = array3[list5[n + 2]];
					if (!(Mathf.Abs(vtx2.D) < 0.0001f) || !(Mathf.Abs(vtx3.D) < 0.0001f) || !(Mathf.Abs(vtx4.D) < 0.0001f))
					{
						ClipToKeepSide(vtx2, vtx3, vtx4, list6);
						for (int num = 1; num + 1 < list6.Count; num++)
						{
							Vtx v = list6[0];
							Vtx v2 = list6[num];
							Vtx v3 = list6[num + 1];
							list7.Add(Emit(v, mirror: false));
							list7.Add(Emit(v2, mirror: false));
							list7.Add(Emit(v3, mirror: false));
							list7.Add(Emit(v, mirror: true));
							list7.Add(Emit(v3, mirror: true));
							list7.Add(Emit(v2, mirror: true));
						}
					}
				}
			}
			dst.Clear();
			dst.indexFormat = (IndexFormat)(oPos.Count > 65000);
			dst.SetVertices(oPos);
			if (hasN)
			{
				dst.SetNormals(oNrm);
			}
			if (hasT)
			{
				dst.SetTangents(oTan);
			}
			if (hasC)
			{
				dst.SetColors(oCol);
			}
			for (int num2 = 0; num2 < 4; num2++)
			{
				if (!hasUv[num2])
				{
					continue;
				}
				if (array2[num2] <= 2)
				{
					dst.SetUVs(num2, oUv[num2].ConvertAll((Converter<Vector4, Vector2>)((Vector4 u) => new Vector2(u.x, u.y))));
				}
				else if (array2[num2] == 3)
				{
					dst.SetUVs(num2, oUv[num2].ConvertAll((Converter<Vector4, Vector3>)((Vector4 u) => new Vector3(u.x, u.y, u.z))));
				}
				else
				{
					dst.SetUVs(num2, oUv[num2]);
				}
			}
			dst.subMeshCount = subMeshCount;
			for (int num3 = 0; num3 < subMeshCount; num3++)
			{
				dst.SetTriangles(array4[num3], num3, false);
			}
			if (!hasN)
			{
				dst.RecalculateNormals();
			}
			if (!hasT && hasN)
			{
				dst.RecalculateTangents();
			}
			dst.RecalculateBounds();
			int Emit(Vtx vtx5, bool mirror)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_00d9: 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_004e: 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_0055: 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_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: 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)
				//IL_009f: 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_00a5: 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_00ad: 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_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: 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_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_0125: Unknown result type (might be due to invalid IL or missing references)
				//IL_0126: 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_012f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0134: Unknown result type (might be due to invalid IL or missing references)
				//IL_013c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0143: 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_0152: Unknown result type (might be due to invalid IL or missing references)
				//IL_0171: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val3 = vtx5.P;
				Vector3 val4 = vtx5.N;
				Vector3 val5 = default(Vector3);
				((Vector3)(ref val5))..ctor(vtx5.T.x, vtx5.T.y, vtx5.T.z);
				float num4 = vtx5.T.w;
				if (mirror)
				{
					float num5 = Vector3.Dot(val3 - planePoint, keepNormal);
					val3 -= 2f * num5 * keepNormal;
					val4 -= 2f * Vector3.Dot(val4, keepNormal) * keepNormal;
					val5 -= 2f * Vector3.Dot(val5, keepNormal) * keepNormal;
					num4 = 0f - num4;
				}
				oPos.Add(((Matrix4x4)(ref rootToMesh)).MultiplyPoint3x4(val3));
				Vector3 val6;
				if (hasN)
				{
					List<Vector3> list8 = oNrm;
					val6 = ((Matrix4x4)(ref normalToMesh)).MultiplyVector(val4);
					list8.Add(((Vector3)(ref val6)).normalized);
				}
				if (hasT)
				{
					val6 = ((Matrix4x4)(ref rootToMesh)).MultiplyVector(val5);
					Vector3 normalized2 = ((Vector3)(ref val6)).normalized;
					oTan.Add(new Vector4(normalized2.x, normalized2.y, normalized2.z, num4));
				}
				if (hasC)
				{
					oCol.Add(vtx5.C);
				}
				for (int num6 = 0; num6 < 4; num6++)
				{
					if (hasUv[num6])
					{
						oUv[num6].Add(vtx5.Uv[num6]);
					}
				}
				return oPos.Count - 1;
			}
		}

		private static void ClipToKeepSide(Vtx a, Vtx b, Vtx c, List<Vtx> result)
		{
			result.Clear();
			Vtx[] array = new Vtx[3] { a, b, c };
			for (int i = 0; i < 3; i++)
			{
				Vtx vtx = array[i];
				Vtx vtx2 = array[(i + 1) % 3];
				bool flag = vtx.D >= -1E-05f;
				bool flag2 = vtx2.D >= -1E-05f;
				if (flag)
				{
					result.Add(vtx);
				}
				if (flag != flag2)
				{
					result.Add(Lerp(vtx, vtx2, vtx.D / (vtx.D - vtx2.D)));
				}
			}
			if (result.Count < 3)
			{
				result.Clear();
			}
		}

		private static Vtx Lerp(Vtx a, Vtx b, float t)
		{
			//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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0040: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_00af: 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_00b7: 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_00be: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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)
			//IL_0103: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			Vtx obj = new Vtx
			{
				P = Vector3.Lerp(a.P, b.P, t)
			};
			Vector3 val = Vector3.Lerp(a.N, b.N, t);
			obj.N = ((Vector3)(ref val)).normalized;
			obj.C = Color.Lerp(a.C, b.C, t);
			obj.D = 0f;
			Vtx vtx = obj;
			val = Vector3.Lerp(new Vector3(a.T.x, a.T.y, a.T.z), new Vector3(b.T.x, b.T.y, b.T.z), t);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			vtx.T = new Vector4(normalized.x, normalized.y, normalized.z, a.T.w);
			for (int i = 0; i < 4; i++)
			{
				vtx.Uv[i] = Vector4.Lerp(a.Uv[i], b.Uv[i], t);
			}
			return vtx;
		}
	}
	internal static class PieceRegistry
	{
		private sealed class MeshPair
		{
			public MeshFilter Filter;

			public Mesh Source;

			public Mesh Result;
		}

		private sealed class Entry
		{
			public string Source;

			public GameObject Clone;

			public readonly List<MeshPair> Meshes = new List<MeshPair>();
		}

		public const string ClonePrefix = "SBP_";

		private static readonly Dictionary<string, Entry> Entries = new Dictionary<string, Entry>();

		private static readonly HashSet<string> Missing = new HashSet<string>();

		private static GameObject _holder;

		private static readonly FieldRef<ZNetScene, Dictionary<int, GameObject>> NamedPrefabs = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs");

		private static MethodInfo _loadImage;

		private static Dictionary<string, char> ParsePieceList()
		{
			Dictionary<string, char> dictionary = new Dictionary<string, char>(StringComparer.Ordinal);
			string[] array = Plugin.PieceList.Value.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				string text2 = text.Trim();
				if (text2.Length != 0)
				{
					string[] array2 = text2.Split(new char[1] { ':' });
					string key = array2[0].Trim();
					int num;
					switch ((array2.Length > 1) ? array2[1].Trim().ToLowerInvariant() : "auto")
					{
					default:
						num = 97;
						break;
					case "flip":
						num = 102;
						break;
					case "-":
					case "back":
						num = 45;
						break;
					case "+":
					case "front":
						num = 43;
						break;
					}
					char value = (char)num;
					dictionary[key] = value;
				}
			}
			return dictionary;
		}

		public static void TrySetup()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)_holder == (Object)null)
			{
				_holder = new GameObject("SBP_PrefabHolder");
				_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_holder);
			}
			foreach (KeyValuePair<string, char> item in ParsePieceList())
			{
				if (!Entries.ContainsKey(item.Key) && !Missing.Contains(item.Key))
				{
					CreateClone(item.Key, item.Value);
				}
			}
			RegisterWithZNetScene();
			AddToHammer();
		}

		private static void CreateClone(string sourceName, char side)
		{
			//IL_0168: 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_0187: Expected O, but got Unknown
			GameObject prefab = ZNetScene.instance.GetPrefab(sourceName);
			if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<Piece>() == (Object)null)
			{
				Missing.Add(sourceName);
				Plugin.Log.LogWarning((object)("'" + sourceName + "' is not a known piece prefab. Run 'sbp_dump' in the F5 console to list prefab names."));
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, _holder.transform, false);
			((Object)val).name = "SBP_" + sourceName;
			Piece component = val.GetComponent<Piece>();
			component.m_name += Plugin.NameSuffix.Value;
			Sprite val2 = LoadIconOverride(sourceName);
			if ((Object)(object)val2 != (Object)null)
			{
				component.m_icon = val2;
			}
			Entry entry = new Entry
			{
				Source = sourceName,
				Clone = val
			};
			MeshFilter[] componentsInChildren = val.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val3 in componentsInChildren)
			{
				Mesh sharedMesh = val3.sharedMesh;
				if (!((Object)(object)sharedMesh == (Object)null))
				{
					if (!sharedMesh.isReadable)
					{
						Plugin.Log.LogError((object)(sourceName + ": mesh '" + ((Object)sharedMesh).name + "' on '" + GetPath(((Component)val3).transform, val.transform) + "' is not readable — left unchanged."));
					}
					else
					{
						Mesh val4 = new Mesh
						{
							name = ((Object)sharedMesh).name + "_sym"
						};
						entry.Meshes.Add(new MeshPair
						{
							Filter = val3,
							Source = sharedMesh,
							Result = val4
						});
						val3.sharedMesh = val4;
					}
				}
			}
			Entries[sourceName] = entry;
			Build(entry, side);
			Plugin.Log.LogInfo((object)$"Created {((Object)val).name} ({entry.Meshes.Count} meshes symmetrized).");
		}

		private static void Build(Entry entry, char side)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			if (entry.Meshes.Count == 0)
			{
				return;
			}
			Transform transform = entry.Clone.transform;
			Analyze(transform, entry.Meshes.Select((MeshPair m) => (Filter: m.Filter, Source: m.Source)), out var axis, out var planePoint, out var posExtent, out var negExtent);
			char c = ((Mathf.Abs(posExtent - negExtent) < 0.005f) ? '+' : ((posExtent < negExtent) ? '+' : '-'));
			char c2 = side switch
			{
				'f' => (c == '+') ? '-' : '+', 
				'a' => c, 
				_ => side, 
			};
			Vector3 keepNormal = ((c2 == '+') ? axis : (-axis));
			foreach (MeshPair mesh in entry.Meshes)
			{
				Matrix4x4 meshToRoot = transform.worldToLocalMatrix * ((Component)mesh.Filter).transform.localToWorldMatrix;
				MeshSymmetrizer.Build(mesh.Source, mesh.Result, meshToRoot, planePoint, keepNormal);
			}
			Plugin.Log.LogInfo((object)$"{((Object)entry.Clone).name}: thin axis {AxisName(axis)}, extents +{posExtent:0.###} / -{negExtent:0.###}, keeping '{c2}' side (config: '{side}').");
		}

		private static void Analyze(Transform root, IEnumerable<(MeshFilter filter, Mesh mesh)> meshes, out Vector3 axis, out Vector3 planePoint, out float posExtent, out float negExtent)
		{
			//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_0007: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0073: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_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)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00a6: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: 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)
			Vector3 val = Vector3.positiveInfinity;
			Vector3 val2 = Vector3.negativeInfinity;
			List<Vector3> list = new List<Vector3>();
			foreach (var mesh in meshes)
			{
				MeshFilter item = mesh.filter;
				Mesh item2 = mesh.mesh;
				Matrix4x4 val3 = root.worldToLocalMatrix * ((Component)item).transform.localToWorldMatrix;
				list.Clear();
				if (item2.isReadable)
				{
					item2.GetVertices(list);
				}
				else
				{
					list.AddRange(BoundsCorners(item2.bounds));
				}
				foreach (Vector3 item3 in list)
				{
					Vector3 val4 = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(item3);
					val = Vector3.Min(val, val4);
					val2 = Vector3.Max(val2, val4);
				}
			}
			Vector3 val5 = val2 - val;
			axis = ((val5.x < val5.z) ? Vector3.right : Vector3.forward);
			float num = Vector3.Dot(val, axis);
			float num2 = Vector3.Dot(val2, axis);
			float num3 = ((Plugin.Plane.Value == PlaneMode.BoundsCenter) ? ((num + num2) * 0.5f) : 0f);
			num3 += Plugin.PlaneOffset.Value;
			planePoint = axis * num3;
			posExtent = num2 - num3;
			negExtent = num3 - num;
		}

		public static void RebuildAll()
		{
			Dictionary<string, char> dictionary = ParsePieceList();
			foreach (Entry value2 in Entries.Values)
			{
				Build(value2, dictionary.TryGetValue(value2.Source, out var value) ? value : 'a');
			}
			if (dictionary.Keys.Any((string k) => !Entries.ContainsKey(k) && !Missing.Contains(k)))
			{
				Plugin.Log.LogInfo((object)"New pieces in the list will be added the next time a world loads.");
			}
		}

		private static void RegisterWithZNetScene()
		{
			ZNetScene instance = ZNetScene.instance;
			Dictionary<int, GameObject> dictionary = NamedPrefabs.Invoke(instance);
			foreach (Entry value in Entries.Values)
			{
				if (!instance.m_prefabs.Contains(value.Clone))
				{
					instance.m_prefabs.Add(value.Clone);
				}
				dictionary[StringExtensionMethods.GetStableHashCode(((Object)value.Clone).name)] = value.Clone;
			}
		}

		private static void AddToHammer()
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer");
			PieceTable val = ((!Object.op_Implicit((Object)(object)itemPrefab)) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Hammer piece table not found.");
				return;
			}
			List<GameObject> pieces = val.m_pieces;
			foreach (Entry e in Entries.Values)
			{
				if (!pieces.Contains(e.Clone))
				{
					int num = pieces.FindIndex((GameObject p) => (Object)(object)p != (Object)null && ((Object)p).name == e.Source);
					if (num >= 0)
					{
						pieces.Insert(num + 1, e.Clone);
					}
					else
					{
						pieces.Add(e.Clone);
					}
				}
			}
		}

		public static int Dump(string filter)
		{
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab("Hammer") : null);
			PieceTable val2 = ((!Object.op_Implicit((Object)(object)val)) ? null : val.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
			if ((Object)(object)val2 == (Object)null)
			{
				return 0;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("===== SBP dump (filter: '" + filter + "') =====");
			int num = 0;
			foreach (GameObject piece in val2.m_pieces)
			{
				if ((Object)(object)piece == (Object)null || ((Object)piece).name.StartsWith("SBP_"))
				{
					continue;
				}
				Piece component = piece.GetComponent<Piece>();
				string text = ((Object.op_Implicit((Object)(object)component) && Localization.instance != null) ? Localization.instance.Localize(component.m_name) : "");
				if (((Object)piece).name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				num++;
				stringBuilder.AppendLine($"{((Object)piece).name}  |  \"{text}\"  |  category {component?.m_category}");
				List<MeshFilter> list = (from f in piece.GetComponentsInChildren<MeshFilter>(true)
					where (Object)(object)f.sharedMesh != (Object)null
					select f).ToList();
				foreach (MeshFilter item in list)
				{
					Mesh sharedMesh = item.sharedMesh;
					MeshRenderer component2 = ((Component)item).GetComponent<MeshRenderer>();
					string text2 = (Object.op_Implicit((Object)(object)component2) ? string.Join(", ", ((Renderer)component2).sharedMaterials.Select((Material m) => Object.op_Implicit((Object)(object)m) ? ((Object)m).name : "null")) : "-");
					stringBuilder.AppendLine($"    {GetPath(((Component)item).transform, piece.transform)}: mesh '{((Object)sharedMesh).name}' readable={sharedMesh.isReadable} verts={sharedMesh.vertexCount} submeshes={sharedMesh.subMeshCount} mats=[{text2}]");
				}
				if (list.Count > 0)
				{
					Analyze(piece.transform, list.Select((MeshFilter f) => (f: f, sharedMesh: f.sharedMesh)), out var axis, out var _, out var posExtent, out var negExtent);
					stringBuilder.AppendLine($"    thin axis {AxisName(axis)}, extents from plane: +{posExtent:0.###} / -{negExtent:0.###}");
				}
			}
			stringBuilder.AppendLine($"===== {num} pieces =====");
			Plugin.Log.LogInfo((object)stringBuilder.ToString());
			return num;
		}

		private static Sprite LoadIconOverride(string sourceName)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.GetDirectoryName(Plugin.PluginPath) ?? "";
			string[] source = new string[2]
			{
				Path.Combine(path, "icons", sourceName + ".png"),
				Path.Combine(path, sourceName + ".png")
			};
			string text = source.FirstOrDefault(File.Exists);
			if (text == null)
			{
				return null;
			}
			try
			{
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					name = "SBP_icon_" + sourceName
				};
				if (!LoadImage(val, File.ReadAllBytes(text)))
				{
					Plugin.Log.LogWarning((object)("Could not decode icon '" + text + "'."));
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)1;
				Plugin.Log.LogInfo((object)("Using custom icon for " + sourceName + ": " + text));
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to load icon '" + text + "': " + ex.Message));
				return null;
			}
		}

		private static bool LoadImage(Texture2D tex, byte[] data)
		{
			if (_loadImage == null)
			{
				_loadImage = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				});
				if (_loadImage == null)
				{
					Plugin.Log.LogWarning((object)"UnityEngine.ImageConversion.LoadImage not found; custom icons disabled.");
					return false;
				}
			}
			return (bool)_loadImage.Invoke(null, new object[2] { tex, data });
		}

		private static string AxisName(Vector3 axis)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return (axis == Vector3.right) ? "X" : "Z";
		}

		private static IEnumerable<Vector3> BoundsCorners(Bounds b)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 8; i++)
			{
				yield return new Vector3(((i & 1) == 0) ? ((Bounds)(ref b)).min.x : ((Bounds)(ref b)).max.x, ((i & 2) == 0) ? ((Bounds)(ref b)).min.y : ((Bounds)(ref b)).max.y, ((i & 4) == 0) ? ((Bounds)(ref b)).min.z : ((Bounds)(ref b)).max.z);
			}
		}

		private static string GetPath(Transform t, Transform root)
		{
			List<string> list = new List<string>();
			while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root)
			{
				list.Add(((Object)t).name);
				t = t.parent;
			}
			list.Reverse();
			return (list.Count == 0) ? "(root)" : string.Join("/", list);
		}
	}
	public enum PlaneMode
	{
		Pivot,
		BoundsCenter
	}
	[BepInPlugin("bhimajenkins.symmetricalbuildingpieces", "Symmetrical Building Pieces", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "bhimajenkins.symmetricalbuildingpieces";

		public const string Name = "Symmetrical Building Pieces";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		internal static string PluginPath;

		internal static ConfigEntry<string> PieceList;

		internal static ConfigEntry<string> NameSuffix;

		internal static ConfigEntry<PlaneMode> Plane;

		internal static ConfigEntry<float> PlaneOffset;

		private const string DefaultPieces = "woodwall, wood_wall_half, wood_wall_quarter, scale_wall_2x2, scale_halfwall_1x2, scale_quarterwall_1x1, scale_wall_roof_26:flip, scale_wall_roof_45:flip, scale_wall_roof_67, scale_wall_roof_26_upsidedown_flipped, scale_wall_roof_45_upsidedown_flipped, scale_wall_roof_67_upsidedown_flipped, ashwood_quarterwall_1x1:flip, ashwood_halfwall_1x2, ashwood_wall_2x2, stave_wall_2x2";

		private void Awake()
		{
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			PluginPath = ((BaseUnityPlugin)this).Info.Location;
			PieceList = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Pieces", "woodwall, wood_wall_half, wood_wall_quarter, scale_wall_2x2, scale_halfwall_1x2, scale_quarterwall_1x1, scale_wall_roof_26:flip, scale_wall_roof_45:flip, scale_wall_roof_67, scale_wall_roof_26_upsidedown_flipped, scale_wall_roof_45_upsidedown_flipped, scale_wall_roof_67_upsidedown_flipped, ashwood_quarterwall_1x1:flip, ashwood_halfwall_1x2, ashwood_wall_2x2, stave_wall_2x2", "Comma-separated vanilla prefab names to make symmetrical copies of.\nAdd ':+' or ':-' to force which face is kept, or ':flip' for the opposite of auto (default 'auto' keeps the flatter face).\nExample: woodwall:+, wood_wall_half:-\nChanging a side rebuilds placed pieces live; newly added names apply on next world load.");
			NameSuffix = ((BaseUnityPlugin)this).Config.Bind<string>("General", "NameSuffix", " (Symmetrical)", "Text added after the vanilla name in the build menu. Takes effect on restart.");
			Plane = ((BaseUnityPlugin)this).Config.Bind<PlaneMode>("Advanced", "MirrorPlane", PlaneMode.Pivot, "Where the mirror plane sits. Pivot = piece origin. BoundsCenter = middle of the thickness.");
			PlaneOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "MirrorPlaneOffset", 0f, "Extra offset (metres) of the mirror plane along the wall's thickness axis.");
			PieceList.SettingChanged += delegate
			{
				PieceRegistry.RebuildAll();
			};
			Plane.SettingChanged += delegate
			{
				PieceRegistry.RebuildAll();
			};
			PlaneOffset.SettingChanged += delegate
			{
				PieceRegistry.RebuildAll();
			};
			new Harmony("bhimajenkins.symmetricalbuildingpieces").PatchAll();
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetSceneAwakePatch
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			PieceRegistry.TrySetup();
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDBAwakePatch
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			PieceRegistry.TrySetup();
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class TerminalPatch
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			public static ConsoleEvent <>9__0_1;

			internal void <Postfix>b__0_0(ConsoleEventArgs args)
			{
				string filter = ((args.Length > 1) ? args[1] : "wall");
				int num = PieceRegistry.Dump(filter);
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString($"SBP: {num} pieces written to BepInEx/LogOutput.log");
				}
			}

			internal void <Postfix>b__0_1(ConsoleEventArgs args)
			{
				((ConfigEntryBase)Plugin.PieceList).ConfigFile.Reload();
				PieceRegistry.RebuildAll();
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("SBP: rebuilt");
				}
			}
		}

		private static void Postfix()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_006d: 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_0063: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					string filter = ((args.Length > 1) ? args[1] : "wall");
					int num = PieceRegistry.Dump(filter);
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString($"SBP: {num} pieces written to BepInEx/LogOutput.log");
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("sbp_dump", "[filter] - log Hammer pieces whose prefab or display name contains filter (default 'wall'), with mesh info", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__0_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					((ConfigEntryBase)Plugin.PieceList).ConfigFile.Reload();
					PieceRegistry.RebuildAll();
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString("SBP: rebuilt");
					}
				};
				<>c.<>9__0_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("sbp_rebuild", "- re-read the SBP config and rebuild all symmetrical meshes", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
}