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 ValheimFloorPlan v2.1.3
BepInEx\plugins\ValheimFloorPlan\ValheimFloorPlan.dll
Decompiled 5 days 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.IO.Compression; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ValheimFloorPlan")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A floor plan building tool mod for Valheim")] [assembly: AssemblyFileVersion("2.1.3.0")] [assembly: AssemblyInformationalVersion("2.1.3+15c96a2c25d187f4c99ed4f7963decf81ac9e3cb")] [assembly: AssemblyProduct("ValheimFloorPlan")] [assembly: AssemblyTitle("ValheimFloorPlan")] [assembly: AssemblyVersion("2.1.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ValheimFloorPlan { public enum WallFaceMode { Default, Outer, Inner } public class FloorPlanPiece { public int Col { get; set; } public int Row { get; set; } public string Type { get; set; } = ""; public int Rotation { get; set; } public WallFaceMode WallFace { get; set; } = WallFaceMode.Default; } public class FlexiWallPiece { public float X1 { get; set; } public float Y1 { get; set; } public float X2 { get; set; } public float Y2 { get; set; } public float Mx { get; set; } public float My { get; set; } } public class FloorPlan { public int Cols { get; set; } public int Rows { get; set; } public List<FloorPlanPiece> Pieces { get; } = new List<FloorPlanPiece>(); public List<FlexiWallPiece> FlexiWalls { get; } = new List<FlexiWallPiece>(); public static FloorPlan Load(string path) { FloorPlan floorPlan = new FloorPlan(); string[] array = File.ReadAllLines(path); foreach (string text in array) { string text2 = text.Trim(); if (text2.StartsWith("cols=")) { floorPlan.Cols = int.Parse(text2.Substring(5)); } else if (text2.StartsWith("rows=")) { floorPlan.Rows = int.Parse(text2.Substring(5)); } else if (text2.StartsWith("flexiwall,") || text2.StartsWith("arcwall,")) { string[] array2 = text2.Split(new char[1] { ',' }); if (array2.Length >= 7 && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.TryParse(array2[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && float.TryParse(array2[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5) && float.TryParse(array2[6], NumberStyles.Float, CultureInfo.InvariantCulture, out var result6)) { floorPlan.FlexiWalls.Add(new FlexiWallPiece { X1 = result, Y1 = result2, X2 = result3, Y2 = result4, Mx = result5, My = result6 }); } } else { if (!text2.StartsWith("piece,")) { continue; } string[] array3 = text2.Split(new char[1] { ',' }); if (array3.Length < 4) { continue; } int rotation = 0; int num = -1; if (array3.Length > 4) { if (int.TryParse(array3[4], out var result7)) { rotation = result7; num = ((array3.Length > 5) ? 5 : (-1)); } else { num = 4; } } floorPlan.Pieces.Add(new FloorPlanPiece { Col = int.Parse(array3[1]), Row = int.Parse(array3[2]), Type = array3[3], Rotation = rotation, WallFace = ((num >= 0) ? ParseWallFace(array3[num]) : WallFaceMode.Default) }); } } return floorPlan; } private static WallFaceMode ParseWallFace(string raw) { string text = (raw ?? string.Empty).Trim().ToLowerInvariant(); if (text == "outer" || text == "out" || text == "o") { return WallFaceMode.Outer; } if (text == "inner" || text == "in" || text == "i") { return WallFaceMode.Inner; } return WallFaceMode.Default; } } public class FloorPlanBuilder : MonoBehaviour { private struct FlexiWallSegment { public float Lx; public float Lz; public float YawDeg; public FlexiWallSegment(float lx, float lz, float yawDeg) { Lx = lx; Lz = lz; YawDeg = yawDeg; } } private sealed class ScaffoldPolePoint { public readonly float T; public readonly Vector2 Local; public readonly Vector3 Pos; public ScaffoldPolePoint(float t, Vector2 local, Vector3 pos) { //IL_0010: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) T = t; Local = local; Pos = pos; } } private sealed class ScaffoldFurnitureExclusion { public readonly Vector2 Center; public readonly Vector2 Forward; public readonly Vector2 Side; public readonly float ForwardHalfExtent; public readonly float SideHalfExtent; public readonly float FrontClearance; public ScaffoldFurnitureExclusion(Vector2 center, Vector2 forward, Vector2 side, float forwardHalfExtent, float sideHalfExtent, float frontClearance) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Center = center; Forward = forward; Side = side; ForwardHalfExtent = forwardHalfExtent; SideHalfExtent = sideHalfExtent; FrontClearance = frontClearance; } } private sealed class ScaffoldDoorSpan { public readonly float Min; public readonly float Max; public ScaffoldDoorSpan(float min, float max) { Min = min; Max = max; } } private sealed class HearthOpening { public readonly int MinCol; public readonly int MinRow; public readonly int MaxColExclusive; public readonly int MaxRowExclusive; public readonly int SourceLevel; public readonly string SourceType; public int Width => MaxColExclusive - MinCol; public int Height => MaxRowExclusive - MinRow; public HearthOpening(int minCol, int minRow, int maxColExclusive, int maxRowExclusive, int sourceLevel = 0, string sourceType = "Opening") { MinCol = minCol; MinRow = minRow; MaxColExclusive = maxColExclusive; MaxRowExclusive = maxRowExclusive; SourceLevel = sourceLevel; SourceType = sourceType; } } private const bool TESTING_ONLY = false; private const float PLACE_DELAY = 0.05f; private const float ORIGIN_MARKER_LIFT = 0.3f; private const float ORIGIN_MARKER_HEIGHT = 10f; private const float PREVIEW_EDGE_RISK_SAMPLE_INTERVAL = 0.45f; private const float PREVIEW_EDGE_RISK_HINT_INTERVAL = 2f; private const float PREVIEW_EDGE_RISK_HINT_START_DELAY = 2.5f; private const float PREVIEW_STEEP_RELIEF_WARN = 6f; private const float PREVIEW_RISK_MARKER_RADIUS = 0.45f; private const float PREVIEW_RISK_MARKER_LIFT = 0.18f; private static readonly string[] TEST_WORKBENCH_PREFABS = new string[6] { "piece_workbench", "forge", "piece_stonecutter", "piece_artisanstation", "blackforge", "piece_magetable" }; public const string VFP_TAG = "vfp_build"; private float _undoConfirmationExpireAt = 0f; private int _undoConfirmationPieceCount = 0; private int _undoConfirmationTerrainChunks = 0; private bool _undoConfirmationKeepLeveledTerrain = false; private Coroutine _undoCountdownCoroutine = null; private Coroutine _undoRefreshCoroutine = null; private GameObject? _undoHighlightGo = null; private const float UNDO_REFRESH_RADIUS = 120f; private const float UNDO_REFRESH_DURATION = 2.5f; private const float UNDO_REFRESH_INTERVAL = 0.25f; private const float UNDO_HIGHLIGHT_RING_RADIUS = 1.05f; private const float UNDO_HIGHLIGHT_RING_LIFT = 0.25f; private const int UNDO_HIGHLIGHT_RING_SEGMENTS = 20; private const float UNDO_RADIUS_ADJUST_STEP = 5f; private const float UNDO_CONFIRMATION_SECONDS = 5f; private const int UNDO_BOUNDARY_CIRCLE_SEGMENTS = 64; private const float UNDO_BOUNDARY_CIRCLE_LIFT = 0.3f; private float _undoActiveRadius = 15f; private Vector3 _undoCenter = Vector3.zero; private readonly List<GameObject> _lastPlaced = new List<GameObject>(); private readonly List<GameObject> _groundFloorScaffoldVerticals = new List<GameObject>(); private bool _previewActive = false; private FloorPlan? _previewPlan = null; private GameObject? _previewGo = null; private MeshFilter? _previewPadWalls = null; private MeshFilter? _previewOuterWalls = null; private LineRenderer? _previewOriginMarker = null; private float _previewRotationDeg = 0f; private Vector3 _previewCenter = Vector3.zero; private Vector3 _previewOrigin = Vector3.zero; private TerrainLeveler.EdgeRiskLevel _previewEdgeRisk = TerrainLeveler.EdgeRiskLevel.Low; private float _previewEdgeRelief = 0f; private float _previewEdgeIrregularity = 0f; private float _previewEdgeMaxStep = 0f; private float _previewRiskNextSampleAt = 0f; private float _previewRiskNextHintAt = 0f; private float _previewRiskHintsEnabledAt = 0f; private bool _previewRiskDirty = true; private readonly List<Vector3> _previewRiskHotspots = new List<Vector3>(); private readonly List<LineRenderer> _previewRiskMarkers = new List<LineRenderer>(); private readonly List<Vector3> _previewRiskRenderPoints = new List<Vector3>(); private readonly List<MeshFilter> _previewUpperLevelRings = new List<MeshFilter>(); private int _previewRiskBottomCount = 0; private const float FLEXI_TIGHT_CURVE_RADIUS = 4f; private const float FLEXI_TIGHT_CURVE_DENSITY = 0.5f; private const float FLEXI_MIN_SEGMENT_ANGLE_RAD = (float)Math.PI / 15f; private static float UNDO_RADIUS => ValheimFloorPlanPlugin.UndoRadius; public static FloorPlanBuilder Instance { get; private set; } = null; public bool CanUndo => _lastPlaced.Count > 0 || TerrainSnapshot.HasSnapshot; private void Awake() { Instance = this; } public void StartPreview(string path) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) if (_previewActive) { CancelPreview(); } FloorPlan floorPlan; try { floorPlan = FloorPlan.Load(path); } catch (Exception ex) { ValheimFloorPlanPlugin.Log.LogError((object)("Failed to load floor plan: " + ex.Message)); ValheimFloorPlanPlugin.ShowWrappedMessage((MessageType)2, "ValheimFloorPlan: Could not load plan '" + Path.GetFileName(path) + "' — " + ex.Message); return; } if (ValidateAdditionalLevelPlanFootprints(floorPlan)) { _previewPlan = floorPlan; _previewActive = true; Player localPlayer = Player.m_localPlayer; _previewRotationDeg = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.eulerAngles.y : (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform.eulerAngles.y : 0f)); _previewRotationDeg = SnapAngleDeg(_previewRotationDeg + 180f); _previewCenter = (((Object)(object)localPlayer != (Object)null) ? GetInitialBuildCenter(localPlayer, floorPlan, _previewRotationDeg) : Vector3.zero); _previewOrigin = GetPlacementOriginFromCenter(floorPlan, _previewCenter, _previewRotationDeg); _previewGo = new GameObject("VFP_Preview"); _previewPadWalls = MakeWallRing(_previewGo, "VFP_WallsPad", new Color(1f, 1f, 1f, 0.28f)); _previewOuterWalls = MakeWallRing(_previewGo, "VFP_WallsOuter", new Color(0.2f, 1f, 0.2f, 0.24f)); _previewOriginMarker = MakeLine(_previewGo, new Color(1f, 0.9f, 0f, 0.98f), 0.2f, 2); _previewUpperLevelRings.Clear(); if (ValheimFloorPlanPlugin.FloorPlanLevels >= 2) { _previewUpperLevelRings.Add(MakeWallRing(_previewGo, "VFP_WallsLevel2", new Color(1f, 0.25f, 0.25f, 0.32f))); } if (ValheimFloorPlanPlugin.FloorPlanLevels >= 3) { _previewUpperLevelRings.Add(MakeWallRing(_previewGo, "VFP_WallsLevel3", new Color(1f, 0.25f, 0.25f, 0.32f))); } _previewEdgeRisk = TerrainLeveler.EdgeRiskLevel.Low; _previewEdgeRelief = 0f; _previewEdgeIrregularity = 0f; _previewEdgeMaxStep = 0f; _previewRiskDirty = true; _previewRiskNextSampleAt = 0f; _previewRiskNextHintAt = Time.time + 2.5f; _previewRiskHintsEnabledAt = Time.time + 2.5f; ValheimFloorPlanPlugin.Log.LogInfo((object)($"[FloorPlanBuilder] Preview active ({floorPlan.Pieces.Count} pieces, " + $"{floorPlan.Cols}×{floorPlan.Rows} cells). {ValheimFloorPlanPlugin.PreviewConfirmKey} to build, RMB/ESC to cancel.")); ValheimFloorPlanPlugin.ShowWrappedMessage((MessageType)2, $"ValheimFloorPlan: {ValheimFloorPlanPlugin.PreviewMoveLeftKey}/{ValheimFloorPlanPlugin.PreviewMoveRightKey}/{ValheimFloorPlanPlugin.PreviewMoveForwardKey}/{ValheimFloorPlanPlugin.PreviewMoveBackwardKey} move | {ValheimFloorPlanPlugin.PreviewRotateLeftKey}/{ValheimFloorPlanPlugin.PreviewRotateRightKey} rotate | {ValheimFloorPlanPlugin.PreviewFineAdjustKey} fine | {ValheimFloorPlanPlugin.PreviewConfirmKey} to place | RMB/{ValheimFloorPlanPlugin.PreviewCancelKey} cancel"); } } private bool ValidateAdditionalLevelPlanFootprints(FloorPlan level1Plan) { GetPlanPieceBounds(level1Plan, out var minCol, out var maxColExclusive, out var minRow, out var maxRowExclusive); if (!ValidateSingleAdditionalLevelPlan("FloorPlanFileLevel2", ValheimFloorPlanPlugin.FloorPlanFileLevel2, minCol, maxColExclusive, minRow, maxRowExclusive)) { return false; } if (!ValidateSingleAdditionalLevelPlan("FloorPlanFileLevel3", ValheimFloorPlanPlugin.FloorPlanFileLevel3, minCol, maxColExclusive, minRow, maxRowExclusive)) { return false; } return true; } private bool ValidateSingleAdditionalLevelPlan(string configKey, string path, int l1MinCol, int l1MaxColExclusive, int l1MinRow, int l1MaxRowExclusive) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) string text = (path ?? string.Empty).Trim(); if (string.IsNullOrEmpty(text)) { return true; } FloorPlan plan; try { plan = FloorPlan.Load(text); } catch (Exception ex) { ValheimFloorPlanPlugin.Log.LogError((object)("[" + configKey + "] Failed to load '" + text + "': " + ex.Message)); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: " + configKey + " could not be loaded. " + Path.GetFileName(text) + " (" + ex.Message + ")"); return false; } GetPlanPieceBounds(plan, out var minCol, out var maxColExclusive, out var minRow, out var maxRowExclusive); if (minCol < l1MinCol || maxColExclusive > l1MaxColExclusive || minRow < l1MinRow || maxRowExclusive > l1MaxRowExclusive) { ValheimFloorPlanPlugin.Log.LogWarning((object)("[" + configKey + "] Footprint must fit inside Level 1 footprint. " + $"Level1=[col {l1MinCol}..{l1MaxColExclusive}, row {l1MinRow}..{l1MaxRowExclusive}] " + $"Candidate=[col {minCol}..{maxColExclusive}, row {minRow}..{maxRowExclusive}] " + "Path='" + text + "'")); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: " + configKey + " footprint must fit inside Level 1 plan. Smaller offset layouts are allowed, but they cannot extend beyond Level 1 bounds."); return false; } ValheimFloorPlanPlugin.Log.LogInfo((object)("[" + configKey + "] Footprint validated inside Level 1. " + $"Candidate=[col {minCol}..{maxColExclusive}, row {minRow}..{maxRowExclusive}] " + "Path='" + text + "'")); return true; } private static MeshFilter MakeWallRing(GameObject parent, string name, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_004a: 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_0072: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent.transform, false); MeshFilter val2 = val.AddComponent<MeshFilter>(); MeshRenderer val3 = val.AddComponent<MeshRenderer>(); ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val3).receiveShadows = false; Material val4 = new Material(Shader.Find("Sprites/Default")); val4.color = color; ((Renderer)val3).sharedMaterial = val4; Mesh val5 = new Mesh { name = name + "_Mesh" }; val5.vertices = (Vector3[])(object)new Vector3[16]; val5.uv = (Vector2[])(object)new Vector2[16]; for (int i = 0; i < 16; i++) { int num = i % 4; Vector2[] uv = val5.uv; int num2 = i; if (1 == 0) { } Vector2 val6 = (Vector2)(num switch { 0 => new Vector2(0f, 0f), 1 => new Vector2(1f, 0f), 2 => new Vector2(1f, 1f), _ => new Vector2(0f, 1f), }); if (1 == 0) { } uv[num2] = val6; } val5.triangles = new int[48] { 0, 1, 2, 0, 2, 3, 2, 1, 0, 3, 2, 0, 4, 5, 6, 4, 6, 7, 6, 5, 4, 7, 6, 4, 8, 9, 10, 8, 10, 11, 10, 9, 8, 11, 10, 8, 12, 13, 14, 12, 14, 15, 14, 13, 12, 15, 14, 12 }; val5.RecalculateNormals(); val2.sharedMesh = val5; return val2; } private static LineRenderer MakeLine(GameObject parent, Color color, float width, int positionCount = 5) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_006d: 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) GameObject val = new GameObject("VFP_Line"); val.transform.SetParent(parent.transform, false); LineRenderer val2 = val.AddComponent<LineRenderer>(); val2.useWorldSpace = true; val2.loop = false; val2.positionCount = positionCount; val2.widthMultiplier = width; ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val2).receiveShadows = false; ((Renderer)val2).sharedMaterial = new Material(Shader.Find("Sprites/Default")); val2.startColor = color; val2.endColor = color; return val2; } private void CancelPreview() { //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_003b: 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) _previewActive = false; _previewPlan = null; _previewPadWalls = null; _previewOuterWalls = null; _previewOriginMarker = null; _previewRotationDeg = 0f; _previewCenter = Vector3.zero; _previewOrigin = Vector3.zero; _previewEdgeRisk = TerrainLeveler.EdgeRiskLevel.Low; _previewEdgeRelief = 0f; _previewEdgeIrregularity = 0f; _previewEdgeMaxStep = 0f; _previewRiskDirty = true; _previewRiskNextSampleAt = 0f; _previewRiskNextHintAt = 0f; _previewRiskHintsEnabledAt = 0f; _previewRiskHotspots.Clear(); _previewRiskRenderPoints.Clear(); _previewRiskMarkers.Clear(); _previewUpperLevelRings.Clear(); if ((Object)(object)_previewGo != (Object)null) { Object.Destroy((Object)(object)_previewGo); _previewGo = null; } } private void Update() { if (_previewActive && _previewPlan != null) { UpdatePreviewMode(); } if (_undoConfirmationExpireAt > Time.time) { UpdateUndoConfirmationInput(); } } public void ToggleTearRepairMode() { } public void ToggleTerrainClipMode() { } private void UpdatePreviewMode() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) if (_previewPlan == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { CancelPreview(); return; } UpdatePreviewPosition(_previewOrigin, _previewCenter); bool previewChanged = false; bool flag = IsFineAdjustHeld(); float num = (flag ? ValheimFloorPlanPlugin.PreviewFineRotateStepDeg : ValheimFloorPlanPlugin.PreviewRotateStepDeg); float num2 = (flag ? ValheimFloorPlanPlugin.PreviewFineMoveStep : ValheimFloorPlanPlugin.PreviewMoveStep); if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewRotateLeftKey)) { _previewRotationDeg = (_previewRotationDeg - num + 360f) % 360f; if (!flag) { _previewRotationDeg = SnapAngleDeg(_previewRotationDeg); } _previewOrigin = GetPlacementOriginFromCenter(_previewPlan, _previewCenter, _previewRotationDeg); previewChanged = true; ((Character)localPlayer).Message(ValheimFloorPlanPlugin.ProgressMessageType, $"ValheimFloorPlan: Rotation {_previewRotationDeg:F1}°", 0, (Sprite)null); } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewRotateRightKey)) { _previewRotationDeg = (_previewRotationDeg + num) % 360f; if (!flag) { _previewRotationDeg = SnapAngleDeg(_previewRotationDeg); } _previewOrigin = GetPlacementOriginFromCenter(_previewPlan, _previewCenter, _previewRotationDeg); previewChanged = true; ((Character)localPlayer).Message(ValheimFloorPlanPlugin.ProgressMessageType, $"ValheimFloorPlan: Rotation {_previewRotationDeg:F1}°", 0, (Sprite)null); } Vector3 forward = Vector3.forward; Vector3 right = Vector3.right; Camera main = Camera.main; if ((Object)(object)main != (Object)null) { forward = ((Component)main).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f) { ((Vector3)(ref forward)).Normalize(); ((Vector3)(ref right))..ctor(forward.z, 0f, 0f - forward.x); } else { forward = Vector3.forward; right = Vector3.right; } } Vector3 val = Vector3.zero; if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveForwardKey)) { val = forward * num2; } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveBackwardKey)) { val = -forward * num2; } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveRightKey)) { val = right * num2; } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveLeftKey)) { val = -right * num2; } if (val != Vector3.zero) { _previewCenter += val; _previewOrigin = GetPlacementOriginFromCenter(_previewPlan, _previewCenter, _previewRotationDeg); previewChanged = true; ((Character)localPlayer).Message(ValheimFloorPlanPlugin.ProgressMessageType, $"ValheimFloorPlan: Center ({_previewCenter.x:F1}, {_previewCenter.z:F1})", 0, (Sprite)null); } UpdatePreviewEdgeRisk(localPlayer, previewChanged); if (Input.GetMouseButtonDown(1) || IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewCancelKey)) { CancelPreview(); ((Character)localPlayer).Message((MessageType)2, "ValheimFloorPlan: Build cancelled.", 0, (Sprite)null); return; } bool flag2 = (Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus(); if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewConfirmKey) && !flag2) { FloorPlan previewPlan = _previewPlan; float previewRotationDeg = _previewRotationDeg; Vector3 previewOrigin = _previewOrigin; Vector3 previewCenter = _previewCenter; TerrainLeveler.EdgeRiskLevel previewEdgeRisk = _previewEdgeRisk; float previewEdgeRelief = _previewEdgeRelief; float previewEdgeMaxStep = _previewEdgeMaxStep; float previewEdgeIrregularity = _previewEdgeIrregularity; bool flag3 = previewEdgeRelief >= 6f; if (previewEdgeRisk == TerrainLeveler.EdgeRiskLevel.High || flag3) { ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: Final warning before build. " + $"Edge risk={previewEdgeRisk}, relief={previewEdgeRelief:F1}m, step={previewEdgeMaxStep:F2}m. " + "Terracing or downhill tears may occur."); } CancelPreview(); ValheimFloorPlanPlugin.Log.LogInfo((object)$"[FloorPlanBuilder] Build confirmed by key {ValheimFloorPlanPlugin.PreviewConfirmKey}. Rotation={previewRotationDeg:F0}° center={previewCenter} origin={previewOrigin} edgeRisk={previewEdgeRisk} edgeRelief={previewEdgeRelief:F2} irregularity={previewEdgeIrregularity:F2} maxEdgeStep={previewEdgeMaxStep:F2}"); ((MonoBehaviour)this).StartCoroutine(LevelThenPlace(previewPlan, previewRotationDeg, previewOrigin)); } } private void UpdatePreviewEdgeRisk(Player player, bool previewChanged) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) if (_previewPlan == null) { return; } if (previewChanged) { _previewRiskDirty = true; } if (!_previewRiskDirty && Time.time < _previewRiskNextSampleAt) { return; } TerrainLeveler.EdgeRiskLevel previewEdgeRisk = _previewEdgeRisk; _previewEdgeRisk = TerrainLeveler.EvaluateEdgeRisk(_previewPlan, _previewOrigin, _previewRotationDeg, out _previewEdgeRelief, out _previewEdgeIrregularity, out _previewEdgeMaxStep, _previewRiskHotspots); _previewRiskBottomCount = BuildPreviewRiskRenderPoints(_previewRiskHotspots, _previewRiskRenderPoints); UpdatePreviewRiskMarkers(_previewEdgeRisk, _previewRiskRenderPoints, _previewRiskBottomCount); _previewRiskDirty = false; _previewRiskNextSampleAt = Time.time + 0.45f; bool flag = _previewEdgeRisk != TerrainLeveler.EdgeRiskLevel.Low; if ((!(Time.time < _previewRiskHintsEnabledAt) || flag) && (previewChanged || _previewEdgeRisk != previewEdgeRisk || Time.time >= _previewRiskNextHintAt)) { if (_previewEdgeRisk == TerrainLeveler.EdgeRiskLevel.High || _previewEdgeRisk == TerrainLeveler.EdgeRiskLevel.Medium) { string text = ((_previewEdgeRisk == TerrainLeveler.EdgeRiskLevel.High) ? $"Edge risk HIGH: uneven boundary terrain may cause tears/spikes. Try nudging or rotating before build. step={_previewEdgeMaxStep:F2}m, relief={_previewEdgeRelief:F1}m" : $"Edge risk MEDIUM: some boundary irregularity detected. Small origin/rotation adjustments may improve results. step={_previewEdgeMaxStep:F2}m, relief={_previewEdgeRelief:F1}m"); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: " + text); } _previewRiskNextHintAt = Time.time + 2f; } } private int BuildPreviewRiskRenderPoints(List<Vector3> hotspots, List<Vector3> output) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) output.Clear(); if (_previewPlan == null) { return 0; } float num = Mathf.Clamp(ValheimFloorPlanPlugin.TerrainHighPointDelta, 0f, 4f); if (hotspots.Count == 0) { return 0; } for (int i = 0; i < hotspots.Count; i++) { output.Add(hotspots[i]); } int count = output.Count; TerrainLeveler.GetLeveledAreaBounds(_previewPlan, _previewOrigin, out var minX, out var maxX, out var minZ, out var maxZ); float num2 = _previewRotationDeg * ((float)Math.PI / 180f); float num3 = Mathf.Cos(num2); float num4 = Mathf.Sin(num2); float[] array = new float[4] { minX, maxX, maxX, minX }; float[] array2 = new float[4] { minZ, minZ, maxZ, maxZ }; float num5 = float.MinValue; float y = _previewOrigin.y; RaycastHit val = default(RaycastHit); for (int j = 0; j < 4; j++) { float num6 = array[j] - _previewOrigin.x; float num7 = array2[j] - _previewOrigin.z; float num8 = _previewOrigin.x + num6 * num3 + num7 * num4; float num9 = _previewOrigin.z - num6 * num4 + num7 * num3; if (Physics.Raycast(new Vector3(num8, y + 300f, num9), Vector3.down, ref val, 600f, 2048) && ((RaycastHit)(ref val)).point.y > num5) { num5 = ((RaycastHit)(ref val)).point.y; } } float num10 = ((num5 == float.MinValue) ? y : num5) + 0.3f + num; float num11 = maxZ - _previewOrigin.z; float[] array3 = new float[3] { 0.25f, 0.5f, 0.75f }; for (int k = 0; k < array3.Length; k++) { float num12 = Mathf.Lerp(minX, maxX, array3[k]); float num13 = num12 - _previewOrigin.x; float num14 = _previewOrigin.x + num13 * num3 + num11 * num4; float num15 = _previewOrigin.z - num13 * num4 + num11 * num3; output.Add(new Vector3(num14, num10, num15)); } return count; } private void UpdatePreviewRiskMarkers(TerrainLeveler.EdgeRiskLevel risk, List<Vector3> hotspots, int bottomCount) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: 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) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) int num = ((risk != TerrainLeveler.EdgeRiskLevel.Low) ? Mathf.Min(hotspots.Count, 24) : 0); EnsureRiskMarkerCount(num); RaycastHit val3 = default(RaycastHit); Vector3 val4 = default(Vector3); for (int i = 0; i < _previewRiskMarkers.Count; i++) { LineRenderer val = _previewRiskMarkers[i]; if (i >= num) { ((Renderer)val).enabled = false; continue; } ((Renderer)val).enabled = true; val.startColor = ((risk == TerrainLeveler.EdgeRiskLevel.High) ? new Color(1f, 0.22f, 0.12f, 0.95f) : new Color(1f, 0.72f, 0.18f, 0.92f)); val.endColor = val.startColor; Vector3 val2 = hotspots[i]; float y; if (i < bottomCount) { y = val2.y; if (Physics.Raycast(new Vector3(val2.x, val2.y + 300f, val2.z), Vector3.down, ref val3, 600f, 2048)) { y = ((RaycastHit)(ref val3)).point.y; } y += 0.18f; } else { y = val2.y; } ((Vector3)(ref val4))..ctor(val2.x, y, val2.z); float num2 = 0.45f; val.positionCount = 5; val.SetPosition(0, val4 + new Vector3(0f - num2, 0f, 0f)); val.SetPosition(1, val4 + new Vector3(0f, 0f, num2)); val.SetPosition(2, val4 + new Vector3(num2, 0f, 0f)); val.SetPosition(3, val4 + new Vector3(0f, 0f, 0f - num2)); val.SetPosition(4, val4 + new Vector3(0f - num2, 0f, 0f)); } } private void EnsureRiskMarkerCount(int count) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_previewGo == (Object)null)) { while (_previewRiskMarkers.Count < count) { LineRenderer val = MakeLine(_previewGo, new Color(1f, 0.72f, 0.18f, 0.92f), 0.06f); val.loop = false; _previewRiskMarkers.Add(val); } } } private static Vector3 GetInitialBuildCenter(Player player, FloorPlan? plan, float rotationDeg) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_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_002f: 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_0047: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0059: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)player).transform.position; Vector3 buildForward = GetBuildForward(player); if (((Vector3)(ref buildForward)).sqrMagnitude < 0.0001f) { return position; } float forwardHalfExtent = GetForwardHalfExtent(plan, rotationDeg, buildForward); float num = Mathf.Max(0f, ValheimFloorPlanPlugin.BuildOriginForwardOffset); return position + buildForward * (forwardHalfExtent + num); } private static Vector3 GetBuildForward(Player player) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) Vector3 result = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.forward : ((Component)player).transform.forward); result.y = 0f; if (((Vector3)(ref result)).sqrMagnitude >= 0.0001f) { ((Vector3)(ref result)).Normalize(); } return result; } private static float GetForwardHalfExtent(FloorPlan? plan, float rotationDeg, Vector3 worldForward) { //IL_00d9: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (plan == null) { return 0f; } GetPlanPieceBounds(plan, out var minCol, out var maxColExclusive, out var minRow, out var maxRowExclusive); float outerPerimeterDelta = TerrainLeveler.GetOuterPerimeterDelta(); float num = (float)minCol * 1f - outerPerimeterDelta; float num2 = (float)maxColExclusive * 1f + outerPerimeterDelta; float num3 = (float)minRow * 1f - outerPerimeterDelta; float num4 = (float)maxRowExclusive * 1f + outerPerimeterDelta; float num5 = (num + num2) * 0.5f; float num6 = (num3 + num4) * 0.5f; float num7 = 0f; float[] array = new float[4] { num, num2, num2, num }; float[] array2 = new float[4] { num3, num3, num4, num4 }; for (int i = 0; i < 4; i++) { float localX = array[i] - num5; float localZ = array2[i] - num6; Vector2 val = PieceMap.TransformLocalXZ(localX, localZ, rotationDeg); float num8 = val.x * worldForward.x + val.y * worldForward.z; if (num8 > num7) { num7 = num8; } } return Mathf.Max(0f, num7); } private static bool IsPreviewKeyDown(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return (int)key != 0 && Input.GetKeyDown(key); } private static bool IsFineAdjustHeld() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) KeyCode previewFineAdjustKey = ValheimFloorPlanPlugin.PreviewFineAdjustKey; if ((int)previewFineAdjustKey == 304 || (int)previewFineAdjustKey == 303) { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } return (int)previewFineAdjustKey != 0 && Input.GetKey(previewFineAdjustKey); } private void UpdatePreviewPosition(Vector3 origin, Vector3 center) { //IL_0030: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) if (_previewPlan == null) { return; } float previewRaiseDelta = Mathf.Clamp(ValheimFloorPlanPlugin.TerrainHighPointDelta, 0f, 4f); TerrainLeveler.GetPadBounds(_previewPlan, origin, out var minX, out var maxX, out var minZ, out var maxZ, _previewRotationDeg); TerrainLeveler.GetLeveledAreaBounds(_previewPlan, origin, out var minX2, out var maxX2, out var minZ2, out var maxZ2, _previewRotationDeg); SetWallRingRectangle(_previewPadWalls, origin.y, (Vector2[])(object)new Vector2[4] { new Vector2(minX, minZ), new Vector2(maxX, minZ), new Vector2(maxX, maxZ), new Vector2(minX, maxZ) }, previewRaiseDelta); SetWallRingRectangle(_previewOuterWalls, origin.y, (Vector2[])(object)new Vector2[4] { new Vector2(minX2, minZ2), new Vector2(maxX2, minZ2), new Vector2(maxX2, maxZ2), new Vector2(minX2, maxZ2) }, previewRaiseDelta); SetOriginMarker(_previewOriginMarker, center.y, center); if (_previewUpperLevelRings.Count > 0) { Vector2[] corners = (Vector2[])(object)new Vector2[4] { new Vector2(minX, minZ), new Vector2(maxX, minZ), new Vector2(maxX, maxZ), new Vector2(minX, maxZ) }; float y = origin.y; RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(origin.x, origin.y + 300f, origin.z), Vector3.down, ref val, 600f, 2048)) { y = ((RaycastHit)(ref val)).point.y; } if (_previewUpperLevelRings.Count >= 1) { SetWallRingAtHeight(_previewUpperLevelRings[0], y + (float)ValheimFloorPlanPlugin.ScaffoldingFloorHeight, corners); } if (_previewUpperLevelRings.Count >= 2) { SetWallRingAtHeight(_previewUpperLevelRings[1], y + (float)ValheimFloorPlanPlugin.ScaffoldingFloorHeight + (float)ValheimFloorPlanPlugin.ScaffoldingFloorHeight2, corners); } } } private static Vector3 GetPlacementOriginFromCenter(FloorPlan? plan, Vector3 center, float rotationDeg) { //IL_0048: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_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_007a: Unknown result type (might be due to invalid IL or missing references) if (plan == null) { return center; } GetPlanPieceBounds(plan, out var minCol, out var maxColExclusive, out var minRow, out var maxRowExclusive); float localX = (float)(minCol + maxColExclusive) * 0.5f * 1f; float localZ = (float)(minRow + maxRowExclusive) * 0.5f * 1f; Vector2 val = PieceMap.TransformLocalXZ(localX, localZ, rotationDeg); return new Vector3(center.x - val.x, center.y, center.z - val.y); } private static Vector2[] RotateBoundsCorners(Vector3 origin, float minX, float maxX, float minZ, float maxZ, float rotDeg) { //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_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_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_0037: 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_005d: 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_0099: 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_00a4: 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_00b5: 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) Vector2[] array = (Vector2[])(object)new Vector2[4] { new Vector2(minX, minZ), new Vector2(maxX, minZ), new Vector2(maxX, maxZ), new Vector2(minX, maxZ) }; if (Mathf.Approximately(rotDeg % 360f, 0f)) { return array; } float x = origin.x; float z = origin.z; for (int i = 0; i < 4; i++) { float localX = array[i].x - x; float localZ = array[i].y - z; Vector2 val = PieceMap.TransformLocalXZ(localX, localZ, rotDeg); array[i] = new Vector2(x + val.x, z + val.y); } return array; } private static void SetWallRingRectangle(MeshFilter? mf, float referenceY, Vector2[] corners, float previewRaiseDelta) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mf == (Object)null || (Object)(object)mf.sharedMesh == (Object)null) { return; } float num = referenceY + 300f; float[] array = new float[4]; float num2 = float.MaxValue; float num3 = float.MinValue; RaycastHit val = default(RaycastHit); for (int i = 0; i < 4; i++) { float num4 = referenceY; if (Physics.Raycast(new Vector3(corners[i].x, num, corners[i].y), Vector3.down, ref val, 600f, 2048)) { num4 = ((RaycastHit)(ref val)).point.y; } array[i] = num4; if (num4 < num2) { num2 = num4; } if (num4 > num3) { num3 = num4; } } float num5 = num2 + 0.06f; float num6 = num3 + 0.3f + Mathf.Max(0f, previewRaiseDelta); if (num6 - num5 < 0.75f) { num6 = num5 + 0.75f; } Mesh sharedMesh = mf.sharedMesh; Vector3[] vertices = sharedMesh.vertices; for (int j = 0; j < 4; j++) { int num7 = (j + 1) % 4; int num8 = j * 4; vertices[num8] = new Vector3(corners[j].x, num5, corners[j].y); vertices[num8 + 1] = new Vector3(corners[num7].x, num5, corners[num7].y); vertices[num8 + 2] = new Vector3(corners[num7].x, num6, corners[num7].y); vertices[num8 + 3] = new Vector3(corners[j].x, num6, corners[j].y); } sharedMesh.vertices = vertices; sharedMesh.RecalculateBounds(); sharedMesh.RecalculateNormals(); } private static void SetWallRingAtHeight(MeshFilter? mf, float floorY, Vector2[] corners, float ringHeight = 0.45f) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)mf == (Object)null) && !((Object)(object)mf.sharedMesh == (Object)null)) { float num = floorY - 0.05f; float num2 = floorY + ringHeight; Mesh sharedMesh = mf.sharedMesh; Vector3[] vertices = sharedMesh.vertices; for (int i = 0; i < 4; i++) { int num3 = (i + 1) % 4; int num4 = i * 4; vertices[num4] = new Vector3(corners[i].x, num, corners[i].y); vertices[num4 + 1] = new Vector3(corners[num3].x, num, corners[num3].y); vertices[num4 + 2] = new Vector3(corners[num3].x, num2, corners[num3].y); vertices[num4 + 3] = new Vector3(corners[i].x, num2, corners[i].y); } sharedMesh.vertices = vertices; sharedMesh.RecalculateBounds(); sharedMesh.RecalculateNormals(); } } private static void SetOriginMarker(LineRenderer? lr, float referenceY, Vector3 origin) { //IL_001b: 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_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_0060: 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_0073: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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) if (!((Object)(object)lr == (Object)null)) { float num = referenceY; float num2 = referenceY + 300f; RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(origin.x, num2, origin.z), Vector3.down, ref val, 600f, 2048)) { num = ((RaycastHit)(ref val)).point.y; } lr.positionCount = 2; lr.SetPosition(0, new Vector3(origin.x, num + 0.3f, origin.z)); lr.SetPosition(1, new Vector3(origin.x, num + 0.3f + 10f, origin.z)); } } private static void SetLinePositions(LineRenderer? lr, Vector3 from, Vector3 to) { //IL_0018: 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) if (!((Object)(object)lr == (Object)null)) { lr.positionCount = 2; lr.SetPosition(0, from); lr.SetPosition(1, to); } } public void Undo(bool keepLeveledTerrain = false) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { ValheimFloorPlanPlugin.Log.LogWarning((object)"[FloorPlanBuilder] No local player for Undo."); return; } if (_undoConfirmationExpireAt > Time.time) { _undoConfirmationExpireAt = 0f; if (_undoCountdownCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_undoCountdownCoroutine); } _undoCountdownCoroutine = null; PerformUndo(localPlayer, _undoConfirmationKeepLeveledTerrain); _undoConfirmationKeepLeveledTerrain = false; return; } _undoActiveRadius = UNDO_RADIUS; _undoCenter = ((Component)localPlayer).transform.position; CountUndoStats(localPlayer, _undoActiveRadius, _undoCenter, out var pieceCount, out var terrainChunkCount); if (pieceCount == 0 && terrainChunkCount == 0) { ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.ProgressMessageType, "ValheimFloorPlan: Nothing to undo."); return; } _undoConfirmationPieceCount = pieceCount; _undoConfirmationTerrainChunks = terrainChunkCount; _undoConfirmationKeepLeveledTerrain = keepLeveledTerrain; _undoConfirmationExpireAt = Time.time + 5f; if (_undoCountdownCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_undoCountdownCoroutine); } _undoCountdownCoroutine = ((MonoBehaviour)this).StartCoroutine(UndoCountdownCoroutine()); ShowUndoHighlights(localPlayer); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.ProgressMessageType, BuildUndoConfirmationMessage(5)); ValheimFloorPlanPlugin.Log.LogInfo((object)(keepLeveledTerrain ? $"[FloorPlanBuilder] Undo confirmation pending (keep terrain): {pieceCount} pieces, snapshot chunks={terrainChunkCount}." : $"[FloorPlanBuilder] Undo confirmation pending: {pieceCount} pieces, {terrainChunkCount} terrain chunks.")); } private string BuildUndoConfirmationMessage(int secondsLeft) { string text = $"ValheimFloorPlan: Confirm Undo? Will remove {_undoConfirmationPieceCount} piece(s)"; if (_undoConfirmationKeepLeveledTerrain) { text = ((_undoConfirmationTerrainChunks <= 0) ? (text + " and keep leveled terrain") : (text + $" and keep leveled terrain (discard {_undoConfirmationTerrainChunks} snapshot chunk(s))")); } else if (_undoConfirmationTerrainChunks > 0) { text += $" and restore {_undoConfirmationTerrainChunks} terrain chunk(s)"; } text += $" within {_undoActiveRadius:F0}m horizontal radius (+/- to adjust)"; return text + $". Arrow keys to move circle center | Press Undo key again ({secondsLeft}s remaining) to confirm, or RMB/Esc to cancel."; } private void CountUndoStats(Player player, float radius, Vector3 center, out int pieceCount, out int terrainChunkCount) { //IL_0060: 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) pieceCount = 0; ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0); foreach (ZNetView val in array) { if (!((Object)(object)val == (Object)null)) { ZDO zDO = val.GetZDO(); if (zDO != null && !(zDO.GetString("vfp_build", "") != "1") && IsWithinHorizontalRadius(((Component)val).transform.position, center, radius)) { pieceCount++; } } } terrainChunkCount = TerrainSnapshot.GetSnapshotChunkCount(); } private void PerformUndo(Player player, bool keepLeveledTerrain) { //IL_0073: 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_021f: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) ClearUndoHighlights(); int num = 0; ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0); foreach (ZNetView val in array) { if (!((Object)(object)val == (Object)null)) { ZDO zDO = val.GetZDO(); if (zDO != null && !(zDO.GetString("vfp_build", "") != "1") && IsWithinHorizontalRadius(((Component)val).transform.position, _undoCenter, _undoActiveRadius)) { ZNetScene.instance.Destroy(((Component)val).gameObject); num++; } } } _lastPlaced.Clear(); bool hasSnapshot = TerrainSnapshot.HasSnapshot; int snapshotChunkCount = TerrainSnapshot.GetSnapshotChunkCount(); int num2 = 0; int num3 = 0; if (keepLeveledTerrain) { if (hasSnapshot) { num3 = snapshotChunkCount; TerrainSnapshot.Clear(); } } else { num2 = snapshotChunkCount; TerrainSnapshot.Restore(); if (hasSnapshot && num2 > 0) { if (_undoRefreshCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_undoRefreshCoroutine); } _undoRefreshCoroutine = ((MonoBehaviour)this).StartCoroutine(PostUndoTerrainRefresh(_undoCenter, num2)); } if (!hasSnapshot) { ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: No terrain snapshot in this session. Undo removed pieces only."); } } if (keepLeveledTerrain) { ValheimFloorPlanPlugin.Log.LogInfo((object)$"[FloorPlanBuilder] Undo(keep terrain): removed {num} VFP pieces within {_undoActiveRadius:F0}m from center {_undoCenter}, discarded {num3} terrain snapshot chunks."); ((Character)player).Message((MessageType)2, string.Format("ValheimFloorPlan: Undone ({0} pieces removed, leveled terrain kept{1}).", num, (num3 > 0) ? $", {num3} snapshot chunks discarded" : ""), 0, (Sprite)null); } else { ValheimFloorPlanPlugin.Log.LogInfo((object)$"[FloorPlanBuilder] Undo: removed {num} VFP pieces within {_undoActiveRadius:F0}m from center {_undoCenter}, restored {num2} terrain chunks."); ((Character)player).Message((MessageType)2, $"ValheimFloorPlan: Undone ({num} pieces removed, {num2} terrain chunks restored).", 0, (Sprite)null); } } private IEnumerator PostUndoTerrainRefresh(Vector3 center, int restoredChunks) { //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) float elapsed = 0f; int passes = 0; int touched = 0; for (; elapsed < 2.5f; elapsed += 0.25f) { Heightmap[] hmaps = Object.FindObjectsOfType<Heightmap>() ?? Array.Empty<Heightmap>(); int passTouched = 0; Heightmap[] array = hmaps; foreach (Heightmap hmap in array) { if (!((Object)(object)hmap == (Object)null) && !(Vector3.Distance(((Component)hmap).transform.position, center) > 120f)) { hmap.Poke(false); passTouched++; } } passes++; touched = passTouched; yield return (object)new WaitForSeconds(0.25f); } ValheimFloorPlanPlugin.Log.LogInfo((object)$"[FloorPlanBuilder] Post-undo refresh complete: {passes} passes, {touched} nearby heightmaps touched, restoredChunks={restoredChunks}."); _undoRefreshCoroutine = null; } private IEnumerator UndoCountdownCoroutine() { float nextUpdateAt = Time.time + 1f; while (_undoConfirmationExpireAt > Time.time) { if (Time.time >= nextUpdateAt) { float remainingSeconds = _undoConfirmationExpireAt - Time.time; ValheimFloorPlanPlugin.ShowWrappedMessage(text: BuildUndoConfirmationMessage((int)Mathf.Ceil(remainingSeconds)), messageType: ValheimFloorPlanPlugin.ProgressMessageType); nextUpdateAt = Time.time + 1f; } yield return null; } _undoCountdownCoroutine = null; _undoConfirmationExpireAt = 0f; _undoConfirmationKeepLeveledTerrain = false; ClearUndoHighlights(); } private void ShowUndoHighlights(Player player) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027a: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) ClearUndoHighlights(); _undoHighlightGo = new GameObject("VFP_UndoHighlight"); Color color = default(Color); ((Color)(ref color))..ctor(1f, 0.18f, 0.12f, 0.95f); ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0); RaycastHit val2 = default(RaycastHit); foreach (ZNetView val in array) { if ((Object)(object)val == (Object)null) { continue; } ZDO zDO = val.GetZDO(); if (zDO != null && !(zDO.GetString("vfp_build", "") != "1") && IsWithinHorizontalRadius(((Component)val).transform.position, _undoCenter, _undoActiveRadius)) { Vector3 position = ((Component)val).transform.position; float y = position.y; if (Physics.Raycast(new Vector3(position.x, position.y + 20f, position.z), Vector3.down, ref val2, 40f, 2048)) { y = ((RaycastHit)(ref val2)).point.y; } y += 0.25f; LineRenderer val3 = MakeLine(_undoHighlightGo, color, 0.09f, 20); val3.loop = true; for (int j = 0; j < 20; j++) { float num = (float)j * (float)Math.PI * 2f / 20f; val3.SetPosition(j, new Vector3(position.x + Mathf.Cos(num) * 1.05f, y, position.z + Mathf.Sin(num) * 1.05f)); } } } LineRenderer val4 = MakeLine(_undoHighlightGo, new Color(1f, 0.65f, 0f, 0.92f), 0.15f, 64); val4.loop = true; RaycastHit val5 = default(RaycastHit); for (int k = 0; k < 64; k++) { float num2 = (float)k * (float)Math.PI * 2f / 64f; float num3 = _undoCenter.x + Mathf.Cos(num2) * _undoActiveRadius; float num4 = _undoCenter.z + Mathf.Sin(num2) * _undoActiveRadius; float y2 = _undoCenter.y; if (Physics.Raycast(new Vector3(num3, _undoCenter.y + 300f, num4), Vector3.down, ref val5, 600f, 2048)) { y2 = ((RaycastHit)(ref val5)).point.y; } val4.SetPosition(k, new Vector3(num3, y2 + 0.3f, num4)); } } private void ClearUndoHighlights() { if ((Object)(object)_undoHighlightGo != (Object)null) { Object.Destroy((Object)(object)_undoHighlightGo); _undoHighlightGo = null; } } private void CancelUndoConfirmation(Player player) { if (_undoCountdownCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_undoCountdownCoroutine); _undoCountdownCoroutine = null; } _undoConfirmationExpireAt = 0f; _undoConfirmationKeepLeveledTerrain = false; ClearUndoHighlights(); ((Character)player).Message((MessageType)2, "ValheimFloorPlan: Undo cancelled.", 0, (Sprite)null); } private void UpdateUndoConfirmationInput() { //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } if (Input.GetMouseButtonDown(1) || Input.GetKeyDown((KeyCode)27)) { CancelUndoConfirmation(localPlayer); return; } bool flag = Input.GetKeyDown((KeyCode)43) || Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270); bool flag2 = Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269); if (flag || flag2) { float num = _undoActiveRadius + (flag ? 5f : (-5f)); _undoActiveRadius = Mathf.Clamp(num, 5f, 150f); ValheimFloorPlanPlugin.SetUndoRadius(_undoActiveRadius); CountUndoStats(localPlayer, _undoActiveRadius, _undoCenter, out var pieceCount, out var terrainChunkCount); _undoConfirmationPieceCount = pieceCount; _undoConfirmationTerrainChunks = terrainChunkCount; ShowUndoHighlights(localPlayer); _undoConfirmationExpireAt = Time.time + 5f; if (_undoCountdownCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_undoCountdownCoroutine); } _undoCountdownCoroutine = ((MonoBehaviour)this).StartCoroutine(UndoCountdownCoroutine()); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.ProgressMessageType, BuildUndoConfirmationMessage(5)); return; } float num2 = (IsFineAdjustHeld() ? ValheimFloorPlanPlugin.PreviewFineMoveStep : ValheimFloorPlanPlugin.PreviewMoveStep); Vector3 forward = Vector3.forward; Vector3 right = Vector3.right; Camera main = Camera.main; if ((Object)(object)main != (Object)null) { forward = ((Component)main).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f) { ((Vector3)(ref forward)).Normalize(); ((Vector3)(ref right))..ctor(forward.z, 0f, 0f - forward.x); } else { forward = Vector3.forward; right = Vector3.right; } } Vector3 val = Vector3.zero; bool flag3 = false; if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveForwardKey)) { val = forward * num2; flag3 = true; } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveBackwardKey)) { val = -forward * num2; flag3 = true; } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveRightKey)) { val = right * num2; flag3 = true; } else if (IsPreviewKeyDown(ValheimFloorPlanPlugin.PreviewMoveLeftKey)) { val = -right * num2; flag3 = true; } if (flag3) { _undoCenter += val; CountUndoStats(localPlayer, _undoActiveRadius, _undoCenter, out var pieceCount2, out var terrainChunkCount2); _undoConfirmationPieceCount = pieceCount2; _undoConfirmationTerrainChunks = terrainChunkCount2; ShowUndoHighlights(localPlayer); _undoConfirmationExpireAt = Time.time + 5f; if (_undoCountdownCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_undoCountdownCoroutine); } _undoCountdownCoroutine = ((MonoBehaviour)this).StartCoroutine(UndoCountdownCoroutine()); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.ProgressMessageType, BuildUndoConfirmationMessage(5)); } } public void BuildFromFile(string path) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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) FloorPlan floorPlan; try { floorPlan = FloorPlan.Load(path); } catch (Exception ex) { ValheimFloorPlanPlugin.Log.LogError((object)("Failed to load floor plan: " + ex.Message)); ValheimFloorPlanPlugin.ShowWrappedMessage((MessageType)2, "ValheimFloorPlan: Could not load plan '" + Path.GetFileName(path) + "' — " + ex.Message); return; } if (ValidateAdditionalLevelPlanFootprints(floorPlan)) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { ValheimFloorPlanPlugin.Log.LogError((object)"No local player found."); return; } ValheimFloorPlanPlugin.Log.LogInfo((object)$"Building floor plan: {floorPlan.Pieces.Count} pieces from {path}"); float num = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.eulerAngles.y : ((Component)localPlayer).transform.eulerAngles.y); num = SnapAngleDeg(num + 180f); Vector3 initialBuildCenter = GetInitialBuildCenter(localPlayer, floorPlan, num); Vector3 placementOriginFromCenter = GetPlacementOriginFromCenter(floorPlan, initialBuildCenter, num); ((MonoBehaviour)this).StartCoroutine(LevelThenPlace(floorPlan, num, placementOriginFromCenter)); } } private IEnumerator LevelThenPlace(FloorPlan plan, float rotationDeg, Vector3 origin) { //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) Player player = Player.m_localPlayer; if ((Object)(object)player == (Object)null) { ValheimFloorPlanPlugin.Log.LogError((object)"No local player found."); yield break; } float snappedRotationDeg = SnapAngleDeg(rotationDeg); if (Mathf.Abs(Mathf.DeltaAngle(rotationDeg, snappedRotationDeg)) > 0.01f) { ValheimFloorPlanPlugin.Log.LogInfo((object)$"Build rotation snapped: {rotationDeg:F1}° -> {snappedRotationDeg:F1}° (step={ValheimFloorPlanPlugin.BuildRotationSnapDegrees:F1}°)"); } rotationDeg = snappedRotationDeg; ValheimFloorPlanPlugin.Log.LogInfo((object)$"Build origin: {origin} rotation={rotationDeg:F1}°"); _lastPlaced.Clear(); _groundFloorScaffoldVerticals.Clear(); TerrainLeveler.GetSnapshotBounds(plan, origin, out var sMinX, out var sMaxX, out var sMinZ, out var sMaxZ, rotationDeg); TerrainSnapshot.Capture(sMinX, sMaxX, sMinZ, sMaxZ, origin.y); if (!TerrainSnapshot.HasSnapshot) { ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: Warning - terrain snapshot capture failed. Undo may remove pieces without restoring terrain."); } ((Character)player).Message((MessageType)2, "Clearing rocks...", 0, (Sprite)null); ClearRocksInPad(plan, origin, rotationDeg); ((Character)player).Message((MessageType)2, "Leveling terrain...", 0, (Sprite)null); yield return ((MonoBehaviour)this).StartCoroutine(TerrainLeveler.LevelForPlan(plan, origin, rotationDeg)); ((Character)player).Message((MessageType)2, "Waiting for terrain physics...", 0, (Sprite)null); ShowBuildProgress("Waiting for terrain physics..."); TerrainLeveler.GetPadBounds(plan, origin, out var padMinX, out var padMaxX, out var padMinZ, out var padMaxZ, rotationDeg); yield return ((MonoBehaviour)this).StartCoroutine(WaitForTerrainPhysics(padMinX, padMaxX, padMinZ, padMaxZ, TerrainLeveler.TargetLevelY)); ((Character)player).Message((MessageType)2, "Placing floor plan pieces...", 0, (Sprite)null); ShowBuildProgress($"Placing pieces... 0/{plan.Pieces.Count}"); yield return ((MonoBehaviour)this).StartCoroutine(PlacePieces(plan, origin, rotationDeg)); if (ValheimFloorPlanPlugin.RoofScaffolding) { ShowBuildProgress("Placing roof scaffolding..."); yield return ((MonoBehaviour)this).StartCoroutine(PlaceRoofScaffolding(plan, origin, rotationDeg)); } yield return ((MonoBehaviour)this).StartCoroutine(PlaceAdditionalLevelLayouts(plan, origin, rotationDeg)); ShowBuildProgress("Final checks..."); yield return ((MonoBehaviour)this).StartCoroutine(PostBuildSpikeGuard(plan, origin, rotationDeg)); if (!ValheimFloorPlanPlugin.DisableWelcomePost) { yield return ((MonoBehaviour)this).StartCoroutine(PlaceCenterSignage(plan, origin, rotationDeg)); } } private IEnumerator PlaceAdditionalLevelLayouts(FloorPlan level1Plan, Vector3 origin, float rotationDeg) { //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) int configuredLevels = Mathf.Clamp(ValheimFloorPlanPlugin.FloorPlanLevels, 1, 3); if (configuredLevels <= 1) { yield break; } List<HearthOpening> blockedChimneyShaftOpenings = BuildHearthOpenings(level1Plan); List<HearthOpening> blockedStaircaseShaftOpenings = BuildStaircaseOpenings(level1Plan, 1); string level2Path = (ValheimFloorPlanPlugin.FloorPlanFileLevel2 ?? string.Empty).Trim(); string level3Path = (ValheimFloorPlanPlugin.FloorPlanFileLevel3 ?? string.Empty).Trim(); if (!ValheimFloorPlanPlugin.RoofScaffolding || !ValheimFloorPlanPlugin.ScaffoldingFloors) { ValheimFloorPlanPlugin.Log.LogWarning((object)"[UpperLevels] FloorPlanLevels > 1 requires RoofScaffolding and ScaffoldingFloors. Upper-level placement skipped."); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: FloorPlanLevels > 1 requires RoofScaffolding and ScaffoldingFloors."); yield break; } GetPlanPieceBounds(level1Plan, out var l1MinCol, out var l1MaxColExclusive, out var l1MinRow, out var l1MaxRowExclusive); if (configuredLevels >= 2) { FloorPlan level2Plan; if (string.IsNullOrEmpty(level2Path)) { ValheimFloorPlanPlugin.Log.LogWarning((object)"[UpperLevels] FloorPlanLevels is 2+ but FloorPlanFileLevel2 is empty. Level 2 placement skipped."); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: FloorPlanLevels is 2+, but FloorPlanFileLevel2 is not set."); } else if (TryLoadValidatedAdditionalLevelPlan("FloorPlanFileLevel2", level2Path, l1MinCol, l1MaxColExclusive, l1MinRow, l1MaxRowExclusive, out level2Plan)) { yield return ((MonoBehaviour)this).StartCoroutine(PlaceUpperLevelPieces(level2Plan, level1Plan, origin, rotationDeg, 2, blockedChimneyShaftOpenings, blockedStaircaseShaftOpenings)); } } if (configuredLevels >= 3) { FloorPlan level3Plan; if (string.IsNullOrEmpty(level3Path)) { ValheimFloorPlanPlugin.Log.LogWarning((object)"[UpperLevels] FloorPlanLevels is 3 but FloorPlanFileLevel3 is empty. Level 3 placement skipped."); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: FloorPlanLevels is 3, but FloorPlanFileLevel3 is not set."); } else if (TryLoadValidatedAdditionalLevelPlan("FloorPlanFileLevel3", level3Path, l1MinCol, l1MaxColExclusive, l1MinRow, l1MaxRowExclusive, out level3Plan)) { yield return ((MonoBehaviour)this).StartCoroutine(PlaceUpperLevelPieces(level3Plan, level1Plan, origin, rotationDeg, 3, blockedChimneyShaftOpenings, blockedStaircaseShaftOpenings)); } } } private bool TryLoadValidatedAdditionalLevelPlan(string configKey, string path, int l1MinCol, int l1MaxColExclusive, int l1MinRow, int l1MaxRowExclusive, out FloorPlan? levelPlan) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) levelPlan = null; string text = (path ?? string.Empty).Trim(); if (string.IsNullOrEmpty(text)) { return false; } try { levelPlan = FloorPlan.Load(text); } catch (Exception ex) { ValheimFloorPlanPlugin.Log.LogError((object)("[" + configKey + "] Failed to load '" + text + "': " + ex.Message)); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: " + configKey + " could not be loaded. " + Path.GetFileName(text) + " (" + ex.Message + ")"); return false; } GetPlanPieceBounds(levelPlan, out var minCol, out var maxColExclusive, out var minRow, out var maxRowExclusive); if (minCol < l1MinCol || maxColExclusive > l1MaxColExclusive || minRow < l1MinRow || maxRowExclusive > l1MaxRowExclusive) { ValheimFloorPlanPlugin.Log.LogWarning((object)("[" + configKey + "] Footprint must fit inside Level 1 footprint. " + $"Level1=[col {l1MinCol}..{l1MaxColExclusive}, row {l1MinRow}..{l1MaxRowExclusive}] " + $"Candidate=[col {minCol}..{maxColExclusive}, row {minRow}..{maxRowExclusive}] " + "Path='" + text + "'")); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, "ValheimFloorPlan: " + configKey + " footprint must fit inside Level 1 plan."); levelPlan = null; return false; } return true; } private IEnumerator PlaceUpperLevelPieces(FloorPlan upperPlan, FloorPlan level1Plan, Vector3 origin, float rotationDeg, int targetLevelNumber, List<HearthOpening> blockedChimneyShaftOpenings, List<HearthOpening> blockedStaircaseShaftOpenings) { //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) int floorIndex = targetLevelNumber - 2; int scaffoldLevels = Mathf.Clamp(ValheimFloorPlanPlugin.ScaffoldingLevels, 1, 3); if (floorIndex < 0 || floorIndex >= scaffoldLevels) { ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber} layout provided but ScaffoldingLevels={scaffoldLevels} does not provide that floor. Skipped."); ValheimFloorPlanPlugin.ShowWrappedMessage(ValheimFloorPlanPlugin.WarningMessageType, $"ValheimFloorPlan: Level {targetLevelNumber} layout skipped because matching scaffold floor is not available."); yield break; } float levelDeckY = GetDeckYForScaffoldLevel(floorIndex); bool useWoodStructure = ValheimFloorPlanPlugin.WallPillarMaterial == ValheimFloorPlanPlugin.StructuralMaterial.Wood; int layoutLevelIndex = Mathf.Clamp(targetLevelNumber - 1, 0, 2); int configuredExternalWallHeight = ValheimFloorPlanPlugin.GetExternalWallHeightForLevel(layoutLevelIndex); GetPlanPieceBounds(level1Plan, out var minCol, out var maxColExclusive, out var minRow, out var maxRowExclusive); int total = upperPlan.Pieces.Count; int placed = 0; int skipped = 0; int skippedPerimeterRule = 0; int skippedStaircaseOverlap = 0; int skippedStaircaseFurnitureOverlap = 0; int skippedStaircaseBuildFailed = 0; int skippedStaircaseReachMode = 0; int skippedChimneyShaftOverlap = 0; int skippedStaircaseShaftOverlap = 0; int skippedHearthPerimeterBuffer = 0; int skippedHearthLowerOverlap = 0; int skippedHearthSpacing = 0; int skippedHearthFurnitureOverlap = 0; int skippedFurnitureShaftOverlap = 0; List<HearthOpening> blockedUpperHearthOpenings = new List<HearthOpening>(); List<HearthOpening> blockedUpperFurnitureOpenings = new List<HearthOpening>(); List<HearthOpening> upperHearthPlacementHistory = new List<HearthOpening>(); List<HearthOpening> placedUpperHearthOpenings = new List<HearthOpening>(); List<string> clashReportLines = new List<string>(); List<FloorPlanPiece> orderedPieces = new List<FloorPlanPiece>(upperPlan.Pieces.Count); for (int i = 0; i < upperPlan.Pieces.Count; i++) { FloorPlanPiece p = upperPlan.Pieces[i]; if (p.Type == "Staircase") { orderedPieces.Add(p); } } for (int j = 0; j < upperPlan.Pieces.Count; j++) { FloorPlanPiece p2 = upperPlan.Pieces[j]; if (p2.Type == "Hearth") { orderedPieces.Add(p2); } } for (int k = 0; k < upperPlan.Pieces.Count; k++) { FloorPlanPiece p3 = upperPlan.Pieces[k]; if (p3.Type != "Staircase" && p3.Type != "Hearth") { orderedPieces.Add(p3); } } ShowBuildProgress($"Placing Level {targetLevelNumber} pieces... 0/{total}"); foreach (FloorPlanPiece piece in orderedPieces) { PieceDef def = PieceMap.GetDef(piece.Type); if (def == null) { skipped++; continue; } if (piece.Type == "Floor2x2" || piece.Type == "Floor1x1") { skipped++; continue; } int effectivePieceRotation = piece.Rotation; int effW = def.EffW(effectivePieceRotation); int effH = def.EffH(effectivePieceRotation); int pieceMaxColExclusive = piece.Col + effW; int pieceMaxRowExclusive = piece.Row + effH; if (DoesFootprintOverlapAnyOpening(piece.Col, piece.Row, pieceMaxColExclusive, pieceMaxRowExclusive, blockedChimneyShaftOpenings)) { HearthOpening overlap = FindFirstOverlappingOpening(piece.Col, piece.Row, pieceMaxColExclusive, pieceMaxRowExclusive, blockedChimneyShaftOpenings, 0); string overlapLabel = DescribeHearthOpening(overlap); ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber}: piece '{piece.Type}' at ({piece.Col},{piece.Row}) overlaps chimney shaft {overlapLabel} and was skipped."); clashReportLines.Add($"{piece.Type} ({piece.Col},{piece.Row}) vs shaft {overlapLabel}"); skippedChimneyShaftOverlap++; skipped++; continue; } List<HearthOpening> applicableStairShaftOpenings = GetApplicableStaircaseShaftOpenings(blockedStaircaseShaftOpenings, targetLevelNumber); if (DoesFootprintOverlapAnyOpening(piece.Col, piece.Row, pieceMaxColExclusive, pieceMaxRowExclusive, applicableStairShaftOpenings)) { HearthOpening overlap2 = FindFirstOverlappingOpening(piece.Col, piece.Row, pieceMaxColExclusive, pieceMaxRowExclusive, applicableStairShaftOpenings, 0); string overlapLabel2 = DescribeHearthOpening(overlap2); ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber}: piece '{piece.Type}' at ({piece.Col},{piece.Row}) overlaps staircase shaft {overlapLabel2} and was skipped."); clashReportLines.Add($"{piece.Type} ({piece.Col},{piece.Row}) vs stair-shaft {overlapLabel2}"); skippedStaircaseShaftOverlap++; skipped++; continue; } bool isExternal = IsOnPlanOuterPerimeter(piece.Col, piece.Row, effW, effH, minCol, maxColExclusive, minRow, maxRowExclusive); bool allowPerimeterPlacement = piece.Type == "Wall" || piece.Type == "Pillar" || piece.Type == "Doorway"; if (isExternal && !allowPerimeterPlacement) { ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber}: piece '{piece.Type}' at ({piece.Col},{piece.Row}) touches Level 1 outer perimeter and was skipped (internal-only rule)."); skippedPerimeterRule++; skipped++; continue; } if (piece.Type == "Staircase") { int stairMaxColExclusive = piece.Col + effW; int stairMaxRowExclusive = piece.Row + effH; if (DoesFootprintOverlapAnyOpening(piece.Col, piece.Row, stairMaxColExclusive, stairMaxRowExclusive, blockedUpperFurnitureOpenings)) { HearthOpening furnitureOverlap = FindFirstOverlappingOpening(piece.Col, piece.Row, stairMaxColExclusive, stairMaxRowExclusive, blockedUpperFurnitureOpenings, 0); ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber}: Staircase at ({piece.Col},{piece.Row}) overlaps furniture {DescribeHearthOpening(furnitureOverlap)} and was skipped."); clashReportLines.Add($"Stair ({piece.Col},{piece.Row}) vs {DescribeHearthOpening(furnitureOverlap)}"); skippedStaircaseFurnitureOverlap++; skipped++; continue; } if (DoesFootprintOverlapAnyOpening(piece.Col, piece.Row, stairMaxColExclusive, stairMaxRowExclusive, blockedUpperHearthOpenings)) { HearthOpening overlap3 = FindFirstOverlappingOpening(piece.Col, piece.Row, stairMaxColExclusive, stairMaxRowExclusive, blockedUpperHearthOpenings, 0); string overlapLabel3 = DescribeHearthOpening(overlap3); ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber}: Staircase at ({piece.Col},{piece.Row}) overlaps {overlapLabel3} and was skipped."); clashReportLines.Add($"Stair ({piece.Col},{piece.Row}) vs {overlapLabel3}"); skippedStaircaseOverlap++; skipped++; continue; } float staircaseTargetTopY = GetUpperLevelStaircaseTargetTopY(levelDeckY, floorIndex, scaffoldLevels); if (staircaseTargetTopY <= levelDeckY + 0.01f) { ValheimFloorPlanPlugin.Log.LogWarning((object)$"[UpperLevels] Level {targetLevelNumber}: Staircase at ({piece.Col},{piece.Row}) skipped by StaircaseReachMode={ValheimFloorPlanPlugin.StaircaseReachMode} (no higher scaffold level available)."); clashReportLines.Add($"Stair ({piece.Col},{piece.Row}) blocked by StaircaseReachMode={ValheimFloorPlanPlugin.StaircaseReachMode}"); skippedStaircaseReachMode++; skipped++; continue; } int staircasePlaced = PlaceStaircaseComposite(piece, def, origin, rotationDeg, "woodiron_pole", "wood_beam", 2f, Player.m_localPlayer, levelDeckY, staircaseTargetTopY); if (staircasePlaced <= 0) { skippedStaircaseBuildFailed++; skipped++; continue; } placed += staircasePlaced; HearthOpening staircaseOpenin