Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SmartBuild v1.10.1
SmartBuild.dll
Decompiled 14 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [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 SmartBuild { internal readonly struct WorldPiece { public readonly string Prefab; public readonly Vector3 Position; public readonly Quaternion Rotation; public readonly string SignText; public readonly int? DoorState; public WorldPiece(string prefab, Vector3 position, Quaternion rotation, string signText = null, int? doorState = null) { //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) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Prefab = prefab; Position = position; Rotation = rotation; SignText = signText; DoorState = doorState; } } internal readonly struct PieceBounds { public readonly Vector3 Min; public readonly Vector3 Max; public readonly Vector3[] SnapPoints; public PieceBounds(Vector3 min, Vector3 max, Vector3[] snapPoints = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0009: Unknown result type (might be due to invalid IL or missing references) Min = min; Max = max; SnapPoints = snapPoints; } } internal sealed class BlueprintItem { public readonly string Prefab; public readonly Vector3 Position; public readonly Quaternion Rotation; public readonly string SignText; public readonly int? DoorState; public BlueprintItem(string prefab, Vector3 position, Quaternion rotation, string signText = null, int? doorState = null) { //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) //IL_0015: 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) Prefab = prefab; Position = position; Rotation = rotation; SignText = signText; DoorState = doorState; } } internal sealed class Blueprint { private readonly List<BlueprintItem> _items; private const float SharedSnapDistance = 0.01f; private const float DefaultLabelTolerance = 0.05f; public string Name { get; } public IReadOnlyList<BlueprintItem> Items => _items; public Blueprint(string name, IEnumerable<BlueprintItem> items) { if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("A blueprint needs a name.", "name"); } if (name.IndexOf('\n') >= 0 || name.IndexOf('\r') >= 0) { throw new ArgumentException("A blueprint name is one line.", "name"); } if (items == null) { throw new ArgumentException("A blueprint needs at least one item.", "items"); } _items = new List<BlueprintItem>(items); if (_items.Count == 0) { throw new ArgumentException("A blueprint needs at least one item.", "items"); } foreach (BlueprintItem item in _items) { if (item == null || !IsSingleWord(item.Prefab)) { throw new ArgumentException("A piece name is one word with no spaces.", "items"); } } Name = name; } internal static bool IsSingleWord(string text) { if (string.IsNullOrEmpty(text)) { return false; } for (int i = 0; i < text.Length; i++) { if (char.IsWhiteSpace(text[i])) { return false; } } return true; } public IEnumerable<string> PrefabsByUsage() { Dictionary<string, int> counts = new Dictionary<string, int>(StringComparer.Ordinal); List<string> list = new List<string>(); foreach (BlueprintItem item in _items) { if (!counts.ContainsKey(item.Prefab)) { list.Add(item.Prefab); } counts.TryGetValue(item.Prefab, out var value); counts[item.Prefab] = value + 1; } return list.OrderByDescending((string name) => counts[name]); } private static Quaternion Inverse(Quaternion q) { //IL_0000: 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_000d: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0038: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) float num = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; return new Quaternion((0f - q.x) / num, (0f - q.y) / num, (0f - q.z) / num, q.w / num); } public static Blueprint FromWorld(string name, IList<WorldPiece> pieces) { Vector3 anchorPosition; Quaternion anchorRotation; return FromWorld(name, pieces, out anchorPosition, out anchorRotation); } public static Blueprint FromWorld(string name, IList<WorldPiece> pieces, out Vector3 anchorPosition, out Quaternion anchorRotation) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011f: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: 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) //IL_016c: Unknown result type (might be due to invalid IL or missing references) if (pieces == null || pieces.Count == 0) { throw new ArgumentException("A blueprint needs at least one piece.", "pieces"); } WorldPiece worldPiece = pieces[0]; Quaternion val = FacingOf(worldPiece.Rotation); Quaternion val2 = Inverse(val); Vector3[] array = (Vector3[])(object)new Vector3[pieces.Count]; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(float.MaxValue, float.MaxValue, float.MaxValue); for (int i = 0; i < pieces.Count; i++) { array[i] = val2 * (pieces[i].Position - worldPiece.Position); ((Vector3)(ref val3))..ctor(Mathf.Min(val3.x, array[i].x), Mathf.Min(val3.y, array[i].y), Mathf.Min(val3.z, array[i].z)); } List<BlueprintItem> list = new List<BlueprintItem>(pieces.Count); for (int j = 0; j < pieces.Count; j++) { WorldPiece worldPiece2 = pieces[j]; list.Add(new BlueprintItem(worldPiece2.Prefab, array[j] - val3, val2 * worldPiece2.Rotation, worldPiece2.SignText, worldPiece2.DoorState)); } anchorPosition = worldPiece.Position + val * val3; anchorRotation = val; return new Blueprint(name, list); } private static Quaternion FacingOf(Quaternion rotation) { //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) //IL_0006: 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) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_001f: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0059: 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_0033: 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_0073: Unknown result type (might be due to invalid IL or missing references) Vector3 val = rotation * Vector3.forward; float degrees; if (Mathf.Sqrt(val.x * val.x + val.z * val.z) >= 0.001f) { degrees = Mathf.Atan2(val.x, val.z) * 57.29578f; } else { Vector3 val2 = rotation * Vector3.right; degrees = Mathf.Atan2(0f - val2.z, val2.x) * 57.29578f; } return GridMath.Yaw(degrees); } public Blueprint Rebased() { //IL_002f: 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) List<WorldPiece> list = new List<WorldPiece>(_items.Count); foreach (BlueprintItem item in _items) { list.Add(new WorldPiece(item.Prefab, item.Position, item.Rotation, item.SignText, item.DoorState)); } return FromWorld(Name, list); } public int[] PlacementOrder() { int[] array = new int[_items.Count]; for (int i = 0; i < array.Length; i++) { array[i] = i; } Array.Sort(array, delegate(int a, int b) { //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_001e: 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_002b: 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_0057: Unknown result type (might be due to invalid IL or missing references) Vector3 position = _items[a].Position; Vector3 position2 = _items[b].Position; int num = position.y.CompareTo(position2.y); if (num == 0) { num = position.x.CompareTo(position2.x); } if (num == 0) { num = position.z.CompareTo(position2.z); } return (num == 0) ? a.CompareTo(b) : num; }); return array; } public Vector3[] OuterSnapPoints(Func<string, PieceBounds> localBounds) { //IL_0022: 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 (localBounds == null) { throw new ArgumentNullException("localBounds"); } Vector3[] array = PooledSnapPoints(localBounds); Dictionary<(long, long, long), List<int>> dictionary = new Dictionary<(long, long, long), List<int>>(); for (int i = 0; i < array.Length; i++) { (long, long, long) key = BucketOf(array[i]); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<int>()); } value.Add(i); } List<Vector3> list2 = new List<Vector3>(); for (int j = 0; j < array.Length; j++) { if (!HasNeighbour(array, dictionary, j)) { list2.Add(array[j]); } } return list2.ToArray(); } private static (long, long, long) BucketOf(Vector3 point) { //IL_0000: 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_0026: Unknown result type (might be due to invalid IL or missing references) return ((long)Math.Floor(point.x / 0.01f), (long)Math.Floor(point.y / 0.01f), (long)Math.Floor(point.z / 0.01f)); } private static bool HasNeighbour(Vector3[] points, Dictionary<(long, long, long), List<int>> buckets, int index) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007e: Unknown result type (might be due to invalid IL or missing references) (long, long, long) tuple = BucketOf(points[index]); long item = tuple.Item1; long item2 = tuple.Item2; long item3 = tuple.Item3; for (long num = -1L; num <= 1; num++) { for (long num2 = -1L; num2 <= 1; num2++) { for (long num3 = -1L; num3 <= 1; num3++) { if (!buckets.TryGetValue((item + num, item2 + num2, item3 + num3), out var value)) { continue; } foreach (int item4 in value) { if (item4 != index) { Vector3 val = points[item4] - points[index]; if (((Vector3)(ref val)).magnitude <= 0.01f) { return true; } } } } } } return false; } public void PoseOf(int index, Vector3 anchorPosition, Quaternion anchorRotation, out Vector3 position, out Quaternion rotation) { //IL_002c: 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_002f: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) if (index < 0 || index >= _items.Count) { throw new ArgumentOutOfRangeException("index"); } BlueprintItem blueprintItem = _items[index]; position = anchorPosition + anchorRotation * blueprintItem.Position; rotation = anchorRotation * blueprintItem.Rotation; } public Dictionary<string, int> PieceCounts(int copies) { if (copies < 1) { throw new ArgumentOutOfRangeException("copies", "A count needs at least one repeat."); } Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (BlueprintItem item in _items) { dictionary.TryGetValue(item.Prefab, out var value); dictionary[item.Prefab] = value + copies; } return dictionary; } public List<string> MissingPieces(Func<string, bool> isAvailable) { if (isAvailable == null) { throw new ArgumentNullException("isAvailable"); } List<string> list = new List<string>(); foreach (BlueprintItem item in _items) { if (!list.Contains(item.Prefab) && !isAvailable(item.Prefab)) { list.Add(item.Prefab); } } return list; } public (Vector3 Min, Vector3 Max) LocalBounds(Func<string, PieceBounds> localBounds) { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_018d: 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_0073: 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_0093: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00de: 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_00f0: 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_010e: 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_0120: 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_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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_0150: 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_0161: Unknown result type (might be due to invalid IL or missing references) if (localBounds == null) { throw new ArgumentNullException("localBounds"); } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(float.MinValue, float.MinValue, float.MinValue); Vector3 val3 = default(Vector3); foreach (BlueprintItem item in _items) { PieceBounds pieceBounds = localBounds(item.Prefab); for (int i = 0; i < 8; i++) { ((Vector3)(ref val3))..ctor(((i & 1) == 0) ? pieceBounds.Min.x : pieceBounds.Max.x, ((i & 2) == 0) ? pieceBounds.Min.y : pieceBounds.Max.y, ((i & 4) == 0) ? pieceBounds.Min.z : pieceBounds.Max.z); Vector3 val4 = item.Position + item.Rotation * val3; val = new Vector3(Mathf.Min(val.x, val4.x), Mathf.Min(val.y, val4.y), Mathf.Min(val.z, val4.z)); val2 = new Vector3(Mathf.Max(val2.x, val4.x), Mathf.Max(val2.y, val4.y), Mathf.Max(val2.z, val4.z)); } } return (Min: val, Max: val2); } public Vector3 Extent(Func<string, PieceBounds> localBounds) { //IL_0008: 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) //IL_0014: Unknown result type (might be due to invalid IL or missing references) (Vector3 Min, Vector3 Max) tuple = LocalBounds(localBounds); var (val, _) = tuple; return tuple.Max - val; } public static string SnapPointLabel(Vector3 point, Vector3 min, Vector3 max, float tolerance = 0.05f) { //IL_0007: 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_0029: 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_0049: 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_006b: 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_008b: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(3); if (Mathf.Abs(point.y - min.y) <= tolerance) { list.Add("bottom"); } else if (Mathf.Abs(point.y - max.y) <= tolerance) { list.Add("top"); } if (Mathf.Abs(point.z - min.z) <= tolerance) { list.Add("front"); } else if (Mathf.Abs(point.z - max.z) <= tolerance) { list.Add("back"); } if (Mathf.Abs(point.x - min.x) <= tolerance) { list.Add("left"); } else if (Mathf.Abs(point.x - max.x) <= tolerance) { list.Add("right"); } if (list.Count <= 0) { return "snappoint"; } return string.Join("-", list); } public Steps FootprintSteps(Func<string, PieceBounds> localBounds) { //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_004e: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00be: 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_00b5: 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) Vector3 val = Extent(localBounds); Vector3[] originPoints = OriginSnapPoints(localBounds); Vector3[] pooledPoints = PooledSnapPoints(localBounds); return new Steps { X = (Vector3)(((??)ProjectedSpan(originPoints, pooledPoints, 0)) ?? new Vector3(val.x, 0f, 0f)), Y = (Vector3)(((??)ProjectedSpan(originPoints, pooledPoints, 1)) ?? new Vector3(0f, val.y, 0f)), Z = (Vector3)(((??)ProjectedSpan(originPoints, pooledPoints, 2)) ?? new Vector3(0f, 0f, val.z)) }; } private static Vector3? ProjectedSpan(Vector3[] originPoints, Vector3[] pooledPoints, int axis) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0040: 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_006d: 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) Vector3? result = Footprint.SnapSpan(originPoints, axis); if (!result.HasValue || pooledPoints.Length == 0) { return result; } Vector3 value = result.Value; Vector3 normalized = ((Vector3)(ref value)).normalized; float num = float.MaxValue; float num2 = float.MinValue; for (int i = 0; i < pooledPoints.Length; i++) { float num3 = Vector3.Dot(pooledPoints[i], normalized); num = Mathf.Min(num, num3); num2 = Mathf.Max(num2, num3); } return normalized * (num2 - num); } private Vector3[] OriginSnapPoints(Func<string, PieceBounds> localBounds) { //IL_004b: 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_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_0062: 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) if (_items.Count == 0) { return Array.Empty<Vector3>(); } BlueprintItem blueprintItem = _items[0]; Vector3[] snapPoints = localBounds(blueprintItem.Prefab).SnapPoints; if (snapPoints == null) { return Array.Empty<Vector3>(); } Vector3[] array = (Vector3[])(object)new Vector3[snapPoints.Length]; for (int i = 0; i < snapPoints.Length; i++) { array[i] = blueprintItem.Position + blueprintItem.Rotation * snapPoints[i]; } return array; } private Vector3[] PooledSnapPoints(Func<string, PieceBounds> localBounds) { //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_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_0053: 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) List<Vector3> list = new List<Vector3>(); foreach (BlueprintItem item in _items) { Vector3[] snapPoints = localBounds(item.Prefab).SnapPoints; if (snapPoints != null) { Vector3[] array = snapPoints; foreach (Vector3 val in array) { list.Add(item.Position + item.Rotation * val); } } } return list.ToArray(); } } internal static class BlueprintFile { public const string Extension = ".blueprint"; private const string Header = "smartbuild-blueprint"; private const int Version = 2; private const int MaxFileNameStem = 100; private static readonly char[] UnsafeFileNameCharacters = new char[9] { '\\', '/', ':', '*', '?', '"', '<', '>', '|' }; private static readonly string[] ReservedNames = new string[22] { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; private static string Number(float value) { return value.ToString("G9", CultureInfo.InvariantCulture); } public static string Serialize(Blueprint blueprint) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("smartbuild-blueprint").Append(' ').Append(2) .Append('\n'); stringBuilder.Append("name ").Append(blueprint.Name).Append('\n'); foreach (BlueprintItem item in blueprint.Items) { stringBuilder.Append("item ").Append(item.Prefab).Append(' ') .Append(Number(item.Position.x)) .Append(' ') .Append(Number(item.Position.y)) .Append(' ') .Append(Number(item.Position.z)) .Append(' ') .Append(Number(item.Rotation.x)) .Append(' ') .Append(Number(item.Rotation.y)) .Append(' ') .Append(Number(item.Rotation.z)) .Append(' ') .Append(Number(item.Rotation.w)) .Append('\n'); if (item.SignText != null) { stringBuilder.Append("sign ").Append(Escape(item.SignText)).Append('\n'); } if (item.DoorState.HasValue) { stringBuilder.Append("door ").Append(item.DoorState.Value.ToString(CultureInfo.InvariantCulture)).Append('\n'); } } return stringBuilder.ToString(); } private static string Escape(string text) { return text.Replace("\\", "\\\\").Replace("\n", "\\n"); } private static string Unescape(string text) { StringBuilder stringBuilder = new StringBuilder(text.Length); for (int i = 0; i < text.Length; i++) { if (text[i] == '\\' && i + 1 < text.Length && (text[i + 1] == '\\' || text[i + 1] == 'n')) { stringBuilder.Append((text[i + 1] == 'n') ? '\n' : '\\'); i++; } else { stringBuilder.Append(text[i]); } } return stringBuilder.ToString(); } public static bool TryParse(string text, string fileName, out Blueprint blueprint, out string error) { blueprint = null; try { if (FirstLine(text).StartsWith("smartbuild-blueprint", StringComparison.Ordinal)) { return Parse(text, out blueprint, out error); } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName ?? ""); if (string.Equals(Path.GetExtension(fileName ?? ""), ".vbuild", StringComparison.OrdinalIgnoreCase)) { return PlanBuildFile.ParseVBuild(text, fileNameWithoutExtension, out blueprint, out error); } return PlanBuildFile.ParseBlueprint(text, fileNameWithoutExtension, out blueprint, out error); } catch (Exception ex) { blueprint = null; error = "Unexpected problem reading the file: " + ex.Message; return false; } } private static string FirstLine(string text) { if (text == null) { return ""; } string[] array = text.Split(new char[1] { '\n' }); foreach (string text2 in array) { if (text2.Trim().Length > 0) { return text2.Trim(); } } return ""; } public static bool TryParse(string text, out Blueprint blueprint, out string error) { blueprint = null; try { return Parse(text, out blueprint, out error); } catch (Exception ex) { blueprint = null; error = "Unexpected problem reading the file: " + ex.Message; return false; } } private static bool Parse(string text, out Blueprint blueprint, out string error) { blueprint = null; if (string.IsNullOrWhiteSpace(text)) { error = "The file is empty."; return false; } string[] array = text.Split(new char[1] { '\n' }); int result = 0; string text2 = null; List<BlueprintItem> list = new List<BlueprintItem>(); bool flag = false; bool flag2 = false; for (int i = 0; i < array.Length; i++) { int num = i + 1; string text3 = array[i].TrimEnd(new char[1] { '\r' }); if (text3.Trim().Length == 0 || text3.TrimStart(Array.Empty<char>()).StartsWith("#", StringComparison.Ordinal)) { continue; } if (result == 0) { string[] array2 = text3.Trim().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 0 || array2[0] != "smartbuild-blueprint") { error = "Line " + num + ": this is not a SmartBuild blueprint file."; return false; } if (array2.Length != 2 || !int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) { error = "Line " + num + ": the file version is missing."; return false; } if (result != 1 && result != 2) { error = "Line " + num + ": file version " + result + " is not supported (this SmartBuild reads versions 1 and " + 2 + ")."; return false; } } else if (text3.StartsWith("name ", StringComparison.Ordinal)) { if (text2 != null) { error = "Line " + num + ": the name is given twice."; return false; } text2 = text3.Substring(5); } else if (text3.StartsWith("item ", StringComparison.Ordinal)) { if (!TryParseItem(text3, out var item)) { error = "Line " + num + ": a piece line needs a name and 7 finite numbers."; return false; } list.Add(item); flag = (flag2 = false); } else if (result >= 2 && (text3 == "sign" || text3.StartsWith("sign ", StringComparison.Ordinal))) { if (list.Count == 0) { error = "Line " + num + ": sign text needs a piece line above it."; return false; } if (flag) { error = "Line " + num + ": this piece already has sign text."; return false; } list[list.Count - 1] = WithExtras(list[list.Count - 1], Unescape((text3.Length > 5) ? text3.Substring(5) : ""), list[list.Count - 1].DoorState); flag = true; } else { if (result < 2 || !text3.StartsWith("door ", StringComparison.Ordinal)) { error = "Line " + num + ": not understood."; return false; } if (list.Count == 0) { error = "Line " + num + ": a door state needs a piece line above it."; return false; } if (flag2) { error = "Line " + num + ": this piece already has a door state."; return false; } if (!int.TryParse(text3.Substring(5).Trim(), NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var result2)) { error = "Line " + num + ": a door state is a whole number."; return false; } list[list.Count - 1] = WithExtras(list[list.Count - 1], list[list.Count - 1].SignText, result2); flag2 = true; } } if (result == 0) { error = "The file has no header."; return false; } if (string.IsNullOrWhiteSpace(text2)) { error = "The file has no name."; return false; } if (list.Count == 0) { error = "The file has no pieces."; return false; } try { blueprint = new Blueprint(text2, list); } catch (ArgumentException ex) { error = ex.Message; return false; } if (result == 1) { blueprint = blueprint.Rebased(); } error = null; return true; } private static BlueprintItem WithExtras(BlueprintItem item, string signText, int? doorState) { //IL_0007: 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) return new BlueprintItem(item.Prefab, item.Position, item.Rotation, signText, doorState); } private static bool TryParseItem(string line, out BlueprintItem item) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) item = null; string[] array = line.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length != 9) { return false; } float[] array2 = new float[7]; for (int i = 0; i < 7; i++) { if (!float.TryParse(array[i + 2], NumberStyles.Float, CultureInfo.InvariantCulture, out array2[i])) { return false; } if (float.IsNaN(array2[i]) || float.IsInfinity(array2[i])) { return false; } } item = new BlueprintItem(array[1], new Vector3(array2[0], array2[1], array2[2]), new Quaternion(array2[3], array2[4], array2[5], array2[6])); return true; } public static string FileNameFor(string name) { string text = name ?? ""; StringBuilder stringBuilder = new StringBuilder(text.Length); string text2 = text; foreach (char c in text2) { stringBuilder.Append((c < ' ' || Array.IndexOf(UnsafeFileNameCharacters, c) >= 0) ? '_' : c); } text = stringBuilder.ToString(); if (text.Length > 100) { text = text.Substring(0, 100); } text = text.Trim().TrimEnd('.', ' '); if (text.Length == 0) { text = "blueprint"; } if (Array.IndexOf(ReservedNames, text.ToUpperInvariant()) >= 0) { text += "_"; } return text + ".blueprint"; } } internal static class BlueprintLibrary { private static BlueprintStore _store; public static readonly List<Blueprint> All = new List<Blueprint>(); public static string Folder { get { if (_store == null) { return ""; } return _store.Directory; } } public static void Load() { _store = new BlueprintStore(Path.Combine(Paths.ConfigPath, "SmartBuild", "Blueprints")); All.Clear(); BlueprintLoadResult blueprintLoadResult = _store.LoadAll(); All.AddRange(blueprintLoadResult.Blueprints); Plugin.Log.LogInfo((object)("Loaded " + All.Count + " blueprint(s) from " + _store.Directory)); foreach (string problem in blueprintLoadResult.Problems) { Plugin.Log.LogWarning((object)("Skipped a blueprint file: " + problem)); } } public static void Save(Blueprint blueprint, Player player) { _store.Save(blueprint); All.RemoveAll((Blueprint existing) => string.Equals(existing.Name, blueprint.Name, StringComparison.OrdinalIgnoreCase)); All.Add(blueprint); All.Sort((Blueprint a, Blueprint b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); BlueprintPieces.Register(blueprint, player); } public static bool Delete(string name) { bool result = _store.Delete(name); All.RemoveAll((Blueprint existing) => string.Equals(existing.Name, name, StringComparison.OrdinalIgnoreCase)); BlueprintPieces.Unregister(name); return result; } } internal static class BlueprintPieces { private const string PiecePrefix = "SmartBuildBP_"; private const string Category = "Blueprints"; private static readonly Dictionary<string, GameObject> StubsByName = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, Blueprint> BlueprintsByPrefabName = new Dictionary<string, Blueprint>(); private static Sprite _blankIcon; public static int Version { get; private set; } public static IEnumerable<GameObject> Stubs { get { foreach (GameObject value in StubsByName.Values) { if ((Object)(object)value != (Object)null) { yield return value; } } } } public static bool TryGetBlueprint(string prefabName, out Blueprint blueprint) { return BlueprintsByPrefabName.TryGetValue(prefabName ?? "", out blueprint); } public static void RegisterAll(IEnumerable<Blueprint> blueprints, Player player) { foreach (Blueprint blueprint in blueprints) { Register(blueprint, player); } } public static void Register(Blueprint blueprint, Player player) { try { if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)SmartHammer.Table == (Object)null) { return; } string text = PrefabNameFor(blueprint.Name); GameObject val = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)val == (Object)null) { val = PrefabManager.Instance.CreateEmptyPrefab(text, false); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Could not add '" + blueprint.Name + "' to the build menu: '" + text + "' could not be created")); return; } } Decorate(val, blueprint.Name, blueprint.Items.Count + ((blueprint.Items.Count == 1) ? " piece" : " pieces"), blueprint, player); PieceManager.Instance.RegisterPieceInPieceTable(val, "SmartHammerPieceTable", "Blueprints"); StubsByName[blueprint.Name] = val; BlueprintsByPrefabName[text] = blueprint; Version++; Plugin.Log.LogInfo((object)("Registered blueprint piece '" + text + "' for '" + blueprint.Name + "' (version " + Version + ", " + StubsByName.Count + " stub(s) known)")); SmartHammer.Sync(); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not add '" + blueprint.Name + "' to the build menu: " + ex)); } } public static void Unregister(string name) { try { if (!StubsByName.TryGetValue(name, out var value)) { return; } StubsByName.Remove(name); if (!((Object)(object)value == (Object)null)) { string name2 = ((Object)value).name; BlueprintsByPrefabName.Remove(name2); if ((Object)(object)SmartHammer.Table != (Object)null) { SmartHammer.Table.m_pieces.Remove(value); } Version++; } } catch (Exception ex) { Plugin.Log.LogError((object)("Could not remove '" + name + "' from the build menu: " + ex)); } } private static void Decorate(GameObject stub, string name, string description, Blueprint blueprint, Player player) { for (int num = stub.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)stub.transform.GetChild(num)).gameObject); } Piece val = stub.GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = stub.AddComponent<Piece>(); } val.m_name = name; val.m_description = description; val.m_icon = IconFor(blueprint); val.m_resources = Array.Empty<Requirement>(); BuildChildren(stub, blueprint); Dictionary<string, PieceBounds> bounds = null; if ((Object)(object)player != (Object)null) { BlueprintPlacer.TryMeasure(player, blueprint, out var _, out bounds, out var _); } BuildAnchorCollider(stub, blueprint, bounds); if (bounds != null) { BuildSnapPoints(stub, blueprint, bounds); } } private static void BuildAnchorCollider(GameObject stub, Blueprint blueprint, Dictionary<string, PieceBounds> bounds) { //IL_0012: 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_0028: Expected O, but got Unknown //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_005e: 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_0064: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_00ae: 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_00b0: 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_00c4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SmartBuildAnchor") { layer = LayerMask.NameToLayer("piece_nonsolid") }; val.transform.SetParent(stub.transform, false); if (bounds != null) { PieceBounds value; (Vector3 Min, Vector3 Max) tuple = blueprint.LocalBounds((string prefab) => (!bounds.TryGetValue(prefab, out value)) ? default(PieceBounds) : value); Vector3 item = tuple.Min; Vector3 item2 = tuple.Max; Vector3 val2 = item2 - item; ((Vector3)(ref val2))..ctor(Mathf.Max(val2.x, 0.1f), Mathf.Max(val2.y, 0.1f), Mathf.Max(val2.z, 0.1f)); BoxCollider obj = val.AddComponent<BoxCollider>(); obj.center = (item + item2) * 0.5f; obj.size = val2; } else { val.AddComponent<SphereCollider>().radius = 0.05f; } } private static void BuildChildren(GameObject stub, Blueprint blueprint) { bool forceDisableInit = ZNetView.m_forceDisableInit; bool forceDisableTerrainOps = TerrainOp.m_forceDisableTerrainOps; ZNetView.m_forceDisableInit = true; TerrainOp.m_forceDisableTerrainOps = true; try { BuildChildrenCore(stub, blueprint); } finally { ZNetView.m_forceDisableInit = forceDisableInit; TerrainOp.m_forceDisableTerrainOps = forceDisableTerrainOps; } } private static void BuildChildrenCore(GameObject stub, Blueprint blueprint) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) foreach (BlueprintItem item in blueprint.Items) { GameObject prefab = ZNetScene.instance.GetPrefab(item.Prefab); if (!((Object)(object)prefab == (Object)null)) { GameObject obj = Object.Instantiate<GameObject>(prefab, stub.transform); obj.transform.localPosition = item.Position; obj.transform.localRotation = item.Rotation; StripToVisual(obj); } } } private static void BuildSnapPoints(GameObject stub, Blueprint blueprint, Dictionary<string, PieceBounds> bounds) { //IL_0020: 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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0041: 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_0045: 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_0051: 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_0061: 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_0088: Unknown result type (might be due to invalid IL or missing references) PieceBounds value; Func<string, PieceBounds> localBounds = (string prefab) => (!bounds.TryGetValue(prefab, out value)) ? default(PieceBounds) : value; (Vector3 Min, Vector3 Max) tuple = blueprint.LocalBounds(localBounds); Vector3 item = tuple.Min; Vector3 item2 = tuple.Max; Vector3[] array = blueprint.OuterSnapPoints(localBounds); foreach (Vector3 val in array) { GameObject val2 = new GameObject(Blueprint.SnapPointLabel(val, item, item2)) { tag = "snappoint", layer = LayerMask.NameToLayer("piece") }; val2.transform.SetParent(stub.transform, false); val2.transform.localPosition = val; } } private static void StripToVisual(GameObject clone) { MonoBehaviour[] componentsInChildren = clone.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } } Collider[] componentsInChildren2 = clone.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } } private static Sprite IconFor(Blueprint blueprint) { foreach (string item in blueprint.PrefabsByUsage()) { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(item) : null); Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.m_icon != (Object)null) { return val2.m_icon; } } return BlankIcon(); } private static Sprite BlankIcon() { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown if ((Object)(object)_blankIcon != (Object)null) { return _blankIcon; } Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, Color.clear); val.Apply(); _blankIcon = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f)); return _blankIcon; } private static string PrefabNameFor(string blueprintName) { StringBuilder stringBuilder = new StringBuilder("SmartBuildBP_".Length + blueprintName.Length); stringBuilder.Append("SmartBuildBP_"); foreach (char c in blueprintName) { stringBuilder.Append(char.IsLetterOrDigit(c) ? c : '_'); } return stringBuilder.ToString(); } } internal static class BlueprintPlacer { private const int ValidatePerFrame = 50; public static Blueprint Active { get; private set; } public static void Arm(Blueprint blueprint) { Active = blueprint; } public static void Disarm() { Active = null; } public static bool TryMeasure(Player player, Blueprint blueprint, out Dictionary<string, Piece> pieces, out Dictionary<string, PieceBounds> bounds, out string missing) { //IL_00c7: 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) pieces = new Dictionary<string, Piece>(); bounds = new Dictionary<string, PieceBounds>(); missing = null; foreach (BlueprintItem item in blueprint.Items) { if (!pieces.ContainsKey(item.Prefab)) { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(item.Prefab) : null); Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null); if ((Object)(object)val2 == (Object)null) { missing = item.Prefab; return false; } pieces[item.Prefab] = val2; GameObject val3 = GameApi.CloneGhost(val, player); try { Footprint footprint = Footprint.Measure(val3); bounds[item.Prefab] = new PieceBounds(new Vector3(footprint.MinX, footprint.MinY, footprint.MinZ), new Vector3(footprint.MaxX, footprint.MaxY, footprint.MaxZ), footprint.Snaps); } finally { Object.Destroy((Object)(object)val3); } } } return true; } public static GridLayout RepeatsFor(Blueprint blueprint, Dictionary<string, PieceBounds> bounds) { //IL_0028: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) PieceBounds value; Func<string, PieceBounds> localBounds = (string prefab) => (!bounds.TryGetValue(prefab, out value)) ? default(PieceBounds) : value; Steps steps = blueprint.FootprintSteps(localBounds); var (val, val2) = blueprint.LocalBounds(localBounds); return GridState.LayoutFor(new Footprint { SpanX = steps.X, SpanY = steps.Y, SpanZ = steps.Z, MinX = val.x, MaxX = val2.x, MinZ = val.z, MaxZ = val2.z }); } public static Quaternion AnchorRotation(GameObject ghost) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0022: Unknown result type (might be due to invalid IL or missing references) Quaternion rotation = ghost.transform.rotation; return Quaternion.Euler(0f, ((Quaternion)(ref rotation)).eulerAngles.y, 0f); } public static bool Begin(Player player, GameObject ghost) { //IL_0020: 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) //IL_0027: 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_0034: 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) Blueprint active = Active; if (active == null) { return false; } if (!PlacementHistory.TryStart(player, "Still placing the previous blueprint")) { return true; } Vector3 position = ghost.transform.position; Quaternion rot = AnchorRotation(ghost); ((MonoBehaviour)Plugin.Instance).StartCoroutine(Guard(Run(player, active, position, rot, GridState.FollowTerrain), player)); return true; } private static IEnumerator Guard(IEnumerator inner, Player player) { try { while (true) { bool flag; try { flag = inner.MoveNext(); } catch (Exception ex) { Plugin.LogOnce("blueprint-place", "Blueprint placement failed: " + ex); GameApi.Message(player, "Blueprint placement failed, see the BepInEx log"); flag = false; } if (flag) { yield return inner.Current; continue; } break; } } finally { PlacementHistory.Finish(); } } private static IEnumerator Run(Player player, Blueprint blueprint, Vector3 anchor, Quaternion rot, bool followTerrain) { //IL_0015: 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_001c: 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) if (!TryMeasure(player, blueprint, out var pieces, out var bounds, out var missing)) { GameApi.Message(player, "Missing piece: " + missing + " (this blueprint needs a mod that isn't loaded)"); yield break; } Dictionary<string, GameObject> probes = new Dictionary<string, GameObject>(); try { foreach (string key in pieces.Keys) { GameObject val = GameApi.CloneGhost(ZNetScene.instance.GetPrefab(key), player); ((Object)val).name = "SmartBuildBlueprintProbe"; val.SetActive(true); probes[key] = val; } GridLayout repeats = RepeatsFor(blueprint, bounds); int copies = repeats.Count; int itemsPerCopy = blueprint.Items.Count; int total = copies * itemsPerCopy; Dictionary<string, int> perCopyCounts = blueprint.PieceCounts(1); int[] order = blueprint.PlacementOrder(); float? anchorGround = (followTerrain ? GameApi.GroundHeight(anchor) : ((float?)null)); int blocked = 0; int checkedCount = 0; for (int r = 0; r < copies; r++) { repeats.Pose(anchor, rot, r, out var copyPos, out var copyRot); float shift = (anchorGround.HasValue ? GameApi.TerrainShift(anchorGround.Value, copyPos) : 0f); for (int oi = 0; oi < itemsPerCopy; oi++) { int index = order[oi]; string prefab = blueprint.Items[index].Prefab; blueprint.PoseOf(index, copyPos, copyRot, out var position, out var rotation); position.y += shift; GameObject val2 = probes[prefab]; val2.transform.SetPositionAndRotation(position, rotation); Physics.SyncTransforms(); if (!CellValidator.IsValid(player, pieces[prefab], val2, position)) { blocked++; } checkedCount++; if (checkedCount % 50 == 49) { yield return null; } if ((Object)(object)player == (Object)null) { yield break; } } copyPos = default(Vector3); copyRot = default(Quaternion); } if (blocked > 0) { GameApi.Message(player, "Blocked: " + blocked + " of " + total + " pieces can't be placed here"); yield break; } foreach (KeyValuePair<string, int> item in blueprint.PieceCounts(copies)) { if (!GridCost.CanAfford(player, pieces[item.Key], item.Value)) { GameApi.Message(player, GridCost.Shortage(player, pieces[item.Key], item.Value)); yield break; } } GridState.Reset(); PlacementHistory.BeginCapture(DateTime.UtcNow.Ticks); bool cheated = player.NoCostCheat(); bool anyCharged = false; string stopped = null; int placedSinceYield = 0; int perFrame = ModConfig.PlacePerFrame.Value; for (int r = 0; r < copies; r++) { if (stopped != null) { break; } if ((Object)(object)player == (Object)null || GameApi.IsDead(player)) { stopped = "Stopped after " + PlacementHistory.Captured.Count + " pieces"; break; } repeats.Pose(anchor, rot, r, out var position2, out var cellRotation); foreach (KeyValuePair<string, int> item2 in perCopyCounts) { if (!GridCost.CanAfford(player, pieces[item2.Key], item2.Value)) { stopped = "Stopped after " + PlacementHistory.Captured.Count + " pieces: " + GridCost.Shortage(player, pieces[item2.Key], item2.Value); break; } } if (stopped != null) { break; } foreach (KeyValuePair<string, int> item3 in perCopyCounts) { if (!GameApi.IsFree(player, pieces[item3.Key])) { GameApi.ConsumeResources(player, pieces[item3.Key], item3.Value); anyCharged = true; } } float num = (anchorGround.HasValue ? GameApi.TerrainShift(anchorGround.Value, position2) : 0f); PlacementHistory.EnterCaptureWindow(); try { for (int i = 0; i < itemsPerCopy; i++) { int index2 = order[i]; string prefab2 = blueprint.Items[index2].Prefab; blueprint.PoseOf(index2, position2, cellRotation, out var position3, out var rotation2); position3.y += num; GameApi.PlacePiece(player, pieces[prefab2], position3, rotation2, r == 0 && i == 0, cheated); placedSinceYield++; } } finally { PlacementHistory.ExitCaptureWindow(); } if (placedSinceYield >= perFrame) { placedSinceYield = 0; yield return null; } } int count = PlacementHistory.Captured.Count; PlacementHistory.EndCapture(anyCharged); GameApi.Message(player, stopped ?? ("Placed " + copies + "x '" + blueprint.Name + "' (" + count + " pieces) - still armed, click to place another")); } finally { foreach (GameObject value in probes.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } } } } internal class BlueprintSavePrompt : TextReceiver { private static readonly BlueprintSavePrompt Instance = new BlueprintSavePrompt(); private static string _lastText = ""; public static void Show(Player player) { if ((Object)(object)TextInput.instance == (Object)null) { GameApi.Message(player, "Could not open the naming prompt, see the BepInEx log"); Plugin.Log.LogError((object)"Could not save a blueprint: TextInput.instance is null"); return; } Safe.Run(delegate { GUI.FocusControl((string)null); }, "GUI.FocusControl"); TextInput.instance.RequestText((TextReceiver)(object)Instance, "Name this blueprint", 40); } public string GetText() { return _lastText; } public void SetText(string text) { _lastText = text; string text2 = BlueprintSession.Save(Player.m_localPlayer, text); GameApi.Message(Player.m_localPlayer, text2); if (text2.StartsWith("Saved", StringComparison.Ordinal)) { _lastText = ""; } } } internal sealed class BlueprintSelection<TKey> { private readonly List<TKey> _keys = new List<TKey>(); private readonly List<WorldPiece> _pieces = new List<WorldPiece>(); public int Count => _keys.Count; public IReadOnlyList<WorldPiece> Pieces => _pieces; public IReadOnlyList<TKey> Keys => _keys; public bool Contains(TKey key) { return IndexOf(key) >= 0; } private int IndexOf(TKey key) { return _keys.FindIndex((TKey existing) => EqualityComparer<TKey>.Default.Equals(existing, key)); } public bool Toggle(TKey key, WorldPiece piece) { int num = IndexOf(key); if (num >= 0) { _keys.RemoveAt(num); _pieces.RemoveAt(num); return false; } _keys.Add(key); _pieces.Add(piece); return true; } public bool Add(TKey key, WorldPiece piece) { if (Contains(key)) { return false; } _keys.Add(key); _pieces.Add(piece); return true; } public bool Remove(TKey key) { int num = IndexOf(key); if (num < 0) { return false; } _keys.RemoveAt(num); _pieces.RemoveAt(num); return true; } public void ToggleGroup(IList<KeyValuePair<TKey, WorldPiece>> group) { if (group == null || group.Count == 0) { return; } bool flag = true; foreach (KeyValuePair<TKey, WorldPiece> item in group) { if (!Contains(item.Key)) { flag = false; break; } } foreach (KeyValuePair<TKey, WorldPiece> item2 in group) { bool flag2 = Contains(item2.Key); if (flag) { Toggle(item2.Key, item2.Value); } else if (!flag2) { Toggle(item2.Key, item2.Value); } } } public void Clear() { _keys.Clear(); _pieces.Clear(); } public Blueprint ToBlueprint(string name) { if (_pieces.Count == 0) { throw new InvalidOperationException("Select at least one piece first."); } return Blueprint.FromWorld(name, _pieces); } } internal static class BlueprintSession { private static readonly Color OriginColor = new Color(1f, 0.85f, 0.2f); private static readonly Color SelectedColor = new Color(0.25f, 0.9f, 1f); private static readonly BlueprintSelection<int> Selection = new BlueprintSelection<int>(); private static readonly Dictionary<int, Piece> Live = new Dictionary<int, Piece>(); private static bool _lit; private static bool _growing; private static bool _sweeping; private static bool _sweepAdding; private static bool _sweepPressedPiece; private static int _sweepLastId; private static int _sweepChanged; private const int GrowPerFrame = 40; private const float TouchMargin = 0.01f; public static int Count => Selection.Count; public static bool Sweeping => _sweeping; public static bool IsSelected(Piece piece) { if ((Object)(object)piece != (Object)null) { return Selection.Contains(((Object)piece).GetInstanceID()); } return false; } public static List<Piece> SelectedPieces() { List<Piece> list = new List<Piece>(Live.Count); foreach (Piece value in Live.Values) { if ((Object)(object)value != (Object)null) { list.Add(value); } } return list; } public static void OnSelectKey(Player player, bool wholeGroup) { try { Select(player, wholeGroup); } catch (Exception ex) { Plugin.LogOnce("blueprint-select", "Selecting a piece failed: " + ex); } } private static void Select(Player player, bool wholeGroup) { //IL_014e: Unknown result type (might be due to invalid IL or missing references) if (BlueprintPlacer.Active != null) { BlueprintPlacer.Disarm(); } Piece aimed = GameApi.AimedPiece(player, ModConfig.SelectReach.Value); if ((Object)(object)aimed == (Object)null) { StartSweep(adding: true, 0, pressed: false); return; } if (!TryCapture(player, aimed, out var captured, out var reason)) { GameApi.Message(player, reason); StartSweep(adding: true, ((Object)aimed).GetInstanceID(), pressed: true); return; } int instanceID = ((Object)aimed).GetInstanceID(); if (!wholeGroup) { bool flag = Selection.Toggle(instanceID, captured); Track(instanceID, aimed, flag); GameApi.Message(player, (flag ? "Added " : "Removed ") + GameApi.Localize(aimed.m_name) + " (" + Selection.Count + " selected)"); StartSweep(flag, instanceID, pressed: true); return; } List<KeyValuePair<int, WorldPiece>> list = new List<KeyValuePair<int, WorldPiece>> { new KeyValuePair<int, WorldPiece>(instanceID, captured) }; Dictionary<int, Piece> dictionary = new Dictionary<int, Piece> { { instanceID, aimed } }; long num = GroupTag.Read(aimed); if (num != 0L) { List<Piece> list2 = new List<Piece>(); Piece.GetAllPiecesInRadius(((Component)aimed).transform.position, 100000f, list2); list2.Sort(delegate(Piece a, Piece b) { //IL_0006: 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_001b: 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_0031: 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) Vector3 val = ((Component)a).transform.position - ((Component)aimed).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - ((Component)aimed).transform.position; return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude); }); foreach (Piece item in list2) { int instanceID2 = ((Object)item).GetInstanceID(); if (instanceID2 != instanceID && GroupTag.Read(item) == num && TryCapture(player, item, out var captured2, out var _)) { list.Add(new KeyValuePair<int, WorldPiece>(instanceID2, captured2)); dictionary[instanceID2] = item; } } } Selection.ToggleGroup(list); foreach (KeyValuePair<int, WorldPiece> item2 in list) { Track(item2.Key, dictionary[item2.Key], Selection.Contains(item2.Key)); } GameApi.Message(player, list.Count + ((list.Count == 1) ? " piece" : " pieces") + " in the group, " + Selection.Count + " selected"); StartSweep(Selection.Contains(instanceID), instanceID, pressed: true); } private static void StartSweep(bool adding, int startId, bool pressed) { _sweeping = true; _sweepAdding = adding; _sweepPressedPiece = pressed; _sweepLastId = startId; _sweepChanged = 0; } public static void SweepStep(Player player) { if (!_sweeping || (Object)(object)player == (Object)null) { return; } try { Piece val = GameApi.AimedPiece(player, ModConfig.SelectReach.Value); if ((Object)(object)val == (Object)null) { return; } int instanceID = ((Object)val).GetInstanceID(); if (instanceID == _sweepLastId) { return; } _sweepLastId = instanceID; if (_sweepAdding) { if (!Selection.Contains(instanceID) && TryCapture(player, val, out var captured, out var _) && Selection.Add(instanceID, captured)) { Track(instanceID, val, selected: true); _sweepChanged++; } } else if (Selection.Remove(instanceID)) { Track(instanceID, val, selected: false); _sweepChanged++; } } catch (Exception ex) { Plugin.LogOnce("blueprint-sweep", "Sweep-selecting failed: " + ex); } } public static void EndSweep(Player player) { if (_sweeping) { _sweeping = false; if (_sweepChanged > 0) { GameApi.Message(player, (_sweepAdding ? "Swept in " : "Swept out ") + _sweepChanged + ((_sweepChanged == 1) ? " piece" : " pieces") + " (" + Selection.Count + " selected)"); } else if (!_sweepPressedPiece) { GameApi.Message(player, "Aim at a built piece first"); } } } public static void OnGrowKey(Player player) { try { StartGrow(player); } catch (Exception ex) { Plugin.LogOnce("blueprint-grow", "Growing the selection failed: " + ex); } } private static void StartGrow(Player player) { if (_growing) { GameApi.Message(player, "Still growing the selection"); return; } Piece val = GameApi.AimedPiece(player, ModConfig.SelectReach.Value); if ((Object)(object)val == (Object)null) { GameApi.Message(player, "Aim at a built piece first"); return; } if (!TryCapture(player, val, out var _, out var reason)) { GameApi.Message(player, reason); return; } bool adding = !Selection.Contains(((Object)val).GetInstanceID()); ((MonoBehaviour)Plugin.Instance).StartCoroutine(Grow(player, val, adding)); } private static IEnumerator Grow(Player player, Piece start, bool adding) { _growing = true; int changed = 0; try { HashSet<int> visited = new HashSet<int> { ((Object)start).GetInstanceID() }; Queue<Piece> frontier = new Queue<Piece>(); frontier.Enqueue(start); int sinceYield = 0; while (frontier.Count > 0) { Piece val = frontier.Dequeue(); if ((Object)(object)val == (Object)null) { continue; } if (TryCapture(player, val, out var captured, out var _)) { int instanceID = ((Object)val).GetInstanceID(); bool flag = Selection.Contains(instanceID); if (adding && !flag) { Selection.Toggle(instanceID, captured); Track(instanceID, val, selected: true); changed++; } else if (!adding && flag) { Selection.Toggle(instanceID, captured); Track(instanceID, val, selected: false); changed++; } Bounds sourceBounds = ColliderBounds(val); if (((Bounds)(ref sourceBounds)).size != Vector3.zero) { List<Piece> list = new List<Piece>(); Vector3 position = ((Component)val).transform.position; Vector3 extents = ((Bounds)(ref sourceBounds)).extents; Piece.GetAllPiecesInRadius(position, ((Vector3)(ref extents)).magnitude + 8f, list); foreach (Piece item in list) { if (!((Object)(object)item == (Object)null)) { int instanceID2 = ((Object)item).GetInstanceID(); if (!visited.Contains(instanceID2) && Touches(sourceBounds, item)) { visited.Add(instanceID2); frontier.Enqueue(item); } } } } } if ((Object)(object)player == (Object)null) { break; } int num = sinceYield + 1; sinceYield = num; if (num >= 40) { sinceYield = 0; yield return null; } } } finally { _growing = false; } if ((Object)(object)player != (Object)null) { GameApi.Message(player, changed + ((changed == 1) ? " piece " : " pieces ") + (adding ? "added" : "removed") + " (" + Selection.Count + " selected)"); } } private static Bounds ColliderBounds(Piece piece) { //IL_0002: 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_0036: 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_002d: Unknown result type (might be due to invalid IL or missing references) Bounds result = default(Bounds); bool flag = false; Collider[] componentsInChildren = ((Component)piece).GetComponentsInChildren<Collider>(); foreach (Collider val in componentsInChildren) { if (!val.isTrigger) { if (!flag) { result = val.bounds; flag = true; } else { ((Bounds)(ref result)).Encapsulate(val.bounds); } } } return result; } private static bool Touches(Bounds sourceBounds, Piece candidate) { //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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Bounds val = sourceBounds; ((Bounds)(ref val)).Expand(0.02f); Collider[] componentsInChildren = ((Component)candidate).GetComponentsInChildren<Collider>(); foreach (Collider val2 in componentsInChildren) { if (!val2.isTrigger && ((Bounds)(ref val)).Intersects(val2.bounds)) { return true; } } return false; } private static bool TryCapture(Player player, Piece piece, out WorldPiece captured, out string reason) { //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) captured = default(WorldPiece); if ((Object)(object)((Component)piece).GetComponent<PrivateArea>() != (Object)null) { reason = "Wards can't go in a blueprint"; return false; } if ((Object)(object)((Component)piece).GetComponent<TeleportWorld>() != (Object)null) { reason = "Portals can't go in a blueprint"; return false; } string prefabName = Utils.GetPrefabName(((Component)piece).gameObject); GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabName) : null); Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("Can't capture '" + ((Object)((Component)piece).gameObject).name + "' for a blueprint: prefab name '" + prefabName + "', ZNetScene.GetPrefab found " + ((Object)(object)val != (Object)null) + ", it has a Piece " + ((Object)(object)val2 != (Object)null))); reason = "That piece can't be copied"; return false; } if (!player.IsPieceAvailable(val2)) { reason = "You haven't unlocked that piece yet"; return false; } captured = new WorldPiece(prefabName, ((Component)piece).transform.position, ((Component)piece).transform.rotation); reason = null; return true; } private static void Track(int id, Piece piece, bool selected) { if (selected) { Live[id] = piece; return; } Live.Remove(id); ResetLook(piece); } public static void Highlight() { //IL_009e: 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_00a3: 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_00be: 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) if (Live.Count == 0) { return; } try { MaterialMan instance = MaterialMan.instance; if ((Object)(object)instance == (Object)null) { return; } _lit = true; List<int> list = null; int num = ((Selection.Count > 0) ? Selection.Keys[0] : 0); foreach (KeyValuePair<int, Piece> item in Live) { if ((Object)(object)item.Value == (Object)null) { (list ?? (list = new List<int>())).Add(item.Key); continue; } Color val = ((item.Key == num) ? OriginColor : SelectedColor); instance.SetValue<Color>(((Component)item.Value).gameObject, ShaderProps._EmissionColor, val * 0.5f, false); instance.SetValue<Color>(((Component)item.Value).gameObject, ShaderProps._Color, val, false); } if (list == null) { return; } foreach (int item2 in list) { Live.Remove(item2); Selection.Toggle(item2, default(WorldPiece)); } } catch (Exception ex) { Plugin.LogOnce("blueprint-highlight", "Highlighting the selection failed: " + ex); } } public static void ClearHighlight() { if (!_lit) { return; } _lit = false; foreach (Piece value in Live.Values) { ResetLook(value); } } private static void ResetLook(Piece piece) { if ((Object)(object)piece == (Object)null) { return; } Safe.Run(delegate { MaterialMan instance = MaterialMan.instance; if (!((Object)(object)instance == (Object)null)) { instance.ResetValue(((Component)piece).gameObject, ShaderProps._Color); instance.ResetValue(((Component)piece).gameObject, ShaderProps._EmissionColor); } }, "MaterialMan.ResetValue"); } public static void Clear() { _sweeping = false; ClearHighlight(); Live.Clear(); Selection.Clear(); } public static string Save(Player player, string name) { if (Selection.Count == 0) { return "Select at least one piece first (aim at it and press F)"; } if (string.IsNullOrWhiteSpace(name)) { return "Give the blueprint a name first"; } try { Blueprint blueprint = Selection.ToBlueprint(name.Trim()); BlueprintLibrary.Save(blueprint, player); Clear(); return "Saved blueprint '" + blueprint.Name + "' (" + blueprint.Items.Count + ((blueprint.Items.Count == 1) ? " piece)" : " pieces)"); } catch (ArgumentException ex) { return ex.Message; } catch (Exception ex2) { Plugin.LogOnce("blueprint-save", "Saving the blueprint failed: " + ex2); return "Could not save the blueprint, see the BepInEx log"; } } public static void OnDeleteKey(Player player) { try { GameObject placementGhost = player.m_placementGhost; if ((Object)(object)placementGhost == (Object)null || !BlueprintPieces.TryGetBlueprint(((Object)placementGhost).name, out var blueprint)) { GameApi.Message(player, "Select a saved blueprint in the build menu first"); return; } BlueprintLibrary.Delete(blueprint.Name); BlueprintPlacer.Disarm(); GameApi.Message(player, "Deleted blueprint '" + blueprint.Name + "'"); } catch (Exception ex) { Plugin.LogOnce("blueprint-delete", "Deleting the blueprint failed: " + ex); } } } internal sealed class BlueprintLoadResult { public readonly List<Blueprint> Blueprints = new List<Blueprint>(); public readonly List<string> Problems = new List<string>(); } internal sealed class BlueprintStore { private static readonly Encoding Utf8WithoutBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); private readonly Dictionary<string, string> _files = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public string Directory { get; } public BlueprintStore(string directory) { Directory = directory; } private string PathFor(string name) { if (!_files.TryGetValue(name, out var value)) { return Path.Combine(Directory, BlueprintFile.FileNameFor(name)); } return value; } public string Save(Blueprint blueprint) { System.IO.Directory.CreateDirectory(Directory); string text = PathFor(blueprint.Name); File.WriteAllText(text, BlueprintFile.Serialize(blueprint), Utf8WithoutBom); _files[blueprint.Name] = text; return text; } public BlueprintLoadResult LoadAll() { BlueprintLoadResult blueprintLoadResult = new BlueprintLoadResult(); _files.Clear(); if (!System.IO.Directory.Exists(Directory)) { return blueprintLoadResult; } List<string> list = new List<string>(); string[] files = System.IO.Directory.GetFiles(Directory); foreach (string text in files) { if (text.EndsWith(".blueprint", StringComparison.OrdinalIgnoreCase) || text.EndsWith(".vbuild", StringComparison.OrdinalIgnoreCase)) { list.Add(text); } } list.Sort((string a, string b) => string.Compare(Path.GetFileName(a), Path.GetFileName(b), StringComparison.OrdinalIgnoreCase)); foreach (string item in list) { string fileName = Path.GetFileName(item); string text2; try { text2 = File.ReadAllText(item, Encoding.UTF8); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { blueprintLoadResult.Problems.Add(fileName + ": could not be read (" + ex.Message + ")"); continue; } if (BlueprintFile.TryParse(text2, fileName, out var blueprint, out var error)) { blueprintLoadResult.Blueprints.Add(blueprint); _files[blueprint.Name] = item; } else { blueprintLoadResult.Problems.Add(fileName + ": " + error); } } return blueprintLoadResult; } public bool Delete(string name) { string path = PathFor(name); _files.Remove(name); if (!File.Exists(path)) { return false; } File.Delete(path); return true; } } internal static class CellValidator { public static bool IsValid(Player player, Piece piece, GameObject cellGhost, Vector3 pos) { //IL_0013: 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_0028: Unknown result type (might be due to invalid IL or missing references) if (piece.m_noClipping && GameApi.IsClipping(player, cellGhost)) { return false; } if (!GameApi.HasWardAccess(pos)) { return false; } if (GameApi.InNoBuildZone(pos)) { return false; } if (GameApi.WrongBiome(piece, pos)) { return false; } return true; } } internal static class ControlPanel { private delegate void AxisSetter(int axis, float value); private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture; private const float PanelWidth = 460f; private const float LegendWidth = 460f; private const float LegendKeyWidth = 180f; private const float Pad = 16f; private const float RowHeight = 28f; private const float RowGap = 6f; private const float LabelWidth = 118f; private const float SmallButton = 28f; private const float FieldWidth = 64f; private static GameObject _window; private static RectTransform _windowRect; private static readonly List<InputField> _fields = new List<InputField>(); private static InputField _sizeX; private static InputField _sizeY; private static InputField _sizeZ; private static InputField _gapX; private static InputField _gapY; private static InputField _gapZ; private static InputField _staggerX; private static InputField _staggerY; private static InputField _staggerZ; private static InputField _rotationField; private static InputField _rotationZField; private static Toggle _terrainToggle; private static Toggle _hudToggle; private static Text _blueprintStatus; private static Text _cellCount; private static Text _holdLabel; private static readonly Color DividerColor = new Color(1f, 1f, 1f, 0.14f); public static bool IsOpen { get { if ((Object)(object)_window != (Object)null) { return _window.activeSelf; } return false; } } public static bool Typing { get { foreach (InputField field in _fields) { if ((Object)(object)field != (Object)null && field.isFocused) { return true; } } return false; } } public static bool CapturingInput { get { if (!Typing) { return CursorOverPanel(); } return true; } } public static bool CursorOverPanel() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (IsOpen && (Object)(object)_windowRect != (Object)null) { return RectTransformUtility.RectangleContainsScreenPoint(_windowRect, Vector2.op_Implicit(Input.mousePosition), (Camera)null); } return false; } public static void Init() { GUIManager.OnCustomGUIAvailable += Build; } public static void Toggle() { Build(); if (!((Object)(object)_window == (Object)null)) { bool flag = !_window.activeSelf; _window.SetActive(flag); if (flag) { Refresh(); } } } public static void Close() { if ((Object)(object)_window != (Object)null) { _window.SetActive(false); } } public static void Refresh() { if (!IsOpen) { return; } try { RefreshLive(); } catch (Exception ex) { Plugin.LogOnce("panel-refresh", "Updating the control panel failed: " + ex); } } private static void RefreshLive() { //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) SyncField(_sizeX, GridState.Cols.ToString(Invariant)); SyncField(_sizeY, GridState.Layers.ToString(Invariant)); SyncField(_sizeZ, GridState.Rows.ToString(Invariant)); SyncField(_gapX, Format(GridState.GapX)); SyncField(_gapY, Format(GridState.GapY)); SyncField(_gapZ, Format(GridState.GapZ)); SyncField(_staggerX, Format(GridState.StaggerX)); SyncField(_staggerY, Format(GridState.StaggerY)); SyncField(_staggerZ, Format(GridState.StaggerZ)); SyncField(_rotationField, Format(GridState.Rotation)); SyncField(_rotationZField, Format(GridState.RotationZ)); if ((Object)(object)_terrainToggle != (Object)null) { _terrainToggle.SetIsOnWithoutNotify(GridState.FollowTerrain); } if ((Object)(object)_hudToggle != (Object)null) { _hudToggle.SetIsOnWithoutNotify(ModConfig.ShowHud.Value); } if ((Object)(object)_blueprintStatus != (Object)null) { _blueprintStatus.text = ((BlueprintSession.Count == 0) ? ("Aim at built pieces and press " + GridPreview.KeyName(ModConfig.KeyBlueprintSelect.Value) + " to select them (" + GridPreview.KeyName(ModConfig.BigStepModifier.Value) + " + " + GridPreview.KeyName(ModConfig.KeyBlueprintSelect.Value) + ": the whole group).") : (BlueprintSession.Count + ((BlueprintSession.Count == 1) ? " piece selected. The gold one is the origin." : " pieces selected. The gold one is the origin."))); } if ((Object)(object)_cellCount != (Object)null) { _cellCount.text = GridState.Cells + ((GridState.Cells == 1) ? " piece" : " pieces"); } if ((Object)(object)_holdLabel != (Object)null) { _holdLabel.text = (GridHold.Frozen ? "Release hold" : "Hold"); } } private static void SyncField(InputField field, string value) { if (!((Object)(object)field == (Object)null) && !field.isFocused && !(field.text == value)) { field.SetTextWithoutNotify(value); } } private static string Format(float value) { return value.ToString("0.###", Invariant); } private static bool TryParse(string text, out float value) { return float.TryParse(text.Replace(',', '.'), NumberStyles.Float, Invariant, out value); } private static void Build() { if ((Object)(object)_window != (Object)null) { return; } try { BuildWindow(); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not build the SmartBuild panel: " + ex)); } } private static void BuildWindow() { //IL_0025: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_05c5: Unknown result type (might be due to invalid IL or missing references) _fields.Clear(); GUIManager instance = GUIManager.Instance; Transform transform = GUIManager.CustomGUIFront.transform; _window = instance.CreateWoodpanel(transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 920f, 400f); ((Object)_window).name = "SmartBuildPanel"; _windowRect = (RectTransform)_window.transform; _window.SetActive(false); float y = -16f; AddTitle(ref y, "SmartBuild"); float top = y; AddHeader(ref y, "Size (negative grows the other way, 1 = one piece)"); _sizeX = AddSizeRow(ref y, "Width (X)", 0); _sizeY = AddSizeRow(ref y, "Height (Y)", 1); _sizeZ = AddSizeRow(ref y, "Depth (Z)", 2); AddHeader(ref y, "Gap (m)"); InputField[] array = AddAxisRow(ref y); _gapX = array[0]; _gapY = array[1]; _gapZ = array[2]; WireAxisFields(array, GridState.SetGap); AddHeader(ref y, "Stagger (m, accumulates)"); InputField[] array2 = AddAxisRow(ref y); _staggerX = array2[0]; _staggerY = array2[1]; _staggerZ = array2[2]; WireAxisFields(array2, GridState.SetStagger); AddNote(ref y, "X: each row sideways Y: each layer sideways Z: each column forward/back"); AddHeader(ref y, "Rotation (degrees added per piece)"); _rotationField = AddLabeledPlusMinusRow(ref y, "Along a row", delegate { GridState.AdjustRotation(0f - ModConfig.RotationStep.Value); }, delegate { GridState.AdjustRotation(ModConfig.RotationStep.Value); }, delegate(string text) { if (TryParse(text, out var value)) { GridState.SetRotation(value); } }); _rotationZField = AddLabeledPlusMinusRow(ref y, "Per row (spiral)", delegate { GridState.AdjustRotationZ(0f - ModConfig.RotationStep.Value); }, delegate { GridState.AdjustRotationZ(ModConfig.RotationStep.Value); }, delegate(string text) { if (TryParse(text, out var value)) { GridState.SetRotationZ(value); } }); _terrainToggle = AddToggle(ref y, "Follow terrain (pieces rise and fall with the ground)", delegate(bool v) { GridState.SetFollowTerrain(v); }); _hudToggle = AddToggle(ref y, "Show HUD (readout and controls legend)", delegate(bool v) { ModConfig.ShowHud.Value = v; }); AddHeader(ref y, "Blueprint"); _blueprintStatus = AddWrappedText(ref y, "", 40f); AddButtonRow(ref y, ("Save...", delegate { BlueprintSavePrompt.Show(Player.m_localPlayer); }), ("Clear", delegate { BlueprintSession.Clear(); BlueprintPlacer.Disarm(); })); _cellCount = AddPlainText(ref y, ""); AddButtonRow(ref y, ("Reset", delegate { GridState.Reset(); }), ("Hold", delegate { GridHold.Toggle(Player.m_localPlayer); }), ("Undo last", delegate { PlacementHistory.Undo(Player.m_localPlayer); }), ("Close", Close)); _holdLabel = FindButtonLabel(_window, "Hold"); AddHeader(ref y, "Nudge (holds the grid)"); AddButtonRow(ref y, ("Left", delegate { NudgeClick(-1, 0, 0); }), ("Forward", delegate { NudgeClick(0, 1, 0); }), ("Back", delegate { NudgeClick(0, -1, 0); }), ("Right", delegate { NudgeClick(1, 0, 0); })); AddButtonRow(ref y, ("Up", delegate { NudgeClick(0, 0, 1); }), ("Down", delegate { NudgeClick(0, 0, -1); })); AddNote(ref y, "Relative to the camera. " + ModConfig.NudgeStep.Value.ToString("0.##", Invariant) + " m per click, " + GridPreview.KeyName(ModConfig.BigStepModifier.Value) + ": " + ModConfig.NudgeBigStep.Value.ToString("0.##", Invariant) + " m"); float num = BuildLegendColumn(top); float num2 = Mathf.Min(y, num) - 10f; _windowRect.SetSizeWithCurrentAnchors((Axis)1, 0f - num2); } private static float BuildLegendColumn(float top) { //IL_002d: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) float num = 460f; float num2 = 444f; float num3 = top - 6f; AddColumnText("Controls", num, num3, num2, GUIManager.Instance.AveriaSerifBold, 16, GUIManager.Instance.ValheimOrange); num3 -= 24f; string[] array = GridPreview.LegendLines(); for (int i = 0; i < array.Length; i++) { string text = array[i]; int num4 = text.IndexOf(" ", StringComparison.Ordinal); float num5; if (i == 0 || num4 < 0) { num5 = Height(AddColumnText(text.Trim(), num, num3, num2, (i == 0) ? GUIManager.Instance.AveriaSerifBold : GUIManager.Instance.AveriaSerif, 13, Color.white)); } else { float num6 = num2 - 180f - 8f; Text t = AddColumnText(Capitalize(text.Substring(num4).Trim()), num, num3, num6, GUIManager.Instance.AveriaSerif, 13, Color.white); num5 = Mathf.Max(Height(AddColumnText(text.Substring(0, num4).Trim(), num + num6 + 8f, num3, 180f, GUIManager.Instance.AveriaSerifBold, 13, Color.white)), Height(t)); } num3 -= num5 + 3f; if (i < array.Length - 1) { AddDivider(num, num3, num2); } num3 -= 4f; } return num3; } private static void AddDivider(float left, float top, float width) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_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_005e: 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_006a: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SmartBuildDivider", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(_window.transform, false); RectTransform val2 = (RectTransform)val.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 1f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(0f, 1f); val2.anchoredPosition = new Vector2(left, top); val2.sizeDelta = new Vector2(width, 1f); Image component = val.GetComponent<Image>(); ((Graphic)component).color = DividerColor; ((Graphic)component).raycastTarget = false; } private static Text AddColumnText(string text, float left, float top, float width, Font font, int fontSize, Color color) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateText(text, _window.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, font, fontSize, color, true, Color.black, width, (float)fontSize + 6f, false); Text component = obj.GetComponent<Text>(); component.alignment = (TextAnchor)0; component.horizontalOverflow = (HorizontalWrapMode)0; component.verticalOverflow = (VerticalWrapMode)1; RectTransform val = (RectTransform)obj.transform; val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(left, top); val.SetSizeWithCurrentAnchors((Axis)1, Height(component)); return component; } private static float Height(Text t) { return Mathf.Max((float)t.fontSize + 4f, t.preferredHeight); } private static string Capitalize(string text) { if (!string.IsNullOrEmpty(text)) { return char.ToUpperInvariant(text[0]) + text.Substring(1); } return text; } private static void NudgeClick(int right, int forward, int up) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { float step = (Keys.Held(ModConfig.BigStepModifier.Value) ? ModConfig.NudgeBigStep.Value : ModConfig.NudgeSte