using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using Dawn; using DunGen; using DunGen.Graph; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using Y4NGZCompany.Facility.Cameras.Placement; using Y4NGZCompany.Facility.Interior.Placement.Authored; using Y4NGZCore; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("Y4NGZCompany")] [assembly: InternalsVisibleTo("LethalCCTV")] [assembly: InternalsVisibleTo("Y4NGZBloodFX")] [assembly: InternalsVisibleTo("Y4NGZAtmosphere")] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("DunGen")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")] [assembly: IgnoresAccessChecksTo("Unity.XR.Management")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZCore")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Shared Y4NGZ runtime services consumed by the other Y4NGZ plugin assemblies")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+94d3a829a505ef9557dc44e52b76374a6a8f3a82")] [assembly: AssemblyProduct("Y4NGZCore")] [assembly: AssemblyTitle("Y4NGZCore")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.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 Y4NGZCompany.ShipSystems { public static class ShipClock24h { public const string UnavailableText = "--:--"; public static string GetShipTime24h() { TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null) { return "--:--"; } StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)instance2 != (Object)null && instance2.inShipPhase) { return "--:--"; } int num = (int)(instance.normalizedTimeOfDay * (60f * (float)instance.numberOfHours)) + 360; if (num < 0) { return "--:--"; } int num2 = num / 60; int num3 = num % 60; if (num2 >= 24) { return "00:00"; } return $"{num2:00}:{num3:00}"; } } } namespace Y4NGZCompany.ShipSystems.Rendering { internal enum OffscreenRigSlot { PowerFuel, MonitorRowCard, QuotaAnnouncement, ProfitQuotaPanel, DeadlinePanel, CctvVanillaMonitor } internal readonly struct OffscreenRigPlacement { internal string Name { get; } internal float CenterX { get; } internal float CenterY { get; } internal float HalfWidth { get; } internal float HalfHeight { get; } internal OffscreenRigPlacement(string name, float centerX, float centerY, float halfWidth, float halfHeight) { Name = name; CenterX = centerX; CenterY = centerY; HalfWidth = halfWidth; HalfHeight = halfHeight; } } internal static class OffscreenRigParking { internal const float ParkingHeight = -10000f; internal const float SlotOrigin = 8192f; internal const float SlotPitch = 4096f; internal const float MinimumClearance = 1024f; internal const float MaxHalfExtent = 1536f; internal static float SlotX(OffscreenRigSlot slot) { return 8192f + (float)slot * 4096f; } internal static bool Fits(float extentFromRootX, float extentFromRootY) { if (extentFromRootX > 0f && extentFromRootY > 0f && extentFromRootX <= 1536f) { return extentFromRootY <= 1536f; } return false; } internal static OffscreenRigPlacement[] CurrentPlacements() { return new OffscreenRigPlacement[6] { Place(OffscreenRigSlot.PowerFuel, 256f, 192f), Place(OffscreenRigSlot.MonitorRowCard, 416f, 96f), Place(OffscreenRigSlot.QuotaAnnouncement, 384f, 216f), Place(OffscreenRigSlot.ProfitQuotaPanel, 256f, 192f), Place(OffscreenRigSlot.DeadlinePanel, 256f, 192f), Place(OffscreenRigSlot.CctvVanillaMonitor, 1408f, 216f) }; } private static OffscreenRigPlacement Place(OffscreenRigSlot slot, float halfWidth, float halfHeight) { return new OffscreenRigPlacement(slot.ToString(), SlotX(slot), -10000f, halfWidth, halfHeight); } internal static bool TryFindConflict(IReadOnlyList placements, float minimumClearance, out string detail) { detail = null; if (placements == null) { return false; } for (int i = 0; i < placements.Count; i++) { for (int j = i + 1; j < placements.Count; j++) { OffscreenRigPlacement offscreenRigPlacement = placements[i]; OffscreenRigPlacement offscreenRigPlacement2 = placements[j]; float num = offscreenRigPlacement.HalfWidth + offscreenRigPlacement2.HalfWidth + minimumClearance; float num2 = offscreenRigPlacement.HalfHeight + offscreenRigPlacement2.HalfHeight + minimumClearance; float num3 = Math.Abs(offscreenRigPlacement.CenterX - offscreenRigPlacement2.CenterX); float num4 = Math.Abs(offscreenRigPlacement.CenterY - offscreenRigPlacement2.CenterY); if (!(num3 >= num) && !(num4 >= num2)) { detail = "'" + offscreenRigPlacement.Name + "' and '" + offscreenRigPlacement2.Name + "' are not separated: " + $"x gap {num3:0.###} needs {num:0.###}, " + $"y gap {num4:0.###} needs {num2:0.###}"; return true; } } } return false; } } } namespace Y4NGZCompany.Facility.Stash { public enum CompanyStashKeypadDisplayState { Normal, Denied, Granted } public sealed class CompanyStashKeypadInteractor : MonoBehaviour { public const int EnterButton = -1; private const int InteractLayer = 9; private const float RefreshInterval = 0.2f; private const float ButtonPressDistance = 0.0025f; private const float ButtonPressDuration = 0.1f; private const float ButtonReturnDuration = 0.1f; public static Func BundledAudioClipProvider; private readonly List _buttons = new List(11); private readonly Dictionary _buttonAnimations = new Dictionary(); private TMP_Text _displayText; private Renderer _displayRenderer; private AudioSource _audioSource; private AudioClip _clickClip; private AudioClip _deniedClip; private AudioClip _grantedClip; private bool _built; private float _nextRefreshAt; private bool _warnedMissingButtonVisuals; private static readonly Color NormalColor = new Color(0.98f, 0.5f, 0.032f, 1f); private static readonly Color DeniedColor = new Color(1f, 0.04f, 0.02f, 1f); private static readonly Color GrantedColor = new Color(0.08f, 0.72f, 0.14f, 1f); public ICompanyStashKeypadClient Client { get; private set; } internal int BuiltButtonCount => _buttons.Count; private void Awake() { ResolveOwner(); EnsureBuilt(); } private void Start() { ResolveOwner(); EnsureBuilt(); RefreshButtons(); } private void Update() { ResolveOwner(); EnsureBuilt(); HandleKeyboardEnterSubmit(); if (!(Time.time < _nextRefreshAt)) { _nextRefreshAt = Time.time + 0.2f; RefreshButtons(); } } internal void EnsureBuilt() { if (!_built) { DisableDemoKeypadBehaviours(); ResolveDisplay(); ResolveAudio(); BuildButtonInteractions(); _built = true; } } internal void RefreshButtons() { for (int i = 0; i < _buttons.Count; i++) { _buttons[i]?.RefreshState(); } } internal void RequestButtonPress(int button, PlayerControllerB player, Transform visual) { ResolveOwner(); ICompanyStashKeypadClient client = Client; if (client != null) { if (!client.IsKeypadInteractable()) { SetDisplayText(client.GetKeypadLockedDisplayText(), client.GetKeypadLockedDisplayState()); RefreshButtons(); return; } PlayClick(); AnimateButton(visual); client.PressKeypadButtonLocally(button, player); RefreshButtons(); } } internal string GetButtonTip(int button) { ResolveOwner(); if (Client == null) { return ButtonLabel(button); } return Client.GetKeypadButtonTip(button); } internal string GetDisabledTip() { ResolveOwner(); if (Client == null) { return "[ Keypad unavailable ]"; } return Client.GetKeypadDisabledTip(); } internal bool IsButtonInteractable() { ResolveOwner(); if (Client != null) { return Client.IsKeypadInteractable(); } return false; } internal void SetDisplayText(string text, CompanyStashKeypadDisplayState state) { //IL_002a: 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_0044: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) ResolveDisplay(); if ((Object)(object)_displayText != (Object)null) { _displayText.text = text ?? string.Empty; } Color displayColor = GetDisplayColor(state); if ((Object)(object)_displayText != (Object)null) { ((Graphic)_displayText).color = displayColor; } if ((Object)(object)_displayRenderer != (Object)null) { Material material = _displayRenderer.material; if ((Object)(object)material != (Object)null) { if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", displayColor * 2.4f); } if (material.HasProperty("_EmissiveColor")) { material.SetColor("_EmissiveColor", displayColor * 2.4f); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", displayColor); } if (material.HasProperty("_Color")) { material.SetColor("_Color", displayColor); } } } switch (state) { case CompanyStashKeypadDisplayState.Denied: PlayDenied(); break; case CompanyStashKeypadDisplayState.Granted: PlayGranted(); break; } } private void ResolveOwner() { if (Client == null) { Client = ((Component)this).GetComponentInParent() ?? ((Component)this).GetComponent(); } } private void ResolveDisplay() { if ((Object)(object)_displayText == (Object)null) { _displayText = ((Component)this).GetComponentInChildren(true); } if ((Object)(object)_displayRenderer == (Object)null) { Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { string transformPath = GetTransformPath(((Component)val).transform); if (transformPath.IndexOf("display", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("screen", StringComparison.OrdinalIgnoreCase) >= 0) { _displayRenderer = val; break; } } } } if ((Object)(object)_displayText == (Object)null && Client != null && Client.AllowsFallbackDisplayText) { _displayText = CreateFallbackDisplayText(); } } private void ResolveAudio() { if ((Object)(object)_audioSource == (Object)null) { _audioSource = ((Component)this).GetComponentInChildren(true); if ((Object)(object)_audioSource == (Object)null) { _audioSource = ((Component)this).gameObject.AddComponent(); } _audioSource.playOnAwake = false; _audioSource.spatialBlend = 1f; _audioSource.rolloffMode = (AudioRolloffMode)1; _audioSource.volume = 0.72f; _audioSource.minDistance = 1.5f; _audioSource.maxDistance = 14f; } _clickClip = _clickClip ?? LoadKeypadClip("sfx_keypadClick", "sfx_keypadClick.wav"); _deniedClip = _deniedClip ?? LoadKeypadClip("sfx_keypadDeniedd", "sfx_keypadDeniedd.wav"); _grantedClip = _grantedClip ?? LoadKeypadClip("sfx_keypadGranted", "sfx_keypadGranted.wav"); } private static AudioClip LoadKeypadClip(params string[] names) { Func bundledAudioClipProvider = BundledAudioClipProvider; if (bundledAudioClipProvider == null) { return null; } try { return bundledAudioClipProvider(names); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Keypad] Audio clip provider failed for '" + string.Join("/", names) + "': " + ex.Message)); } return null; } } private void BuildButtonInteractions() { _buttons.Clear(); for (int i = 0; i <= 9; i++) { BuildButtonInteraction(i); } BuildButtonInteraction(-1); } private void BuildButtonInteraction(int button) { Transform val = FindButtonVisual(button); if ((Object)(object)val == (Object)null && Client != null && !Client.AllowsFallbackButtonVisuals) { if (_warnedMissingButtonVisuals) { return; } _warnedMissingButtonVisuals = true; string missingButtonVisualsWarning = Client.MissingButtonVisualsWarning; if (!string.IsNullOrEmpty(missingButtonVisualsWarning)) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)missingButtonVisualsWarning); } } return; } if ((Object)(object)val == (Object)null) { val = CreateFallbackButtonVisual(button); } GameObject val2 = FindOrCreateTriggerChild(val, "CompanyStash_KeypadButton_" + ButtonObjectName(button) + "_Interact"); ConfigureTriggerCollider(val2, val, button); CompanyStashKeypadButton companyStashKeypadButton = val2.GetComponent(); if ((Object)(object)companyStashKeypadButton == (Object)null) { companyStashKeypadButton = val2.AddComponent(); } companyStashKeypadButton.Owner = this; companyStashKeypadButton.Button = button; companyStashKeypadButton.Visual = val; companyStashKeypadButton.ConfigureTrigger(); _buttons.Add(companyStashKeypadButton); } private Transform FindButtonVisual(int button) { Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); string[] array = ((button != -1) ? new string[4] { $"bttn{button}", $"button{button}", $"key{button}", button.ToString() } : new string[11] { "bttnEnter", "bttn10", "buttonEnter", "button10", "keyEnter", "key10", "Enter", "Submit", "Confirm", "Return", "OK" }); foreach (Transform val in componentsInChildren) { if (!IsUsableButtonVisual(val)) { continue; } string name = ((Object)val).name ?? string.Empty; for (int j = 0; j < array.Length; j++) { if (IsExactOrPrefixedButtonName(name, array[j])) { return val; } } } foreach (Transform val2 in componentsInChildren) { if (!IsUsableButtonVisual(val2)) { continue; } string name2 = ((Object)val2).name ?? string.Empty; if (button == -1) { if (IsEnterButtonName(name2)) { return val2; } } else if (IsDigitButtonName(name2, button)) { return val2; } } return null; } private static bool IsUsableButtonVisual(Transform candidate) { if ((Object)(object)candidate == (Object)null) { return false; } string transformPath = GetTransformPath(candidate); if (transformPath.IndexOf("Interact", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("Trigger", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("Fallback", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("DD_Wire", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("DD_KeypadTerminal", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("DD_Detonator", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("DD_Display", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("DD_Marking", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("Socket", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (!((Object)(object)((Component)candidate).GetComponent() != (Object)null)) { return ((Component)candidate).GetComponentsInChildren(true).Length != 0; } return true; } private static bool IsExactOrPrefixedButtonName(string name, string exactName) { if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(exactName)) { return false; } if (string.Equals(name, exactName, StringComparison.OrdinalIgnoreCase)) { return true; } if (!name.EndsWith("_" + exactName, StringComparison.OrdinalIgnoreCase) && !name.EndsWith("-" + exactName, StringComparison.OrdinalIgnoreCase)) { return name.EndsWith("." + exactName, StringComparison.OrdinalIgnoreCase); } return true; } private void HandleKeyboardEnterSubmit() { Keyboard current = Keyboard.current; if (current == null || (!((ButtonControl)current.enterKey).wasPressedThisFrame && !((ButtonControl)current.numpadEnterKey).wasPressedThisFrame)) { return; } ResolveOwner(); ICompanyStashKeypadClient client = Client; bool num = client?.HasLocalKeypadInput ?? false; bool flag = client?.IsKeypadInteractable() ?? false; if (num && flag) { PlayerControllerB player = GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; if (CanLocalPlayerSubmitKeyboardEnter(player)) { RequestButtonPress(-1, player, FindButtonVisual(-1)); } } } private TMP_Text CreateFallbackDisplayText() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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_00f9: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Renderer val = _displayRenderer ?? FindPanelRenderer(); if ((Object)(object)val == (Object)null) { return null; } GameObject val2 = new GameObject("DisplayCanvas"); val2.transform.SetParent(((Component)val).transform, false); Bounds val3 = CalculateRendererLocalBounds(((Component)val).transform, val); int num = SmallestAxis(((Bounds)(ref val3)).size); Vector3 val4 = AxisVector(num); Vector3 extents = ((Bounds)(ref val3)).extents; float num2 = num switch { 1 => extents.y, 0 => extents.x, _ => extents.z, }; val2.transform.localPosition = ((Bounds)(ref val3)).center + val4 * (num2 + 0.001f); val2.transform.localRotation = Quaternion.FromToRotation(Vector3.forward, val4); val2.transform.localScale = Vector3.one * 0.018f; GameObject val5 = new GameObject("DisplayText"); val5.transform.SetParent(val2.transform, false); val5.transform.localPosition = Vector3.zero; val5.transform.localRotation = Quaternion.identity; val5.transform.localScale = Vector3.one; TextMeshPro obj = val5.AddComponent(); ((TMP_Text)obj).text = "_ _ _ _"; ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj).enableWordWrapping = false; ((TMP_Text)obj).enableAutoSizing = true; ((TMP_Text)obj).fontSizeMin = 0.18f; ((TMP_Text)obj).fontSizeMax = 0.85f; ((Graphic)obj).color = NormalColor; ((TMP_Text)obj).rectTransform.sizeDelta = new Vector2(5.4f, 1.3f); return (TMP_Text)(object)obj; } private Renderer FindPanelRenderer() { Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { string transformPath = GetTransformPath(((Component)val).transform); if (transformPath.IndexOf("panel", StringComparison.OrdinalIgnoreCase) >= 0 || transformPath.IndexOf("keypad", StringComparison.OrdinalIgnoreCase) >= 0) { return val; } } } return null; } private bool CanLocalPlayerSubmitKeyboardEnter(PlayerControllerB player) { //IL_0062: 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_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } if (player.inTerminalMenu) { return false; } if ((Object)(object)player.quickMenuManager != (Object)null && player.quickMenuManager.isMenuOpen) { return false; } if (player.isTypingChat) { return false; } return Vector3.Distance(((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.position : ((Component)player).transform.position, ((Component)this).transform.position) <= 4f; } private static bool IsEnterButtonName(string name) { if (string.IsNullOrWhiteSpace(name)) { return false; } string text = name.ToLowerInvariant(); if (text.Contains("enter") || text.Contains("submit") || text.Contains("confirm") || text.Contains("return")) { return true; } if (text == "ok" || text.EndsWith("_ok") || text.EndsWith("-ok")) { return true; } if (text.Contains("10")) { if (!text.Contains("bttn") && !text.Contains("button")) { return text.Contains("key"); } return true; } return false; } private static bool IsDigitButtonName(string name, int digit) { if (string.IsNullOrWhiteSpace(name)) { return false; } string value = Mathf.Clamp(digit, 0, 9).ToString(); string text = name.ToLowerInvariant(); if (text.Contains(value)) { if (!text.Contains("bttn") && !text.Contains("button")) { return text.Contains("key"); } return true; } return false; } private Transform CreateFallbackButtonVisual(int button) { //IL_0040: 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_0089: 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) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = ((button == -1) ? "bttnEnter" : $"bttn{button}"); obj.transform.SetParent(((Component)this).transform, false); obj.transform.localPosition = EstimateFallbackButtonPosition(button); obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = ((button == -1) ? new Vector3(0.13f, 0.035f, 0.045f) : new Vector3(0.045f, 0.035f, 0.045f)); Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } return obj.transform; } private static Vector3 EstimateFallbackButtonPosition(int button) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) int num; switch (button) { case -1: return new Vector3(0.055f, 0.73f, 0.435f); default: num = button - 1; break; case 0: num = 10; break; } int num2 = num / 3; return new Vector3((float)(num % 3 - 1) * 0.055f, 0.92f - (float)num2 * 0.06f, 0.435f); } private static GameObject FindOrCreateTriggerChild(Transform visual, string name) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)visual != (Object)null) ? visual.Find(name) : null); GameObject val2 = (GameObject)(((Object)(object)val != (Object)null) ? ((object)((Component)val).gameObject) : ((object)new GameObject(name))); if ((Object)(object)visual != (Object)null) { val2.transform.SetParent(visual, false); } val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; return val2; } private static void ConfigureTriggerCollider(GameObject triggerObject, Transform visual, int button) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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) triggerObject.layer = ResolveLayer("InteractableObject", 9); SetTagSafe(triggerObject, "InteractTrigger"); BoxCollider val = triggerObject.GetComponent(); if ((Object)(object)val == (Object)null) { val = triggerObject.AddComponent(); } ((Collider)val).isTrigger = true; Bounds val2 = CalculateButtonColliderBounds(visual); if (button == -1) { ((Bounds)(ref val2)).size = new Vector3(ExpandLocalColliderAxis(((Bounds)(ref val2)).size.x, 2f, 0.002f), ExpandLocalColliderAxis(((Bounds)(ref val2)).size.y, 2f, 0.002f), ExpandLocalColliderAxis(((Bounds)(ref val2)).size.z, 2.5f, 0.002f)); } val.center = ((Bounds)(ref val2)).center; val.size = ((Bounds)(ref val2)).size; } private static Bounds CalculateButtonColliderBounds(Transform visual) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_028a: 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_0218: 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_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_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_00b2: 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_00c0: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_0157: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: 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_0192: 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_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: 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) if ((Object)(object)visual == (Object)null) { return new Bounds(Vector3.zero, new Vector3(0.006f, 0.006f, 0.004f)); } Renderer[] componentsInChildren = ((Component)visual).GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return new Bounds(Vector3.zero, new Vector3(0.006f, 0.006f, 0.004f)); } bool flag = false; Bounds result = default(Bounds); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Mesh rendererMesh = GetRendererMesh(val); if ((Object)(object)rendererMesh == (Object)null) { continue; } Bounds bounds = rendererMesh.bounds; Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; Vector3[] array = (Vector3[])(object)new Vector3[8] { new Vector3(min.x, min.y, min.z), new Vector3(max.x, min.y, min.z), new Vector3(min.x, max.y, min.z), new Vector3(max.x, max.y, min.z), new Vector3(min.x, min.y, max.z), new Vector3(max.x, min.y, max.z), new Vector3(min.x, max.y, max.z), new Vector3(max.x, max.y, max.z) }; for (int j = 0; j < array.Length; j++) { Vector3 val2 = visual.InverseTransformPoint(((Component)val).transform.TransformPoint(array[j])); if (!flag) { ((Bounds)(ref result))..ctor(val2, Vector3.zero); flag = true; } else { ((Bounds)(ref result)).Encapsulate(val2); } } } if (!flag) { return new Bounds(Vector3.zero, new Vector3(0.006f, 0.006f, 0.004f)); } ((Bounds)(ref result)).size = new Vector3(ExpandLocalColliderAxis(((Bounds)(ref result)).size.x, 1.45f, 0.0005f), ExpandLocalColliderAxis(((Bounds)(ref result)).size.y, 1.45f, 0.0005f), ExpandLocalColliderAxis(((Bounds)(ref result)).size.z, 2.25f, 0.0015f)); return result; } private static Bounds CalculateRendererLocalBounds(Transform localRoot, Renderer renderer) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0104: 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) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: 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_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_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_019c: 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_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)localRoot == (Object)null || (Object)(object)renderer == (Object)null) { return new Bounds(Vector3.zero, Vector3.one * 0.01f); } Mesh rendererMesh = GetRendererMesh(renderer); if ((Object)(object)rendererMesh == (Object)null) { return new Bounds(Vector3.zero, Vector3.one * 0.01f); } Bounds bounds = rendererMesh.bounds; Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; Vector3[] array = (Vector3[])(object)new Vector3[8] { new Vector3(min.x, min.y, min.z), new Vector3(max.x, min.y, min.z), new Vector3(min.x, max.y, min.z), new Vector3(max.x, max.y, min.z), new Vector3(min.x, min.y, max.z), new Vector3(max.x, min.y, max.z), new Vector3(min.x, max.y, max.z), new Vector3(max.x, max.y, max.z) }; Bounds result = default(Bounds); ((Bounds)(ref result))..ctor(localRoot.InverseTransformPoint(((Component)renderer).transform.TransformPoint(array[0])), Vector3.zero); for (int i = 1; i < array.Length; i++) { ((Bounds)(ref result)).Encapsulate(localRoot.InverseTransformPoint(((Component)renderer).transform.TransformPoint(array[i]))); } return result; } private static int SmallestAxis(Vector3 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (size.x <= size.y && size.x <= size.z) { return 0; } if (size.y <= size.x && size.y <= size.z) { return 1; } return 2; } private static Vector3 AxisVector(int axis) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return (Vector3)(axis switch { 0 => Vector3.right, 1 => Vector3.up, _ => Vector3.forward, }); } private static Mesh GetRendererMesh(Renderer renderer) { if ((Object)(object)renderer == (Object)null) { return null; } MeshFilter component = ((Component)renderer).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { return component.sharedMesh; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.sharedMesh; } private static float ExpandLocalColliderAxis(float size, float multiplier, float padding) { if (size <= 1E-05f) { return padding; } return Mathf.Max(size * multiplier, size + padding); } private void AnimateButton(Transform visual) { if (!((Object)(object)visual == (Object)null)) { if (_buttonAnimations.TryGetValue(visual, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _buttonAnimations[visual] = ((MonoBehaviour)this).StartCoroutine(AnimateButtonRoutine(visual)); } } private IEnumerator AnimateButtonRoutine(Transform visual) { Vector3 start = visual.localPosition; Vector3 pressed = start + new Vector3(0f, 0f, 0.0025f); float elapsed = 0f; while (elapsed < 0.1f) { elapsed += Time.deltaTime; visual.localPosition = Vector3.Lerp(start, pressed, Mathf.Clamp01(elapsed / 0.1f)); yield return null; } visual.localPosition = pressed; elapsed = 0f; while (elapsed < 0.1f) { elapsed += Time.deltaTime; visual.localPosition = Vector3.Lerp(pressed, start, Mathf.Clamp01(elapsed / 0.1f)); yield return null; } visual.localPosition = start; _buttonAnimations.Remove(visual); } private void DisableDemoKeypadBehaviours() { MonoBehaviour[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (MonoBehaviour val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { string a = ((object)val).GetType().FullName ?? string.Empty; if (string.Equals(a, "NavKeypad.Keypad", StringComparison.Ordinal) || string.Equals(a, "NavKeypad.KeypadInteractionFPV", StringComparison.Ordinal)) { ((Behaviour)val).enabled = false; } } } } private void PlayClick() { PlayOneShot(_clickClip, 0.62f); } private void PlayDenied() { PlayOneShot(_deniedClip, 0.75f); } private void PlayGranted() { PlayOneShot(_grantedClip, 0.8f); } private void PlayOneShot(AudioClip clip, float volume) { ResolveAudio(); if ((Object)(object)_audioSource != (Object)null && (Object)(object)clip != (Object)null) { _audioSource.PlayOneShot(clip, volume); } } private static Color GetDisplayColor(CompanyStashKeypadDisplayState state) { //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_0016: Unknown result type (might be due to invalid IL or missing references) return (Color)(state switch { CompanyStashKeypadDisplayState.Denied => DeniedColor, CompanyStashKeypadDisplayState.Granted => GrantedColor, _ => NormalColor, }); } private static string ButtonLabel(int button) { if (button != -1) { return $"Press [{Mathf.Clamp(button, 0, 9)}]"; } return "Press [Enter]"; } private static string ButtonObjectName(int button) { if (button != -1) { return button.ToString(); } return "Enter"; } private static Bounds Encapsulate(Bounds a, Bounds b) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) ((Bounds)(ref a)).Encapsulate(((Bounds)(ref b)).min); ((Bounds)(ref a)).Encapsulate(((Bounds)(ref b)).max); return a; } private static string GetTransformPath(Transform transform) { if ((Object)(object)transform == (Object)null) { return string.Empty; } string text = ((Object)transform).name; Transform parent = transform.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private static int ResolveLayer(string name, int fallback) { int num = LayerMask.NameToLayer(name); if (num < 0) { return fallback; } return num; } private static void SetTagSafe(GameObject obj, string tag) { try { obj.tag = tag; } catch { obj.tag = "Untagged"; } } } public sealed class CompanyStashKeypadButton : MonoBehaviour { public CompanyStashKeypadInteractor Owner; public int Button; public Transform Visual; private InteractTrigger _trigger; private Collider _collider; internal void ConfigureTrigger() { _collider = ((Component)this).GetComponent(); _trigger = ((Component)this).GetComponent(); if ((Object)(object)_trigger == (Object)null) { _trigger = ((Component)this).gameObject.AddComponent(); } ConfigureCommonTrigger(_trigger); ((UnityEvent)(object)_trigger.onInteract).RemoveListener((UnityAction)OnInteract); ((UnityEvent)(object)_trigger.onInteract).AddListener((UnityAction)OnInteract); RefreshState(); } internal void RefreshState() { if (!((Object)(object)_trigger == (Object)null)) { bool interactable = (Object)(object)Owner != (Object)null && Owner.IsButtonInteractable(); _trigger.interactable = interactable; _trigger.hoverTip = (((Object)(object)Owner != (Object)null) ? Owner.GetButtonTip(Button) : "Press keypad"); _trigger.disabledHoverTip = (((Object)(object)Owner != (Object)null) ? Owner.GetDisabledTip() : "[ Keypad unavailable ]"); ApplyInteractionIcons(_trigger); if ((Object)(object)_collider != (Object)null) { _collider.enabled = true; } } } public void OnInteract(PlayerControllerB player) { Owner?.RequestButtonPress(Button, player, Visual); RefreshState(); } private static void ApplyInteractionIcons(InteractTrigger trigger) { if (!((Object)(object)trigger == (Object)null) && !((Object)(object)trigger.hoverIcon != (Object)null)) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; if (!((Object)(object)val?.grabItemIcon == (Object)null)) { trigger.hoverIcon = val.grabItemIcon; trigger.disabledHoverIcon = val.grabItemIcon; } } } private static void ConfigureCommonTrigger(InteractTrigger trigger) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown trigger.oneHandedItemAllowed = true; trigger.twoHandedItemAllowed = true; trigger.holdInteraction = false; trigger.timeToHold = 0.1f; trigger.timeToHoldSpeedMultiplier = 1f; trigger.interactCooldown = true; trigger.cooldownTime = 0.08f; trigger.disableTriggerMesh = true; ApplyInteractionIcons(trigger); if (trigger.onInteract == null) { trigger.onInteract = new InteractEvent(); } if (trigger.onInteractEarly == null) { trigger.onInteractEarly = new InteractEvent(); } if (trigger.onInteractEarlyOtherClients == null) { trigger.onInteractEarlyOtherClients = new InteractEvent(); } if (trigger.onStopInteract == null) { trigger.onStopInteract = new InteractEvent(); } if (trigger.onCancelAnimation == null) { trigger.onCancelAnimation = new InteractEvent(); } if (trigger.holdingInteractEvent == null) { trigger.holdingInteractEvent = new InteractEventFloat(); } } } public interface ICompanyStashKeypadClient { bool HasLocalKeypadInput { get; } bool AllowsFallbackDisplayText { get; } bool AllowsFallbackButtonVisuals { get; } string MissingButtonVisualsWarning { get; } bool IsKeypadInteractable(); string GetKeypadButtonTip(int button); string GetKeypadDisabledTip(); void PressKeypadButtonLocally(int button, PlayerControllerB player); string GetKeypadLockedDisplayText(); CompanyStashKeypadDisplayState GetKeypadLockedDisplayState(); } } namespace Y4NGZCompany.Facility.Shared { public static class FacilityAudioClipLoader { private const string AudioDirectory = "Audio"; private const string ContractAudioDirectory = "ContractAudio"; private static readonly string[] PackageDirectoryNames = new string[6] { "Y4NGZCore", "y4ngz-Y4NGZCore", "Y4NGZCompany", "y4ngz-Y4NGZCompany", "LethalCCTV", "y4ngz-LethalCCTV" }; private static readonly Dictionary Clips = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary>> Pending = new Dictionary>>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet Failed = new HashSet(StringComparer.OrdinalIgnoreCase); public static void Request(MonoBehaviour owner, string fileName, Action completed) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)owner == (Object)null || string.IsNullOrWhiteSpace(fileName)) { return; } if (Clips.TryGetValue(fileName, out var value) && (Object)(object)value != (Object)null) { completed?.Invoke(value); } else { if (Failed.Contains(fileName)) { return; } if (Pending.TryGetValue(fileName, out var value2)) { if (completed != null) { value2.Add(completed); } return; } string text = ResolvePath(fileName, ((object)owner).GetType().Assembly); if (string.IsNullOrEmpty(text)) { Failed.Add(fileName); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[LethalCCTV][Audio] Missing facility audio '" + fileName + "'.")); } return; } AudioType val = ResolveAudioType(text); if ((int)val == 0) { Failed.Add(fileName); ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)("[LethalCCTV][Audio] Unsupported facility audio extension '" + fileName + "'.")); } return; } value2 = new List>(); if (completed != null) { value2.Add(completed); } Pending[fileName] = value2; owner.StartCoroutine(Load(fileName, text, val)); } } private static IEnumerator Load(string fileName, string path, AudioType audioType) { //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) UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, audioType); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Failed.Add(fileName); Pending.Remove(fileName); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[LethalCCTV][Audio] Failed loading '" + fileName + "': " + request.error)); } yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { Failed.Add(fileName); Pending.Remove(fileName); ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)("[LethalCCTV][Audio] Decoded null clip '" + fileName + "'.")); } yield break; } ((Object)content).name = "Y4NGZ_" + Path.GetFileNameWithoutExtension(fileName); Clips[fileName] = content; if (Pending.TryGetValue(fileName, out var value)) { Pending.Remove(fileName); for (int i = 0; i < value.Count; i++) { try { value[i]?.Invoke(content); } catch (Exception ex) { ManualLogSource log3 = CoreDiagnostics.Log; if (log3 != null) { log3.LogWarning((object)("[LethalCCTV][Audio] Clip callback failed for '" + fileName + "': " + ex.Message)); } } } } ManualLogSource log4 = CoreDiagnostics.Log; if (log4 != null) { log4.LogInfo((object)$"[LethalCCTV][Audio] Loaded '{fileName}' as {audioType}."); } } finally { ((IDisposable)request)?.Dispose(); } } private static string ResolvePath(string fileName, Assembly requester) { string text = fileName.Replace('/', Path.DirectorySeparatorChar); foreach (string item in EnumerateRoots(requester)) { string text2 = Path.Combine(item, "Audio", text); if (File.Exists(text2)) { return text2; } string text3 = Path.Combine(item, "ContractAudio", text); if (File.Exists(text3)) { return text3; } string text4 = Path.Combine(item, text); if (File.Exists(text4)) { return text4; } } return null; } private static IEnumerable EnumerateRoots(Assembly requester) { HashSet seen = new HashSet(StringComparer.OrdinalIgnoreCase); List roots = new List(); Add(DirectoryOf(requester)); Add(DirectoryOf(typeof(FacilityAudioClipLoader).Assembly)); string text = null; try { text = Paths.PluginPath; } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZCore][Audio] Plugin root resolve failed: " + ex.Message)); } } if (!string.IsNullOrEmpty(text)) { for (int i = 0; i < PackageDirectoryNames.Length; i++) { string text2 = Path.Combine(text, PackageDirectoryNames[i]); if (Directory.Exists(text2)) { Add(text2); } } } return roots; void Add(string candidate) { if (!string.IsNullOrEmpty(candidate) && seen.Add(candidate)) { roots.Add(candidate); } } } private static string DirectoryOf(Assembly assembly) { if (assembly == null) { return null; } try { string location = assembly.Location; return string.IsNullOrEmpty(location) ? null : Path.GetDirectoryName(location); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZCore][Audio] Assembly directory resolve failed: " + ex.Message)); } return null; } } private static AudioType ResolveAudioType(string path) { string extension = Path.GetExtension(path); if (!string.Equals(extension, ".ogg", StringComparison.OrdinalIgnoreCase)) { if (!string.Equals(extension, ".wav", StringComparison.OrdinalIgnoreCase)) { if (!string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase)) { return (AudioType)0; } return (AudioType)13; } return (AudioType)20; } return (AudioType)14; } } internal static class FacilitySmokeEffectBuilder { private static Material _smokeMaterial; private static Texture2D _softCircleTexture; internal static ParticleSystem BuildSmoke(Transform parent, string objectName, float scale = 1f) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_0158: 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_0168: 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: Expected O, but got Unknown //IL_0183: 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_0192: 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_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_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: 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_01f0: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0214: 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_0224: 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) float num = Mathf.Clamp(scale, 0.1f, 2f); GameObject val = new GameObject(string.IsNullOrWhiteSpace(objectName) ? "Smoke" : objectName); val.transform.SetParent(parent, false); ParticleSystem val2 = val.AddComponent(); MainModule main = val2.main; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(1.6f, 2.6f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.22f, 0.48f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.18f * num, 0.4f * num); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(0.2f, 0.2f, 0.22f, 0.35f), new Color(0.32f, 0.32f, 0.34f, 0.28f)); ((MainModule)(ref main)).gravityModifier = new MinMaxCurve(-0.015f); ((MainModule)(ref main)).maxParticles = Mathf.CeilToInt(90f * num); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(9f * num); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = 16f; ((ShapeModule)(ref shape)).radius = 0.06f * num; ((ShapeModule)(ref shape)).rotation = new Vector3(-90f, 0f, 0f); ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.42f, 0.15f), new GradientAlphaKey(0.26f, 0.6f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, AnimationCurve.EaseInOut(0f, 0.6f, 1f, 1.8f)); ParticleSystemRenderer component = val.GetComponent(); component.renderMode = (ParticleSystemRenderMode)0; component.alignment = (ParticleSystemRenderSpace)0; component.minParticleSize = 0.004f; component.maxParticleSize = 0.28f * num; ((Renderer)component).sharedMaterial = GetOrCreateSmokeMaterial(); return val2; } internal static Material CreateParticleMaterial(string name, Color color, bool additive) { //IL_0042: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_008d: 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_00a5: 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_00bd: 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_00d2: 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_00e8: 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_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) Material val = new Material(Shader.Find("HDRP/Unlit") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Standard")) { name = name, hideFlags = (HideFlags)61, renderQueue = 3100 }; Texture2D orCreateSoftCircleTexture = GetOrCreateSoftCircleTexture(); SetTextureIfPresent(val, "_BaseColorMap", (Texture)(object)orCreateSoftCircleTexture); SetTextureIfPresent(val, "_MainTex", (Texture)(object)orCreateSoftCircleTexture); SetTextureIfPresent(val, "_UnlitColorMap", (Texture)(object)orCreateSoftCircleTexture); val.color = color; SetColorIfPresent(val, "_Color", color); SetColorIfPresent(val, "_BaseColor", color); SetColorIfPresent(val, "_UnlitColor", color); SetColorIfPresent(val, "_TintColor", color); if (additive) { SetColorIfPresent(val, "_EmissionColor", color * 6f); SetColorIfPresent(val, "_EmissiveColor", color * 6f); } BlendMode val2 = (BlendMode)(additive ? 1 : 10); SetFloatIfPresent(val, "_SurfaceType", 1f); SetFloatIfPresent(val, "_BlendMode", additive ? 1f : 0f); SetFloatIfPresent(val, "_AlphaCutoffEnable", 0f); SetFloatIfPresent(val, "_ZWrite", 0f); SetFloatIfPresent(val, "_SrcBlend", 5f); SetFloatIfPresent(val, "_DstBlend", (float)val2); SetFloatIfPresent(val, "_AlphaSrcBlend", 5f); SetFloatIfPresent(val, "_AlphaDstBlend", (float)val2); SetFloatIfPresent(val, "_CullMode", 0f); SetFloatIfPresent(val, "_TransparentCullMode", 0f); val.SetOverrideTag("RenderType", "Transparent"); val.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); if (additive) { val.EnableKeyword("_BLENDMODE_ADD"); val.DisableKeyword("_BLENDMODE_ALPHA"); } else { val.EnableKeyword("_BLENDMODE_ALPHA"); val.DisableKeyword("_BLENDMODE_ADD"); } val.EnableKeyword("_ENABLE_FOG_ON_TRANSPARENT"); val.DisableKeyword("_ALPHATEST_ON"); return val; } private static Material GetOrCreateSmokeMaterial() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_smokeMaterial == (Object)null) { _smokeMaterial = CreateParticleMaterial("Y4NGZ_BlackoutBreakerSmoke", new Color(0.5f, 0.5f, 0.52f, 1f), additive: false); } return _smokeMaterial; } private static Texture2D GetOrCreateSoftCircleTexture() { //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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_softCircleTexture != (Object)null) { return _softCircleTexture; } Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false) { name = "Y4NGZ_BlackoutDistressTexture", hideFlags = (HideFlags)61, wrapMode = (TextureWrapMode)1 }; float num = 15.5f; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num2 = Mathf.Sqrt(((float)j - num) * ((float)j - num) + ((float)i - num) * ((float)i - num)) / num; float num3 = Mathf.Clamp01(1f - num2); num3 *= num3; val.SetPixel(j, i, new Color(1f, 1f, 1f, num3)); } } val.Apply(false, true); _softCircleTexture = val; return val; } private static void SetTextureIfPresent(Material material, string property, Texture texture) { if ((Object)(object)texture != (Object)null && material.HasProperty(property)) { material.SetTexture(property, texture); } } private static void SetColorIfPresent(Material material, string property, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(property)) { material.SetColor(property, color); } } private static void SetFloatIfPresent(Material material, string property, float value) { if (material.HasProperty(property)) { material.SetFloat(property, value); } } } } namespace Y4NGZCompany.Facility.Security { public static class EnemyLocationPulseService { public const float PulseIntervalSeconds = 20f; private static readonly List InteriorPlayerLocations = new List(8); private static readonly Dictionary NextAllowedPulseByEnemy = new Dictionary(); public static void ResetRunState() { InteriorPlayerLocations.Clear(); NextAllowedPulseByEnemy.Clear(); } public static void PulseEnemies(IReadOnlyList enemies, float unscaledNow) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (enemies == null || enemies.Count == 0) { return; } CaptureInteriorPlayerLocations(); if (InteriorPlayerLocations.Count == 0) { return; } for (int i = 0; i < enemies.Count; i++) { EnemyAI val = enemies[i]; if (IsValidInteriorEnemy(val) && (((NetworkBehaviour)val).IsServer || ((NetworkBehaviour)val).IsOwner)) { int instanceID = ((Object)val).GetInstanceID(); if ((!NextAllowedPulseByEnemy.TryGetValue(instanceID, out var value) || !(unscaledNow + 0.001f < value)) && TryPickClosestLocation(((Component)val).transform.position, out var destination)) { ApplyFrozenDestination(val, destination); NextAllowedPulseByEnemy[instanceID] = unscaledNow + 20f; } } } } public static bool IsValidInteriorEnemy(EnemyAI enemy) { if ((Object)(object)enemy != (Object)null && !enemy.isEnemyDead && !enemy.isOutside) { return !enemy.isInsidePlayerShip; } return false; } private static void CaptureInteriorPlayerLocations() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) InteriorPlayerLocations.Clear(); PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null) { return; } foreach (PlayerControllerB val in array) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead && val.isInsideFactory) { InteriorPlayerLocations.Add(((Component)val).transform.position); } } } private static bool TryPickClosestLocation(Vector3 enemyPosition, out Vector3 destination) { //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_001d: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) destination = Vector3.zero; float num = float.PositiveInfinity; bool result = false; for (int i = 0; i < InteriorPlayerLocations.Count; i++) { Vector3 val = InteriorPlayerLocations[i]; Vector3 val2 = val - enemyPosition; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude >= num)) { num = sqrMagnitude; destination = val; result = true; } } return result; } private static void ApplyFrozenDestination(EnemyAI enemy, Vector3 frozenDestination) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) enemy.moveTowardsDestination = true; enemy.SetDestinationToPosition(frozenDestination, false); } } } namespace Y4NGZCompany.Facility.Interior { internal enum InteriorSelectionProfile { Generic, ShadowRaid } internal readonly struct InteriorTileSelection { internal readonly Tile Tile; internal readonly Vector3 FloorPosition; internal readonly Quaternion Rotation; internal readonly float Score; internal readonly float PathDistance; internal readonly float HorizontalDistance; internal readonly float NormalizedDepth; internal readonly float NormalizedBranchDepth; internal readonly float Area; internal readonly int DoorwayCount; internal readonly bool IsOnMainPath; internal string TileName { get { if (!((Object)(object)Tile != (Object)null)) { return ""; } return ((Object)Tile).name; } } internal Bounds Bounds { get { //IL_001e: 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_0016: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Tile != (Object)null)) { return default(Bounds); } return Tile.Bounds; } } internal InteriorTileSelection(Tile tile, Vector3 floorPosition, Quaternion rotation, float score, float pathDistance, float horizontalDistance, float normalizedDepth, float normalizedBranchDepth, float area, int doorwayCount, bool isOnMainPath) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Tile = tile; FloorPosition = floorPosition; Rotation = rotation; Score = score; PathDistance = pathDistance; HorizontalDistance = horizontalDistance; NormalizedDepth = normalizedDepth; NormalizedBranchDepth = normalizedBranchDepth; Area = area; DoorwayCount = doorwayCount; IsOnMainPath = isOnMainPath; } } internal static class InteriorAnchorService { private readonly struct Candidate { internal readonly Tile Tile; internal readonly Vector3 FloorPosition; internal readonly float Score; internal readonly float PathDistance; internal readonly float HorizontalDistance; internal readonly float NormalizedDepth; internal readonly float NormalizedBranchDepth; internal readonly float Area; internal readonly int DoorwayCount; internal readonly bool IsOnMainPath; internal readonly bool Valid; internal readonly string DecisionReason; internal Candidate(Tile tile, Vector3 floorPosition, float score, float pathDistance, float horizontalDistance, float normalizedDepth, float normalizedBranchDepth, float area, int doorwayCount, bool isOnMainPath, bool valid, string decisionReason) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Tile = tile; FloorPosition = floorPosition; Score = score; PathDistance = pathDistance; HorizontalDistance = horizontalDistance; NormalizedDepth = normalizedDepth; NormalizedBranchDepth = normalizedBranchDepth; Area = area; DoorwayCount = doorwayCount; IsOnMainPath = isOnMainPath; Valid = valid; DecisionReason = decisionReason ?? string.Empty; } } private readonly struct CandidateRules { internal readonly float MinArea; internal readonly float MinDepth; internal readonly float MinBranchDepth; internal readonly float AbsoluteMinBranchDepth; internal readonly float MinPathDistance; internal readonly float MinHorizontalDistance; internal readonly int MinDoorways; internal readonly int MaxDoorways; internal readonly float HorizontalWeight; internal readonly float DepthWeight; internal readonly float BranchWeight; internal readonly float AreaWeight; internal readonly float BranchRoomBonus; internal readonly float MainPathPenalty; internal readonly float LowDoorwayBonus; internal readonly float ExtraDoorwayPenalty; internal CandidateRules(float minArea, float minDepth, float minBranchDepth, float absoluteMinBranchDepth, float minPathDistance, float minHorizontalDistance, int minDoorways, int maxDoorways, float horizontalWeight, float depthWeight, float branchWeight, float areaWeight, float branchRoomBonus, float mainPathPenalty, float lowDoorwayBonus, float extraDoorwayPenalty) { MinArea = minArea; MinDepth = minDepth; MinBranchDepth = minBranchDepth; AbsoluteMinBranchDepth = absoluteMinBranchDepth; MinPathDistance = minPathDistance; MinHorizontalDistance = minHorizontalDistance; MinDoorways = minDoorways; MaxDoorways = maxDoorways; HorizontalWeight = horizontalWeight; DepthWeight = depthWeight; BranchWeight = branchWeight; AreaWeight = areaWeight; BranchRoomBonus = branchRoomBonus; MainPathPenalty = mainPathPenalty; LowDoorwayBonus = lowDoorwayBonus; ExtraDoorwayPenalty = extraDoorwayPenalty; } internal static CandidateRules Create(InteriorSelectionProfile profile) { if (profile == InteriorSelectionProfile.ShadowRaid) { return new CandidateRules(44f, 0.55f, 0.28f, 0.12f, 95f, 48f, 1, 4, 0.6f, 430f, 260f, 0.28f, 130f, -180f, 35f, 26f); } return new CandidateRules(28f, 0.22f, 0f, 0f, 30f, 18f, 0, 6, 0.55f, 240f, 150f, 0.25f, 70f, -20f, 35f, 18f); } } private readonly struct CachedSelection { internal readonly InteriorTileSelection Selection; internal readonly bool HasSelection; internal CachedSelection(InteriorTileSelection selection, bool hasSelection) { Selection = selection; HasSelection = hasSelection; } } private const float MinTileArea = 28f; private static readonly Dictionary CachedSelections = new Dictionary(); private static readonly Dictionary CachedTileEntrancePathDistances = new Dictionary(); private static readonly Dictionary CachedTileEntranceReachable = new Dictionary(); private static List CachedEntrancePositions; private static int CachedDungeonHash; private static bool LastEntranceResolutionWasProvisional; private static bool ReachabilityVetoSuppressed; private static bool AnchorRefreshAttempted; private static bool AnchorRejectionWarningLogged; private static List ProvisionalEntrancePositions; private static int ProvisionalEntranceFrame; private const int ProvisionalEntranceReresolveFrames = 30; private const float PointSetMatchSqrEpsilon = 0.0001f; internal static int NavMeshPathCalculationCount { get; private set; } internal static int PhysicsQueryCount { get; private set; } internal static bool AreEntranceAnchorsValidated => CachedEntrancePositions != null; internal static void ResetRunState() { CachedSelections.Clear(); CachedTileEntrancePathDistances.Clear(); CachedTileEntranceReachable.Clear(); CachedEntrancePositions = null; CachedDungeonHash = 0; LastEntranceResolutionWasProvisional = false; ReachabilityVetoSuppressed = false; AnchorRefreshAttempted = false; AnchorRejectionWarningLogged = false; ProvisionalEntrancePositions = null; ProvisionalEntranceFrame = 0; NavMeshPathCalculationCount = 0; PhysicsQueryCount = 0; } internal static void RecordNavMeshPathCalculation() { NavMeshPathCalculationCount++; } internal static void RecordPhysicsQuery(int count = 1) { if (count > 0) { PhysicsQueryCount += count; } } internal static bool TryGetPrimaryInteriorTile(out InteriorTileSelection selection) { return TryGetInteriorTile(InteriorSelectionProfile.Generic, out selection); } internal static bool TryGetInteriorTile(InteriorSelectionProfile profile, out InteriorTileSelection selection) { EnsureDungeonCacheFresh(); if (CachedSelections.TryGetValue(profile, out var value) && value.HasSelection) { selection = value.Selection; return true; } bool num = TrySelectInteriorTile(profile, out selection); if (num) { CachedSelections[profile] = new CachedSelection(selection, hasSelection: true); } return num; } internal static List GetInteriorEntrancePositions() { //IL_00a8: 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) EnsureDungeonCacheFresh(); if (CachedEntrancePositions != null) { return new List(CachedEntrancePositions); } if (ProvisionalEntrancePositions != null && Time.frameCount - ProvisionalEntranceFrame < 30) { return new List(ProvisionalEntrancePositions); } List list = new List(); EntranceTeleport[] array = Object.FindObjectsOfType(); foreach (EntranceTeleport val in array) { if (!((Object)(object)val == (Object)null) && !val.isEntranceToBuilding) { Transform val2 = (((Object)(object)val.entrancePoint != (Object)null) ? val.entrancePoint : ((Component)val).transform); list.Add(ResolveFloorPosition(val2.position)); } } if (list.Count == 0) { list.Add(RoundManager.FindMainEntrancePosition(false, false)); } List list2 = FilterValidEntrancePositions(list); if (list2.Count == 0) { LastEntranceResolutionWasProvisional = true; ProvisionalEntrancePositions = list; ProvisionalEntranceFrame = Time.frameCount; return new List(list); } if (LastEntranceResolutionWasProvisional) { CachedTileEntrancePathDistances.Clear(); CachedTileEntranceReachable.Clear(); LastEntranceResolutionWasProvisional = false; if (ReachabilityVetoSuppressed) { ReachabilityVetoSuppressed = false; AnchorRefreshAttempted = false; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZ.InteriorAnchor] REACHABILITY_FAIL_OPEN_END reason=validated-anchors-resolved anchors={list2.Count}. Restoring the entrance-reachability veto and recomputing every tile verdict from the validated anchors."); } } } ProvisionalEntrancePositions = null; ProvisionalEntranceFrame = 0; AnchorRejectionWarningLogged = false; CachedEntrancePositions = list2; return new List(CachedEntrancePositions); } private static void InvalidateEntranceCache() { CachedEntrancePositions = null; ProvisionalEntrancePositions = null; ProvisionalEntranceFrame = 0; } private static List FilterValidEntrancePositions(List points) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) List list = new List(points.Count); if (!TryGetDungeonElevationBand(out var bandMinY, out var bandMaxY)) { bandMinY = 1f; bandMaxY = 0f; } int num = 0; int num2 = 0; NavMeshHit val2 = default(NavMeshHit); for (int i = 0; i < points.Count; i++) { Vector3 val = points[i]; bool hasNavMeshNearby = NavMesh.SamplePosition(val, ref val2, 12f, -1); EntranceAnchorVerdict entranceAnchorVerdict = InteriorEntranceAnchorPolicy.Evaluate(val.y, hasNavMeshNearby, bandMinY, bandMaxY, 25f); if (entranceAnchorVerdict.Accepted) { float snapDistanceMeters = Vector3.Distance(val, ((NavMeshHit)(ref val2)).position); list.Add(InteriorEntranceAnchorPolicy.ShouldAdoptNavMeshSnap(snapDistanceMeters) ? ((NavMeshHit)(ref val2)).position : val); continue; } if (entranceAnchorVerdict.OffElevationBand) { num++; } if (entranceAnchorVerdict.OffNavMesh) { num2++; } } if (list.Count < points.Count && !AnchorRejectionWarningLogged) { AnchorRejectionWarningLogged = true; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)string.Format("[Y4NGZ.InteriorAnchor] Rejected {0} of {1} facility entrance anchor(s): offElevationBand={2}, offNavMesh={3}, band={4:0.0}..{5:0.0} (+/-{6:0.0}). {7}", points.Count - list.Count, points.Count, num, num2, bandMinY, bandMaxY, 25f, (list.Count == 0) ? "No usable anchor this query; not caching, will re-resolve." : "Keeping the validated anchors.")); } } return list; } private static bool TryGetDungeonElevationBand(out float bandMinY, out float bandMaxY) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) bandMinY = 1f; bandMaxY = 0f; RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null || val.AllTiles.Count == 0) { return false; } List list = new List(val.AllTiles.Count); List list2 = new List(val.AllTiles.Count); for (int i = 0; i < val.AllTiles.Count; i++) { Tile val2 = val.AllTiles[i]; if (!((Object)(object)val2 == (Object)null)) { Bounds bounds = val2.Bounds; list.Add(((Bounds)(ref bounds)).min.y); list2.Add(((Bounds)(ref bounds)).max.y); } } return InteriorEntranceAnchorPolicy.TryBuildElevationBand(list, list2, out bandMinY, out bandMaxY); } internal static Vector3 ResolveFloorPosition(Vector3 origin) { //IL_0000: 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_000a: Unknown result type (might be due to invalid IL or missing references) if (!TryResolveFloorPosition(origin, out var floor)) { return origin; } return floor; } internal static bool TryResolveFloorPosition(Vector3 origin, out Vector3 floor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) floor = origin; StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } RecordPhysicsQuery(); RaycastHit val = default(RaycastHit); if (!Physics.Raycast(origin + Vector3.up * 5f, Vector3.down, ref val, 12f, instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1)) { return false; } floor = ((RaycastHit)(ref val)).point; return true; } internal static float EstimatePathDistance(Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) TryEstimatePathDistance(from, to, out var distance); return distance; } private static bool TryEstimatePathDistance(Vector3 from, Vector3 to, out float distance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_0086: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(from, ref val, 12f, -1) && NavMesh.SamplePosition(to, ref val2, 12f, -1)) { NavMeshPath val3 = new NavMeshPath(); RecordNavMeshPathCalculation(); if (NavMesh.CalculatePath(((NavMeshHit)(ref val)).position, ((NavMeshHit)(ref val2)).position, -1, val3) && (int)val3.status == 0 && val3.corners != null && val3.corners.Length > 1) { float num = 0f; for (int i = 1; i < val3.corners.Length; i++) { num += Vector3.Distance(val3.corners[i - 1], val3.corners[i]); } distance = num; return true; } } distance = Vector3.Distance(from, to); return false; } internal static float EstimateNearestPathDistance(IReadOnlyList fromPoints, Vector3 to) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) TryEstimateNearestPathDistance(fromPoints, to, out var nearestDistance, out var _); return nearestDistance; } private static bool TryEstimateNearestPathDistance(IReadOnlyList fromPoints, Vector3 to, out float nearestDistance, out float nearestCompleteDistance) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) nearestDistance = 0f; nearestCompleteDistance = 0f; if (fromPoints == null || fromPoints.Count == 0) { return false; } float num = float.MaxValue; float num2 = float.MaxValue; for (int i = 0; i < fromPoints.Count; i++) { float distance; bool num3 = TryEstimatePathDistance(fromPoints[i], to, out distance); num = Mathf.Min(num, distance); if (num3) { num2 = Mathf.Min(num2, distance); } } nearestDistance = ((num == float.MaxValue) ? 0f : num); if (num2 == float.MaxValue) { return false; } nearestCompleteDistance = num2; return true; } internal static bool TryGetEntrancePathDistance(Vector3 to, out float distance, IReadOnlyList fromPoints = null) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) float nearestDistance; float nearestCompleteDistance; bool flag = TryEstimateNearestPathDistance(fromPoints ?? GetInteriorEntrancePositions(), to, out nearestDistance, out nearestCompleteDistance); distance = (flag ? nearestCompleteDistance : nearestDistance); return ReachabilityVetoSuppressed || flag; } internal static float EstimateTileEntrancePathDistance(Tile tile, IReadOnlyList fromPoints = null) { EnsureDungeonCacheFresh(); if ((Object)(object)tile == (Object)null) { return 0f; } EnsureTileEntranceCache(tile, fromPoints); return CachedTileEntrancePathDistances[tile]; } internal static bool IsTileReachableFromEntrance(Tile tile, IReadOnlyList fromPoints = null) { EnsureDungeonCacheFresh(); if ((Object)(object)tile == (Object)null) { return false; } EnsureTileEntranceCache(tile, fromPoints); if (!ReachabilityVetoSuppressed) { return CachedTileEntranceReachable[tile]; } return true; } internal static void GetEntranceReachabilityTally(out int tilesEvaluated, out int tilesReachable) { tilesEvaluated = CachedTileEntranceReachable.Count; tilesReachable = 0; foreach (KeyValuePair item in CachedTileEntranceReachable) { if (item.Value) { tilesReachable++; } } } internal static void ReevaluateReachabilitySuppression() { if (!ReachabilityVetoSuppressed) { return; } GetEntranceReachabilityTally(out var tilesEvaluated, out var tilesReachable); if (InteriorEntranceAnchorPolicy.ShouldRestoreVeto(tilesEvaluated, tilesReachable)) { ReachabilityVetoSuppressed = false; AnchorRefreshAttempted = false; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZ.InteriorAnchor] REACHABILITY_FAIL_OPEN_END reason=reachable-tiles-observed tilesEvaluated={tilesEvaluated} tilesReachable={tilesReachable}. The entrance-reachability veto is back on for the rest of the round."); } } } internal static InteriorEntranceAnchorPolicy.EntranceRecoveryStep TryRecoverEntranceReachability(string context, out List entrances) { entrances = null; GetEntranceReachabilityTally(out var tilesEvaluated, out var tilesReachable); InteriorEntranceAnchorPolicy.EntranceRecoveryStep entranceRecoveryStep = InteriorEntranceAnchorPolicy.DecideRecoveryStep(ReachabilityVetoSuppressed, AnchorRefreshAttempted, tilesEvaluated, tilesReachable, 3); switch (entranceRecoveryStep) { case InteriorEntranceAnchorPolicy.EntranceRecoveryStep.None: return entranceRecoveryStep; case InteriorEntranceAnchorPolicy.EntranceRecoveryStep.RefreshAnchors: { AnchorRefreshAttempted = true; List cachedEntrancePositions = CachedEntrancePositions; InvalidateEntranceCache(); List interiorEntrancePositions = GetInteriorEntrancePositions(); entranceRecoveryStep = InteriorEntranceAnchorPolicy.DecideStepAfterRefresh(InteriorEntranceAnchorPolicy.ClassifyRefresh(!LastEntranceResolutionWasProvisional, !AreSamePointSets(cachedEntrancePositions, interiorEntrancePositions))); entrances = interiorEntrancePositions; switch (entranceRecoveryStep) { case InteriorEntranceAnchorPolicy.EntranceRecoveryStep.RefreshAnchors: { CachedTileEntrancePathDistances.Clear(); CachedTileEntranceReachable.Clear(); ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)$"[Y4NGZ.InteriorAnchor] REACHABILITY_ANCHOR_REFRESH context={context} anchors={interiorEntrancePositions.Count} tilesEvaluated={tilesEvaluated} tilesReachable={tilesReachable}. Re-resolved the facility entrances and dropped every tile verdict pathed from the old set; re-scanning with the reachability veto still on."); } return entranceRecoveryStep; } case InteriorEntranceAnchorPolicy.EntranceRecoveryStep.None: { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.InteriorAnchor] REACHABILITY_ANCHOR_REFRESH context={context} outcome=unchanged anchors={interiorEntrancePositions.Count} tilesEvaluated={tilesEvaluated} tilesReachable={tilesReachable}. The validated facility entrances re-resolved to themselves, so the reachability veto stays on for this scan."); } return entranceRecoveryStep; } } break; } } ReachabilityVetoSuppressed = true; ManualLogSource log3 = CoreDiagnostics.Log; if (log3 != null) { log3.LogWarning((object)$"[Y4NGZ.InteriorAnchor] REACHABILITY_FAIL_OPEN context={context} tilesEvaluated={tilesEvaluated} tilesReachable={tilesReachable} entranceAnchors={((entrances != null) ? entrances.Count : ((CachedEntrancePositions != null) ? CachedEntrancePositions.Count : 0))} anchorsValidated={AreEntranceAnchorsValidated}. No tile in this dungeon is reachable from the resolved facility entrances and re-resolving them did not help, which is evidence against the anchors rather than the dungeon; running interior placement without the reachability veto until a validated anchor set or a reachable tile restores it."); } return InteriorEntranceAnchorPolicy.EntranceRecoveryStep.SuppressVeto; } private static bool AreSamePointSets(List a, List b) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (a == null || b == null) { if (a == null) { return b == null; } return false; } if (a.Count != b.Count) { return false; } bool[] array = new bool[b.Count]; for (int i = 0; i < a.Count; i++) { bool flag = false; for (int j = 0; j < b.Count; j++) { if (flag) { break; } if (!array[j] && !(Vector3.SqrMagnitude(a[i] - b[j]) > 0.0001f)) { array[j] = true; flag = true; } } if (!flag) { return false; } } return true; } private static void EnsureTileEntranceCache(Tile tile, IReadOnlyList fromPoints) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_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_0168: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) if (CachedTileEntranceReachable.ContainsKey(tile)) { return; } IReadOnlyList fromPoints2 = fromPoints ?? GetInteriorEntrancePositions(); Bounds bounds = tile.Bounds; Vector3 val = ResolveFloorPosition(((Bounds)(ref bounds)).center); float nearestDistance; float nearestCompleteDistance; bool flag = TryEstimateNearestPathDistance(fromPoints2, val, out nearestDistance, out nearestCompleteDistance); int num = 1; if (!flag) { Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((Bounds)(ref bounds)).extents.x * 0.5f, 0f, ((Bounds)(ref bounds)).extents.z * 0.5f); Vector3[] array = (Vector3[])(object)new Vector3[2] { ((Bounds)(ref bounds)).center + val2, ((Bounds)(ref bounds)).center - val2 }; NavMeshHit val4 = default(NavMeshHit); for (int i = 0; i < array.Length; i++) { if (flag) { break; } Vector3 val3 = ResolveFloorPosition(array[i]); if (NavMesh.SamplePosition(val3 + Vector3.up * 0.05f, ref val4, 5f, -1)) { val3 = ((NavMeshHit)(ref val4)).position; } num++; val = val3; if (TryEstimateNearestPathDistance(fromPoints2, val3, out var nearestDistance2, out nearestCompleteDistance)) { flag = true; nearestDistance = nearestDistance2; } else { nearestDistance = Mathf.Min(nearestDistance, nearestDistance2); } } } CachedTileEntrancePathDistances[tile] = nearestDistance; CachedTileEntranceReachable[tile] = flag; if (!flag) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.InteriorAnchor] Tile '{((Object)tile).name}' is unreachable from the facility entrance: no complete NavMesh path from any of {num} probe point(s) inside it, last tried {FormatVector(val)} (nearest estimate {nearestDistance:0.0}). Excluding it from interior placement."); } } } internal static float EstimateNearestHorizontalDistance(IReadOnlyList fromPoints, Vector3 to) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (fromPoints == null || fromPoints.Count == 0) { return 0f; } float num = float.MaxValue; for (int i = 0; i < fromPoints.Count; i++) { num = Mathf.Min(num, HorizontalDistance(fromPoints[i], to)); } if (num != float.MaxValue) { return num; } return 0f; } internal static Vector3 GetNearestEntrancePoint(IReadOnlyList fromPoints, Vector3 to) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) if (fromPoints == null || fromPoints.Count == 0) { return RoundManager.FindMainEntrancePosition(false, false); } Vector3 result = fromPoints[0]; float num = float.MaxValue; for (int i = 0; i < fromPoints.Count; i++) { float num2 = HorizontalDistance(fromPoints[i], to); if (!(num2 >= num)) { num = num2; result = fromPoints[i]; } } return result; } internal static float HorizontalDistance(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = a.x - b.x; float num2 = a.z - b.z; return Mathf.Sqrt(num * num + num2 * num2); } internal static float GetTileDepth(Tile tile) { if ((Object)(object)tile == (Object)null) { return 0f; } try { return tile.Placement.NormalizedPathDepth; } catch { return 0f; } } internal static float GetTileArea(Tile tile) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)tile == (Object)null) { return 0f; } Bounds bounds = tile.Bounds; return Mathf.Max(0f, ((Bounds)(ref bounds)).size.x) * Mathf.Max(0f, ((Bounds)(ref bounds)).size.z); } private static bool TrySelectInteriorTile(InteriorSelectionProfile profile, out InteriorTileSelection selection) { //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: 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_0376: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) selection = default(InteriorTileSelection); RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null || val.AllTiles.Count == 0) { return false; } if (profile == InteriorSelectionProfile.ShadowRaid) { if (TrySelectAuthoredBlacksiteTile(out selection)) { return true; } if (AuthoredInteriorPlacementStore.GetRecordsForFlow("blacksite-container", ResolveCurrentFlowName()).Count > 0) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)"[MoonContracts.ShadowRaid] Authored Shadow Raid placements exist, but none matched the loaded interior. Skipping heuristic Shadow Raid room fallback so this contract only runs in authored interiors."); } return false; } } List entrances = GetInteriorEntrancePositions(); bool num = profile == InteriorSelectionProfile.ShadowRaid; CandidateRules rules = CandidateRules.Create(profile); List list = (from tile in val.AllTiles where (Object)(object)tile != (Object)null select BuildCandidate(profile, tile, entrances, rules)).ToList(); if (num) { foreach (Candidate item in list) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)string.Format("[MoonContracts.ShadowRaid] Candidate '{0}' {1}: {2} | depth={3:0.00}, branch={4:0.00}, path={5:0.0}, horizontal={6:0.0}, area={7:0.0}, doorways={8}, mainPath={9}, score={10:0.0}.", ((Object)item.Tile).name, item.Valid ? "accepted" : "rejected", item.DecisionReason, item.NormalizedDepth, item.NormalizedBranchDepth, item.PathDistance, item.HorizontalDistance, item.Area, item.DoorwayCount, item.IsOnMainPath, item.Score)); } } } List list2 = (from candidate2 in list where candidate2.Valid orderby candidate2.Score descending, candidate2.NormalizedDepth descending, candidate2.NormalizedBranchDepth descending, candidate2.Area descending select candidate2).ThenBy((Candidate candidate2) => ((Object)candidate2.Tile).name, StringComparer.Ordinal).ToList(); if (list2.Count == 0) { ManualLogSource log3 = CoreDiagnostics.Log; if (log3 != null) { log3.LogWarning((object)$"[MoonContracts] Interior injection could not find a valid {profile} room candidate."); } return false; } Candidate candidate = list2[0]; Vector3 val2 = candidate.FloorPosition - GetNearestEntrancePoint(entrances, candidate.FloorPosition); val2.y = 0f; Quaternion rotation = ((((Vector3)(ref val2)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up) : Quaternion.identity); selection = new InteriorTileSelection(candidate.Tile, candidate.FloorPosition, rotation, candidate.Score, candidate.PathDistance, candidate.HorizontalDistance, candidate.NormalizedDepth, candidate.NormalizedBranchDepth, candidate.Area, candidate.DoorwayCount, candidate.IsOnMainPath); string text = ((profile == InteriorSelectionProfile.ShadowRaid) ? "[MoonContracts.ShadowRaid]" : "[MoonContracts]"); ManualLogSource log4 = CoreDiagnostics.Log; if (log4 != null) { log4.LogInfo((object)$"{text} Interior injection selected tile '{selection.TileName}' center={FormatVector(selection.FloorPosition)}, depth={selection.NormalizedDepth:0.00}, branch={selection.NormalizedBranchDepth:0.00}, path={selection.PathDistance:0.0}, horizontal={selection.HorizontalDistance:0.0}, area={selection.Area:0.0}, doorways={selection.DoorwayCount}, mainPath={selection.IsOnMainPath}, score={selection.Score:0.0}."); } return true; } private static bool TrySelectAuthoredBlacksiteTile(out InteriorTileSelection selection) { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) selection = default(InteriorTileSelection); if (!AuthoredInteriorPlacementStore.TryResolvePoses("blacksite-container", out var poses) || poses == null) { return false; } for (int i = 0; i < poses.Count; i++) { AuthoredInteriorPlacementPose authoredInteriorPlacementPose = poses[i]; Tile tile = authoredInteriorPlacementPose.Tile; if (!((Object)(object)tile == (Object)null)) { Bounds bounds = tile.Bounds; Vector3 val = ResolveFloorPosition(((Bounds)(ref bounds)).center); float area = Mathf.Max(0f, ((Bounds)(ref bounds)).size.x) * Mathf.Max(0f, ((Bounds)(ref bounds)).size.z); int doorwayCount = CountConnectedDoorways(tile); float normalizedDepth = 0f; float normalizedBranchDepth = 0f; bool isOnMainPath = true; try { normalizedDepth = tile.Placement.NormalizedPathDepth; normalizedBranchDepth = tile.Placement.NormalizedBranchDepth; isOnMainPath = tile.Placement.IsOnMainPath; } catch { } List interiorEntrancePositions = GetInteriorEntrancePositions(); float pathDistance = EstimateNearestPathDistance(interiorEntrancePositions, val); float horizontalDistance = EstimateNearestHorizontalDistance(interiorEntrancePositions, val); Quaternion normalized; Quaternion rotation = (TryNormalizeRotation(authoredInteriorPlacementPose.WorldRotation, out normalized) ? normalized : BuildAwayFromEntranceRotation(interiorEntrancePositions, val)); selection = new InteriorTileSelection(tile, val, rotation, 20000f, pathDistance, horizontalDistance, normalizedDepth, normalizedBranchDepth, area, doorwayCount, isOnMainPath); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)("[MoonContracts.ShadowRaid] Authored placement selected tile '" + selection.TileName + "' from " + authoredInteriorPlacementPose.Source + " id='" + authoredInteriorPlacementPose.Record?.objectId + "' at " + FormatVector(authoredInteriorPlacementPose.WorldPosition) + ".")); } return true; } } return false; } private static bool TryNormalizeRotation(Quaternion rotation, out Quaternion normalized) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_007b: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) normalized = Quaternion.identity; float num = rotation.x * rotation.x + rotation.y * rotation.y + rotation.z * rotation.z + rotation.w * rotation.w; if (float.IsNaN(num) || float.IsInfinity(num) || num < 0.0001f) { return false; } float num2 = 1f / Mathf.Sqrt(num); normalized = new Quaternion(rotation.x * num2, rotation.y * num2, rotation.z * num2, rotation.w * num2); return true; } private static Quaternion BuildAwayFromEntranceRotation(IReadOnlyList entrances, Vector3 floorPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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) Vector3 val = floorPosition - GetNearestEntrancePoint(entrances, floorPosition); val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f)) { return Quaternion.identity; } return Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); } private static Candidate BuildCandidate(InteriorSelectionProfile profile, Tile tile, IReadOnlyList entrances, CandidateRules rules) { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_008e: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = tile.Bounds; float tileArea = GetTileArea(tile); float num = Mathf.Min(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z); float num2 = Mathf.Max(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z); bool hallwayLike = num < 3.1f || (num2 > num * 4.5f && tileArea < 84f); int num3 = CountConnectedDoorways(tile); Vector3 val = ResolveFloorPosition(((Bounds)(ref bounds)).center); NavMeshHit val2 = default(NavMeshHit); bool flag = NavMesh.SamplePosition(val + Vector3.up * 0.05f, ref val2, 5f, -1); if (flag) { val = ((NavMeshHit)(ref val2)).position; } float num4 = 0f; float num5 = 0f; bool flag2 = true; try { num4 = tile.Placement.NormalizedPathDepth; num5 = tile.Placement.NormalizedBranchDepth; flag2 = tile.Placement.IsOnMainPath; } catch { } float num6 = EstimateTileEntrancePathDistance(tile, entrances); bool reachable = IsTileReachableFromEntrance(tile, entrances); float num7 = EstimateNearestHorizontalDistance(entrances, val); float score = num6 + num7 * rules.HorizontalWeight + num4 * rules.DepthWeight + num5 * rules.BranchWeight + tileArea * rules.AreaWeight + ((!flag2) ? rules.BranchRoomBonus : rules.MainPathPenalty) + ((num3 <= 2) ? rules.LowDoorwayBonus : 0f) - (float)Mathf.Max(0, num3 - 3) * rules.ExtraDoorwayPenalty; string reason; bool valid = EvaluateCandidate(profile, rules, tileArea, hallwayLike, flag, reachable, num4, num5, num6, num7, num3, flag2, out reason); return new Candidate(tile, val, score, num6, num7, num4, num5, tileArea, num3, flag2, valid, reason); } private static void EnsureDungeonCacheFresh() { int currentDungeonHash = GetCurrentDungeonHash(); if (CachedDungeonHash != currentDungeonHash) { CachedDungeonHash = currentDungeonHash; CachedSelections.Clear(); CachedTileEntrancePathDistances.Clear(); CachedTileEntranceReachable.Clear(); CachedEntrancePositions = null; LastEntranceResolutionWasProvisional = false; ReachabilityVetoSuppressed = false; AnchorRefreshAttempted = false; AnchorRejectionWarningLogged = false; ProvisionalEntrancePositions = null; ProvisionalEntranceFrame = 0; } } private static int GetCurrentDungeonHash() { RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null) { return 0; } int num = 17; for (int i = 0; i < val.AllTiles.Count; i++) { Tile val2 = val.AllTiles[i]; num = num * 31 + (((Object)(object)val2 != (Object)null) ? ((Object)val2).GetInstanceID() : 0); } return num; } private static bool EvaluateCandidate(InteriorSelectionProfile profile, CandidateRules rules, float area, bool hallwayLike, bool hasNavMesh, bool reachable, float normalizedDepth, float normalizedBranchDepth, float pathDistance, float horizontalDistance, int doorwayCount, bool isOnMainPath, out string reason) { if (area < rules.MinArea) { reason = $"area {area:0.0} < {rules.MinArea:0.0}"; return false; } if (hallwayLike) { reason = "hallway-like bounds"; return false; } if (!hasNavMesh) { reason = "no nearby NavMesh"; return false; } if (!reachable) { reason = "unreachable from entrance"; return false; } if (normalizedDepth < rules.MinDepth) { reason = $"depth {normalizedDepth:0.00} < {rules.MinDepth:0.00}"; return false; } if (pathDistance < rules.MinPathDistance && horizontalDistance < rules.MinHorizontalDistance) { reason = $"too close to entrances path={pathDistance:0.0}, horizontal={horizontalDistance:0.0}"; return false; } if (doorwayCount < rules.MinDoorways) { reason = $"doorways {doorwayCount} < {rules.MinDoorways}"; return false; } if (doorwayCount > rules.MaxDoorways) { reason = $"doorways {doorwayCount} > {rules.MaxDoorways}"; return false; } if (profile == InteriorSelectionProfile.ShadowRaid) { if (isOnMainPath && normalizedBranchDepth < rules.MinBranchDepth) { reason = $"main-path transit room branch={normalizedBranchDepth:0.00} < {rules.MinBranchDepth:0.00}"; return false; } if (normalizedBranchDepth < rules.AbsoluteMinBranchDepth && isOnMainPath) { reason = $"insufficient leaf feel branch={normalizedBranchDepth:0.00}"; return false; } } reason = "accepted (" + (isOnMainPath ? "main path fallback" : "branch/leaf") + ")"; return true; } private static int CountConnectedDoorways(Tile tile) { if (tile?.UsedDoorways == null) { return 0; } int num = 0; for (int i = 0; i < tile.UsedDoorways.Count; i++) { Doorway val = tile.UsedDoorways[i]; if ((Object)(object)val != (Object)null && (Object)(object)val.ConnectedDoorway != (Object)null) { num++; } } return num; } private static string FormatVector(Vector3 value) { //IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references) return $"{value.x:0.0},{value.y:0.0},{value.z:0.0}"; } private static string ResolveCurrentFlowName() { try { DungeonFlow val = RoundManager.Instance?.dungeonGenerator?.Generator?.DungeonFlow; return ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) ? ((Object)val).name : "unknown-flow"; } catch { return "unknown-flow"; } } } internal readonly struct EntranceAnchorVerdict { internal readonly bool Accepted; internal readonly bool OffElevationBand; internal readonly bool OffNavMesh; internal EntranceAnchorVerdict(bool accepted, bool offElevationBand, bool offNavMesh) { Accepted = accepted; OffElevationBand = offElevationBand; OffNavMesh = offNavMesh; } } internal static class InteriorEntranceAnchorPolicy { internal enum EntranceRecoveryStep { None, RefreshAnchors, SuppressVeto } internal enum EntranceRefreshOutcome { Rescan, Unvalidated, Unchanged } internal const float ElevationBandToleranceMeters = 25f; internal const float NavMeshSampleRadiusMeters = 12f; internal const int MinTilesForFailOpen = 3; internal const float MaxAdoptedNavMeshSnapMeters = 1f; internal static bool ShouldAdoptNavMeshSnap(float snapDistanceMeters) { return snapDistanceMeters <= 1f; } internal static EntranceRecoveryStep DecideRecoveryStep(bool alreadySuppressed, bool anchorRefreshAttempted, int tilesEvaluated, int tilesReachable, int minTilesEvaluated) { if (alreadySuppressed) { return EntranceRecoveryStep.None; } if (!ShouldFailOpen(tilesEvaluated, tilesReachable, minTilesEvaluated)) { return EntranceRecoveryStep.None; } if (!anchorRefreshAttempted) { return EntranceRecoveryStep.RefreshAnchors; } return EntranceRecoveryStep.SuppressVeto; } internal static EntranceRefreshOutcome ClassifyRefresh(bool validated, bool differsFromPrevious) { if (!validated) { return EntranceRefreshOutcome.Unvalidated; } if (!differsFromPrevious) { return EntranceRefreshOutcome.Unchanged; } return EntranceRefreshOutcome.Rescan; } internal static EntranceRecoveryStep DecideStepAfterRefresh(EntranceRefreshOutcome outcome) { return outcome switch { EntranceRefreshOutcome.Rescan => EntranceRecoveryStep.RefreshAnchors, EntranceRefreshOutcome.Unvalidated => EntranceRecoveryStep.SuppressVeto, _ => EntranceRecoveryStep.None, }; } internal static bool ShouldRestoreVeto(int tilesEvaluated, int tilesReachable) { if (tilesEvaluated > 0) { return tilesReachable > 0; } return false; } internal static EntranceAnchorVerdict Evaluate(float anchorY, bool hasNavMeshNearby, float bandMinY, float bandMaxY, float toleranceMeters) { bool flag = !IsWithinElevationBand(anchorY, bandMinY, bandMaxY, toleranceMeters); bool flag2 = !hasNavMeshNearby; return new EntranceAnchorVerdict(!flag && !flag2, flag, flag2); } internal static bool IsWithinElevationBand(float y, float bandMinY, float bandMaxY, float toleranceMeters) { if (bandMinY > bandMaxY) { return true; } float num = ((toleranceMeters > 0f) ? toleranceMeters : 0f); if (y >= bandMinY - num) { return y <= bandMaxY + num; } return false; } internal static bool ShouldFailOpen(int tilesEvaluated, int tilesReachable, int minTilesEvaluated) { if (tilesEvaluated >= minTilesEvaluated) { return tilesReachable <= 0; } return false; } internal static bool TryBuildElevationBand(IReadOnlyList tileBoundsMinY, IReadOnlyList tileBoundsMaxY, out float bandMinY, out float bandMaxY) { bandMinY = 1f; bandMaxY = 0f; if (tileBoundsMinY == null || tileBoundsMaxY == null) { return false; } int num = ((tileBoundsMinY.Count < tileBoundsMaxY.Count) ? tileBoundsMinY.Count : tileBoundsMaxY.Count); if (num <= 0) { return false; } float num2 = float.MaxValue; float num3 = float.MinValue; for (int i = 0; i < num; i++) { if (tileBoundsMinY[i] < num2) { num2 = tileBoundsMinY[i]; } if (tileBoundsMaxY[i] > num3) { num3 = tileBoundsMaxY[i]; } } if (num2 > num3) { return false; } bandMinY = num2; bandMaxY = num3; return true; } } } namespace Y4NGZCompany.Facility.Interior.Placement { public readonly struct FixtureFootprint { public readonly Vector3 LocalFront; public readonly Vector3 LocalBack; public readonly Vector3 LocalUp; public readonly Vector3 Size; public readonly float BackPlaneOffset; public readonly float BottomOffset; public readonly float FrontClearance; public readonly float InteractionHeight; public FixtureFootprint(Vector3 localFront, Vector3 localBack, Vector3 localUp, Vector3 size, float backPlaneOffset, float bottomOffset, float frontClearance, float interactionHeight) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_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_0012: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) LocalFront = SafeAxis(localFront, Vector3.forward); LocalBack = SafeAxis(localBack, Vector3.back); LocalUp = SafeAxis(localUp, Vector3.up); Size = new Vector3(Mathf.Abs(size.x), Mathf.Abs(size.y), Mathf.Abs(size.z)); BackPlaneOffset = Mathf.Max(0f, backPlaneOffset); BottomOffset = bottomOffset; FrontClearance = Mathf.Max(0.35f, frontClearance); InteractionHeight = Mathf.Max(0.2f, interactionHeight); } public static FixtureFootprint Mainframe(float backOffset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new FixtureFootprint(Vector3.back, Vector3.forward, Vector3.up, new Vector3(1.55f, 2.2f, 0.82f), backOffset, 0f, 1.35f, 1.15f); } public static FixtureFootprint Alarm(float backOffset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new FixtureFootprint(Vector3.forward, Vector3.back, Vector3.up, new Vector3(0.72f, 1f, 0.36f), backOffset, 0.85f, 1.05f, 1.2f); } public static FixtureFootprint Vault(float backOffset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new FixtureFootprint(Vector3.forward, Vector3.back, Vector3.up, new Vector3(1f, 1.45f, 0.86f), backOffset, 0f, 1.15f, 0.95f); } public static FixtureFootprint LargeBackWall(float width, float height, float depth, float backOffset, float frontClearance, float interactionHeight) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new FixtureFootprint(Vector3.forward, Vector3.back, Vector3.up, new Vector3(width, height, depth), backOffset, 0f, frontClearance, interactionHeight); } private static Vector3 SafeAxis(Vector3 value, Vector3 fallback) { //IL_0012: 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) if (((Vector3)(ref value)).sqrMagnitude < 1E-06f) { return fallback; } return ((Vector3)(ref value)).normalized; } } public static class FixtureReservationRegistry { private sealed class ReservationEntry { internal readonly long Id; internal readonly string Label; internal readonly string Source; internal readonly FixtureReservationObb Obb; internal ReservationEntry(long id, string label, string source, FixtureReservationObb obb) { Id = id; Label = label; Source = source; Obb = obb; } } private readonly struct GroupCandidate { internal readonly string Label; internal readonly string Source; internal readonly FixtureReservationObb Obb; internal readonly ReservationEntry Existing; internal GroupCandidate(string label, string source, FixtureReservationObb obb, ReservationEntry existing) { Label = label; Source = source; Obb = obb; Existing = existing; } } public const float HorizontalPadding = 0.1f; public const float VerticalPadding = 0.05f; private static readonly object Sync = new object(); private static readonly List Reservations = new List(); private static long _nextId = 1L; public static FixtureReservationObb CreateObb(FixtureFootprint footprint, Vector3 position, Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) Vector3 axisX = SafeAxis(rotation * Vector3.right, Vector3.right); Vector3 val = SafeAxis(rotation * Vector3.up, Vector3.up); Vector3 axisZ = SafeAxis(rotation * Vector3.forward, Vector3.forward); Vector3 val2 = SafeAxis(rotation * footprint.LocalUp, val); Vector3 center = position + val2 * (footprint.BottomOffset + footprint.Size.y * 0.5f); Vector3 halfExtents = default(Vector3); ((Vector3)(ref halfExtents))..ctor(footprint.Size.x * 0.5f + 0.1f, footprint.Size.y * 0.5f + 0.05f, footprint.Size.z * 0.5f + 0.1f); return new FixtureReservationObb(center, halfExtents, axisX, val, axisZ); } public static bool Overlaps(FixtureReservationObb a, FixtureReservationObb b) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0081: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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) //IL_014c: 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_015d: 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_016e: 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_00e3: 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) Vector3[] array = (Vector3[])(object)new Vector3[3] { a.AxisX, a.AxisY, a.AxisZ }; Vector3[] array2 = (Vector3[])(object)new Vector3[3] { b.AxisX, b.AxisY, b.AxisZ }; float[] array3 = new float[3] { a.HalfExtents.x, a.HalfExtents.y, a.HalfExtents.z }; float[] array4 = new float[3] { b.HalfExtents.x, b.HalfExtents.y, b.HalfExtents.z }; float[,] array5 = new float[3, 3]; float[,] array6 = new float[3, 3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { array5[i, j] = Vector3.Dot(array[i], array2[j]); array6[i, j] = Mathf.Abs(array5[i, j]) + 1E-06f; } } Vector3 val = b.Center - a.Center; float[] array7 = new float[3] { Vector3.Dot(val, array[0]), Vector3.Dot(val, array[1]), Vector3.Dot(val, array[2]) }; for (int k = 0; k < 3; k++) { float num = array3[k]; float num2 = array4[0] * array6[k, 0] + array4[1] * array6[k, 1] + array4[2] * array6[k, 2]; if (Mathf.Abs(array7[k]) > num + num2) { return false; } } for (int l = 0; l < 3; l++) { float num3 = Mathf.Abs(array7[0] * array5[0, l] + array7[1] * array5[1, l] + array7[2] * array5[2, l]); float num4 = array3[0] * array6[0, l] + array3[1] * array6[1, l] + array3[2] * array6[2, l]; float num5 = array4[l]; if (num3 > num4 + num5) { return false; } } for (int m = 0; m < 3; m++) { int num6 = (m + 1) % 3; int num7 = (m + 2) % 3; for (int n = 0; n < 3; n++) { int num8 = (n + 1) % 3; int num9 = (n + 2) % 3; float num10 = Mathf.Abs(array7[num7] * array5[num6, n] - array7[num6] * array5[num7, n]); float num11 = array3[num6] * array6[num7, n] + array3[num7] * array6[num6, n]; float num12 = array4[num8] * array6[m, num9] + array4[num9] * array6[m, num8]; if (num10 > num11 + num12) { return false; } } } return true; } public static bool TryGetConflict(FixtureFootprint footprint, Vector3 position, Quaternion rotation, out FixtureReservationConflict conflict) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) FixtureReservationObb candidate = CreateObb(footprint, position, rotation); lock (Sync) { ReservationEntry idempotentEntry; return TryFindConflict(candidate, null, null, out idempotentEntry, out conflict); } } public static bool TryReserve(string label, FixtureFootprint footprint, Vector3 position, Quaternion rotation, out FixtureReservationConflict conflict) { //IL_0003: 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) FixtureReservationHandle handle; return TryReserve(label, label, footprint, position, rotation, out handle, out conflict); } public static bool TryReserve(string label, FixtureFootprint footprint, Vector3 position, Quaternion rotation, out FixtureReservationHandle handle, out FixtureReservationConflict conflict) { //IL_0003: 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 TryReserve(label, label, footprint, position, rotation, out handle, out conflict); } public static bool TryReserve(string label, string source, FixtureFootprint footprint, Vector3 position, Quaternion rotation, out FixtureReservationHandle handle, out FixtureReservationConflict conflict) { //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) string text = Normalize(label, "unlabeled-fixture"); string source2 = Normalize(source, text); FixtureReservationObb fixtureReservationObb = CreateObb(footprint, position, rotation); lock (Sync) { if (TryFindConflict(fixtureReservationObb, text, source2, out var idempotentEntry, out conflict)) { handle = default(FixtureReservationHandle); return false; } if (idempotentEntry != null) { handle = new FixtureReservationHandle(idempotentEntry.Id, idempotentEntry.Label); conflict = default(FixtureReservationConflict); return true; } long id = _nextId++; Reservations.Add(new ReservationEntry(id, text, source2, fixtureReservationObb)); handle = new FixtureReservationHandle(id, text); conflict = default(FixtureReservationConflict); return true; } } public static bool TryReserveGroup(IReadOnlyList requests, out FixtureReservationGroup group, out FixtureReservationConflict conflict) { //IL_0072: 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) group = default(FixtureReservationGroup); conflict = default(FixtureReservationConflict); if (requests == null || requests.Count == 0) { return false; } GroupCandidate[] array = new GroupCandidate[requests.Count]; lock (Sync) { for (int i = 0; i < requests.Count; i++) { FixtureReservationRequest fixtureReservationRequest = requests[i]; string text = Normalize(fixtureReservationRequest.Label, "unlabeled-fixture"); string source = Normalize(fixtureReservationRequest.Source, text); FixtureReservationObb fixtureReservationObb = CreateObb(fixtureReservationRequest.Footprint, fixtureReservationRequest.Position, fixtureReservationRequest.Rotation); if (TryFindConflict(fixtureReservationObb, text, source, out var idempotentEntry, out conflict)) { return false; } array[i] = new GroupCandidate(text, source, fixtureReservationObb, idempotentEntry); } FixtureReservationHandle[] array2 = new FixtureReservationHandle[array.Length]; for (int j = 0; j < array.Length; j++) { GroupCandidate groupCandidate = array[j]; ReservationEntry reservationEntry = groupCandidate.Existing; if (reservationEntry == null) { reservationEntry = new ReservationEntry(_nextId++, groupCandidate.Label, groupCandidate.Source, groupCandidate.Obb); Reservations.Add(reservationEntry); } array2[j] = new FixtureReservationHandle(reservationEntry.Id, reservationEntry.Label); } group = new FixtureReservationGroup(array2); return true; } } public static bool TryGetConflict(IReadOnlyList requests, out int requestIndex, out FixtureReservationConflict conflict) { //IL_003a: 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) requestIndex = -1; conflict = default(FixtureReservationConflict); if (requests == null || requests.Count == 0) { return false; } lock (Sync) { for (int i = 0; i < requests.Count; i++) { FixtureReservationRequest fixtureReservationRequest = requests[i]; if (TryFindConflict(CreateObb(fixtureReservationRequest.Footprint, fixtureReservationRequest.Position, fixtureReservationRequest.Rotation), null, null, out var _, out conflict)) { requestIndex = i; return true; } } } return false; } public static bool Release(FixtureReservationHandle handle) { if (!handle.IsValid) { return false; } lock (Sync) { for (int i = 0; i < Reservations.Count; i++) { if (Reservations[i].Id == handle.Id) { Reservations.RemoveAt(i); return true; } } } return false; } public static bool Release(FixtureReservationGroup group) { FixtureReservationHandle[] handles = group.Handles; if (handles == null || handles.Length == 0) { return false; } bool result = false; lock (Sync) { for (int i = 0; i < handles.Length; i++) { FixtureReservationHandle fixtureReservationHandle = handles[i]; if (!fixtureReservationHandle.IsValid) { continue; } for (int num = Reservations.Count - 1; num >= 0; num--) { if (Reservations[num].Id == fixtureReservationHandle.Id) { Reservations.RemoveAt(num); result = true; break; } } } return result; } } public static bool Release(string label) { if (string.IsNullOrWhiteSpace(label)) { return false; } bool result = false; lock (Sync) { for (int num = Reservations.Count - 1; num >= 0; num--) { if (string.Equals(Reservations[num].Label, label.Trim(), StringComparison.Ordinal)) { Reservations.RemoveAt(num); result = true; } } return result; } } public static void ResetRunState() { lock (Sync) { Reservations.Clear(); } } private static bool TryFindConflict(FixtureReservationObb candidate, string label, string source, out ReservationEntry idempotentEntry, out FixtureReservationConflict conflict) { idempotentEntry = null; for (int i = 0; i < Reservations.Count; i++) { ReservationEntry reservationEntry = Reservations[i]; if (Overlaps(candidate, reservationEntry.Obb)) { if (label != null && string.Equals(reservationEntry.Label, label, StringComparison.Ordinal) && string.Equals(reservationEntry.Source, source, StringComparison.Ordinal) && ApproximatelySame(candidate, reservationEntry.Obb)) { idempotentEntry = reservationEntry; conflict = default(FixtureReservationConflict); return false; } conflict = new FixtureReservationConflict(reservationEntry.Label, reservationEntry.Source); return true; } } conflict = default(FixtureReservationConflict); return false; } private static bool ApproximatelySame(FixtureReservationObb a, FixtureReservationObb b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) Vector3 val = a.Center - b.Center; if (((Vector3)(ref val)).sqrMagnitude <= 1E-06f) { val = a.HalfExtents - b.HalfExtents; if (((Vector3)(ref val)).sqrMagnitude <= 1E-08f && Mathf.Abs(Vector3.Dot(a.AxisX, b.AxisX)) >= 0.99999f && Mathf.Abs(Vector3.Dot(a.AxisY, b.AxisY)) >= 0.99999f) { return Mathf.Abs(Vector3.Dot(a.AxisZ, b.AxisZ)) >= 0.99999f; } } return false; } private static Vector3 SafeAxis(Vector3 value, Vector3 fallback) { //IL_0018: 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) if (((Vector3)(ref value)).sqrMagnitude >= 1E-08f) { return ((Vector3)(ref value)).normalized; } return ((Vector3)(ref fallback)).normalized; } private static string Normalize(string value, string fallback) { if (!string.IsNullOrWhiteSpace(value)) { return value.Trim(); } return fallback; } } public readonly struct FixtureReservationRequest { public readonly string Label; public readonly string Source; public readonly FixtureFootprint Footprint; public readonly Vector3 Position; public readonly Quaternion Rotation; public FixtureReservationRequest(string label, string source, FixtureFootprint footprint, Vector3 position, Quaternion rotation) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Label = label; Source = source; Footprint = footprint; Position = position; Rotation = rotation; } } public readonly struct FixtureReservationGroup { internal readonly FixtureReservationHandle[] Handles; public int Count { get { FixtureReservationHandle[] handles = Handles; if (handles == null) { return 0; } return handles.Length; } } public bool IsValid { get { if (Handles == null || Handles.Length == 0) { return false; } for (int i = 0; i < Handles.Length; i++) { if (!Handles[i].IsValid) { return false; } } return true; } } internal FixtureReservationGroup(FixtureReservationHandle[] handles) { Handles = handles; } } public readonly struct FixtureReservationObb { public readonly Vector3 Center; public readonly Vector3 HalfExtents; public readonly Vector3 AxisX; public readonly Vector3 AxisY; public readonly Vector3 AxisZ; public FixtureReservationObb(Vector3 center, Vector3 halfExtents, Vector3 axisX, Vector3 axisY, Vector3 axisZ) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_0094: Unknown result type (might be due to invalid IL or missing references) Center = center; HalfExtents = new Vector3(Mathf.Abs(halfExtents.x), Mathf.Abs(halfExtents.y), Mathf.Abs(halfExtents.z)); AxisX = ((((Vector3)(ref axisX)).sqrMagnitude >= 1E-08f) ? ((Vector3)(ref axisX)).normalized : Vector3.right); AxisY = ((((Vector3)(ref axisY)).sqrMagnitude >= 1E-08f) ? ((Vector3)(ref axisY)).normalized : Vector3.up); AxisZ = ((((Vector3)(ref axisZ)).sqrMagnitude >= 1E-08f) ? ((Vector3)(ref axisZ)).normalized : Vector3.forward); } } public readonly struct FixtureReservationHandle { internal readonly long Id; public readonly string Label; public bool IsValid => Id > 0; internal FixtureReservationHandle(long id, string label) { Id = id; Label = label; } } public readonly struct FixtureReservationConflict { public readonly string ExistingLabel; public readonly string ExistingSource; public bool HasConflict => !string.IsNullOrEmpty(ExistingLabel); public FixtureReservationConflict(string existingLabel, string existingSource) { ExistingLabel = existingLabel ?? "unknown"; ExistingSource = existingSource ?? "unknown"; } public string ToDiagnosticString() { return "reservation-conflict existing-label='" + (ExistingLabel ?? "unknown") + "' existing-source='" + (ExistingSource ?? "unknown") + "'"; } } public static class InteriorFixtureHooks { public static Func FixturePreviewFactory { get; set; } public static event Action BeforeExternalPlacementRequest; public static void RaiseBeforeExternalPlacementRequest() { Action beforeExternalPlacementRequest = InteriorFixtureHooks.BeforeExternalPlacementRequest; if (beforeExternalPlacementRequest == null) { return; } Delegate[] invocationList = beforeExternalPlacementRequest.GetInvocationList(); foreach (Delegate obj in invocationList) { try { ((Action)obj)(); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Placement] Pre-request fixture reservation hook failed: " + ex.GetType().Name + ": " + ex.Message)); } } } } public static GameObject CreateFixturePreview(string kind, string metadataJson) { Func fixturePreviewFactory = FixturePreviewFactory; if (fixturePreviewFactory == null) { return null; } try { return fixturePreviewFactory(kind, metadataJson); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Placement] Fixture preview factory failed for kind '" + kind + "': " + ex.GetType().Name + ": " + ex.Message)); } return null; } } } public sealed class InteriorPlacementPlan { public InteriorPlacementRole Role { get; } public InteriorPlacementProfile Profile { get; } public PlacementPose Pose { get; } public string FallbackTier { get; } public IReadOnlyList ValidationReasons { get; } public InteriorPlacementPlan(InteriorPlacementRole role, InteriorPlacementProfile profile, PlacementPose pose, string fallbackTier, IReadOnlyList validationReasons) { Role = role; Profile = profile; Pose = pose; FallbackTier = fallbackTier ?? "unknown"; ValidationReasons = validationReasons ?? new List(); } } public sealed class InteriorPlacementProfile { public string FlowName { get; } public string InteriorName { get; } public string TileFingerprint { get; } public string ProfileKey { get; } public bool HasAuthoredRules { get; } private InteriorPlacementProfile(string flowName, string interiorName, string tileFingerprint, bool hasAuthoredRules) { FlowName = (string.IsNullOrEmpty(flowName) ? "unknown-flow" : flowName); InteriorName = (string.IsNullOrEmpty(interiorName) ? "unknown-interior" : interiorName); TileFingerprint = (string.IsNullOrEmpty(tileFingerprint) ? "empty" : tileFingerprint); HasAuthoredRules = hasAuthoredRules; ProfileKey = FlowName + "|" + InteriorName + "|" + TileFingerprint; } public static InteriorPlacementProfile Detect(Dungeon dungeon) { string flowName = ResolveFlowName(dungeon); string interiorName = ResolveInteriorName(dungeon, flowName); string tileFingerprint = BuildTileFingerprint(dungeon); bool hasAuthoredRules = IsAuthored(flowName, interiorName); return new InteriorPlacementProfile(flowName, interiorName, tileFingerprint, hasAuthoredRules); } private static string ResolveFlowName(Dungeon dungeon) { try { DungeonFlow val = RoundManager.Instance?.dungeonGenerator?.Generator?.DungeonFlow; if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) { return ((Object)val).name; } } catch { } try { DungeonFlow val2 = ((dungeon != null) ? dungeon.DungeonFlow : null); if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(((Object)val2).name)) { return ((Object)val2).name; } } catch { } return "unknown-flow"; } private static string ResolveInteriorName(Dungeon dungeon, string flowName) { string text = (((Object)(object)dungeon != (Object)null && !string.IsNullOrEmpty(((Object)dungeon).name)) ? ((Object)dungeon).name : null); if (!string.IsNullOrEmpty(text)) { return text; } return flowName; } private static string BuildTileFingerprint(Dungeon dungeon) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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) if (((dungeon != null) ? dungeon.AllTiles : null) == null || dungeon.AllTiles.Count == 0) { return "tiles0"; } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); int num = 0; int num2 = 0; float num3 = 0f; for (int i = 0; i < dungeon.AllTiles.Count; i++) { Tile val = dungeon.AllTiles[i]; if (!((Object)(object)val == (Object)null)) { num++; num2 += ((val.UsedDoorways != null) ? val.UsedDoorways.Count : 0); Bounds bounds = val.Bounds; num3 += Mathf.Round(Mathf.Max(0f, ((Bounds)(ref bounds)).size.x * ((Bounds)(ref bounds)).size.z) / 25f) * 25f; string key = NormalizeTileName(((Object)val).name); dictionary.TryGetValue(key, out var value); dictionary[key] = value + 1; } } List list = new List(dictionary.Keys); list.Sort(StringComparer.Ordinal); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("tiles").Append(num).Append("_doors") .Append(num2) .Append("_area") .Append(Mathf.RoundToInt(num3)); int num4 = Mathf.Min(8, list.Count); for (int j = 0; j < num4; j++) { stringBuilder.Append('_').Append(list[j]).Append('x') .Append(dictionary[list[j]]); } return stringBuilder.ToString(); } private static string NormalizeTileName(string value) { if (string.IsNullOrEmpty(value)) { return "unnamed"; } string text = value.Replace("(Clone)", string.Empty).Trim(); if (text.Length != 0) { return text; } return "unnamed"; } private static bool IsAuthored(string flowName, string interiorName) { if (!Contains(flowName, "factory") && !Contains(flowName, "mansion") && !Contains(flowName, "manor") && !Contains(interiorName, "factory") && !Contains(interiorName, "mansion")) { return Contains(interiorName, "manor"); } return true; } private static bool Contains(string value, string token) { if (!string.IsNullOrEmpty(value)) { return value.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } } public sealed class InteriorPlacementRequest { public InteriorPlacementRole Role { get; set; } public FixtureFootprint Footprint { get; set; } public Tile PreferredTile { get; set; } public bool ForcePreferredTile { get; set; } public Tile ExcludedTile { get; set; } public IReadOnlyCollection ExcludedTiles { get; set; } public Tile MustDifferFromTile { get; set; } public Vector3? PreferredTarget { get; set; } public float MinEntranceDistance { get; set; } = 24f; public bool AllowEntranceRoom { get; set; } public bool RequireWallContact { get; set; } = true; public bool RequireFloorContact { get; set; } public bool RequireCctvLineOfSight { get; set; } public bool PreferImportantRoom { get; set; } public bool RequireImportantRoomWhenReviewed { get; set; } public bool DisallowHallway { get; set; } = true; public bool RequireBodyClearance { get; set; } = true; public bool RequireReachableInteractionPoint { get; set; } = true; public int VariantIndex { get; set; } public string DebugLabel { get; set; } } public readonly struct InteriorPlacementReviewHint { public readonly bool HasAnyReview; public readonly bool ImportantRoom; public readonly bool MainframeCandidate; public readonly bool CompanyStashCandidate; public readonly float ObjectiveScore; public readonly float CameraScoreBonus; public readonly int PositiveCount; public readonly int HardRejectCount; public readonly int SkyboxRejectCount; public readonly int FurnitureRejectCount; public readonly int MainframeRejectCount; public readonly int CompanyStashRejectCount; internal InteriorPlacementReviewHint(bool hasAnyReview, bool importantRoom, bool mainframeCandidate, bool companyStashCandidate, float objectiveScore, float cameraScoreBonus, int positiveCount, int hardRejectCount, int skyboxRejectCount, int furnitureRejectCount, int mainframeRejectCount, int companyStashRejectCount) { HasAnyReview = hasAnyReview; ImportantRoom = importantRoom; MainframeCandidate = mainframeCandidate; CompanyStashCandidate = companyStashCandidate; ObjectiveScore = objectiveScore; CameraScoreBonus = cameraScoreBonus; PositiveCount = positiveCount; HardRejectCount = hardRejectCount; SkyboxRejectCount = skyboxRejectCount; FurnitureRejectCount = furnitureRejectCount; MainframeRejectCount = mainframeRejectCount; CompanyStashRejectCount = companyStashRejectCount; } } internal static class InteriorPlacementReviewHints { private const string ApiTypeName = "Y4NGZCompany.Facility.Cameras.CctvPlacementReviewApi"; private const string LegacyApiTypeName = "LethalCCTV.Cameras.CctvPlacementReviewApi"; private static bool _lookupAttempted; private static MethodInfo _tryGetMethod; private static FieldInfo _hasAnyReviewField; private static FieldInfo _importantRoomField; private static FieldInfo _mainframeCandidateField; private static FieldInfo _companyStashCandidateField; private static FieldInfo _objectiveScoreField; private static FieldInfo _cameraScoreBonusField; private static FieldInfo _positiveCountField; private static FieldInfo _hardRejectCountField; private static FieldInfo _skyboxRejectCountField; private static FieldInfo _furnitureRejectCountField; private static FieldInfo _mainframeRejectCountField; private static FieldInfo _companyStashRejectCountField; internal static bool TryGet(Tile tile, out InteriorPlacementReviewHint hint) { hint = default(InteriorPlacementReviewHint); if ((Object)(object)tile == (Object)null) { return false; } try { if (!EnsureResolved()) { return false; } object[] array = new object[2] { tile, null }; object obj = _tryGetMethod.Invoke(null, array); if (!(obj is bool) || !(bool)obj || array[1] == null) { return false; } object source = array[1]; hint = new InteriorPlacementReviewHint(GetBool(_hasAnyReviewField, source), GetBool(_importantRoomField, source), GetBool(_mainframeCandidateField, source), GetBool(_companyStashCandidateField, source), GetFloat(_objectiveScoreField, source), GetFloat(_cameraScoreBonusField, source), GetInt(_positiveCountField, source), GetInt(_hardRejectCountField, source), GetInt(_skyboxRejectCountField, source), GetInt(_furnitureRejectCountField, source), GetInt(_mainframeRejectCountField, source), GetInt(_companyStashRejectCountField, source)); return hint.HasAnyReview; } catch { hint = default(InteriorPlacementReviewHint); return false; } } private static bool EnsureResolved() { if (_lookupAttempted) { return _tryGetMethod != null; } _lookupAttempted = true; Type type = Type.GetType("Y4NGZCompany.Facility.Cameras.CctvPlacementReviewApi, LethalCCTV", throwOnError: false) ?? Type.GetType("Y4NGZCompany.Facility.Cameras.CctvPlacementReviewApi, Y4NGZCompany", throwOnError: false) ?? Type.GetType("LethalCCTV.Cameras.CctvPlacementReviewApi, LethalCCTV", throwOnError: false) ?? FindLoadedApiType(); if (type == null) { return false; } MethodInfo method = type.GetMethod("TryGetTilePlacementHint", BindingFlags.Static | BindingFlags.Public); if (method == null) { return false; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 2 || parameters[0].ParameterType != typeof(object) || !parameters[1].IsOut) { return false; } Type elementType = parameters[1].ParameterType.GetElementType(); if (elementType == null) { return false; } _hasAnyReviewField = elementType.GetField("HasAnyReview", BindingFlags.Instance | BindingFlags.Public); _importantRoomField = elementType.GetField("ImportantRoom", BindingFlags.Instance | BindingFlags.Public); _mainframeCandidateField = elementType.GetField("MainframeCandidate", BindingFlags.Instance | BindingFlags.Public); _companyStashCandidateField = elementType.GetField("CompanyStashCandidate", BindingFlags.Instance | BindingFlags.Public); _objectiveScoreField = elementType.GetField("ObjectiveScore", BindingFlags.Instance | BindingFlags.Public); _cameraScoreBonusField = elementType.GetField("CameraScoreBonus", BindingFlags.Instance | BindingFlags.Public); _positiveCountField = elementType.GetField("PositiveCount", BindingFlags.Instance | BindingFlags.Public); _hardRejectCountField = elementType.GetField("HardRejectCount", BindingFlags.Instance | BindingFlags.Public); _skyboxRejectCountField = elementType.GetField("SkyboxRejectCount", BindingFlags.Instance | BindingFlags.Public); _furnitureRejectCountField = elementType.GetField("FurnitureRejectCount", BindingFlags.Instance | BindingFlags.Public); _mainframeRejectCountField = elementType.GetField("MainframeRejectCount", BindingFlags.Instance | BindingFlags.Public); _companyStashRejectCountField = elementType.GetField("CompanyStashRejectCount", BindingFlags.Instance | BindingFlags.Public); if (_hasAnyReviewField == null || _importantRoomField == null || _mainframeCandidateField == null || _companyStashCandidateField == null || _objectiveScoreField == null || _cameraScoreBonusField == null || _positiveCountField == null || _hardRejectCountField == null || _skyboxRejectCountField == null || _furnitureRejectCountField == null || _mainframeRejectCountField == null || _companyStashRejectCountField == null) { return false; } _tryGetMethod = method; return true; } private static Type FindLoadedApiType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("Y4NGZCompany.Facility.Cameras.CctvPlacementReviewApi", throwOnError: false); if (type != null) { return type; } } return null; } private static bool GetBool(FieldInfo field, object source) { object value = field.GetValue(source); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static float GetFloat(FieldInfo field, object source) { object value = field.GetValue(source); if (value is float) { return (float)value; } return 0f; } private static int GetInt(FieldInfo field, object source) { object value = field.GetValue(source); if (value is int) { return (int)value; } return 0; } } public enum InteriorPlacementRole { MainframeStandingBackToWall, AlarmWallMounted, VaultWallOrFloorSafe, EntranceCamera, SupportCoverageCamera, GenericWallFixture, GenericCeilingFixture, BreachRoomProp, LargeFloorFixtureBackToWall } public static class InteriorPlacementService { private readonly struct Candidate { public readonly PlacementPose Pose; public readonly float Score; public readonly string FallbackTier; public readonly PlacementValidationResult Validation; public readonly PlacementValidationResult ExpensiveValidation; public Candidate(PlacementPose pose, float score, string fallbackTier, PlacementValidationResult validation, PlacementValidationResult expensiveValidation = default(PlacementValidationResult)) { Pose = pose; Score = score; FallbackTier = fallbackTier; Validation = validation; ExpensiveValidation = expensiveValidation; } } private sealed class RejectSummary { private readonly Dictionary _byReason = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _bySource = new Dictionary(StringComparer.Ordinal); public int TotalRejects { get; private set; } public void Record(string source, string tier, string reason) { TotalRejects++; Increment(_bySource, source + "/" + tier); Increment(_byReason, NormalizeReason(reason)); } public string Format() { if (TotalRejects <= 0) { return "rejects=0"; } return $"rejects={TotalRejects} topReasons={FormatTop(_byReason)} topSources={FormatTop(_bySource)}"; } private static string NormalizeReason(string reason) { if (string.IsNullOrWhiteSpace(reason)) { return "unknown"; } reason = reason.Trim(); int num = reason.IndexOf(' '); if (num <= 0) { return reason; } return reason.Substring(0, num); } private static void Increment(Dictionary values, string key) { key = (string.IsNullOrWhiteSpace(key) ? "unknown" : key.Trim()); values.TryGetValue(key, out var value); values[key] = value + 1; } private static string FormatTop(Dictionary values) { if (values.Count == 0) { return "none"; } List> list = new List>(values); list.Sort(delegate(KeyValuePair a, KeyValuePair b) { int num3 = b.Value.CompareTo(a.Value); return (num3 == 0) ? string.CompareOrdinal(a.Key, b.Key) : num3; }); StringBuilder stringBuilder = new StringBuilder(); int num = Mathf.Min(5, list.Count); for (int num2 = 0; num2 < num; num2++) { if (num2 > 0) { stringBuilder.Append(","); } stringBuilder.Append(list[num2].Key); stringBuilder.Append("="); stringBuilder.Append(list[num2].Value); } return stringBuilder.ToString(); } } private const float WallInset = 0.12f; private const float MaxWallCast = 22f; private const float ImportantRoomMismatchRelaxedPenalty = 600f; private const int MaxReachabilityRecoveryPasses = 2; private static bool DetailedRejectLogging => CoreDiagnostics.DetailedPlacementRejectLogging; public static void ResetRunState() { FixtureReservationRegistry.ResetRunState(); InteriorProbeExporter.ResetRunState(); } public static bool TryBuildPlan(InteriorPlacementRequest request, out InteriorPlacementPlan plan) { plan = null; if (!TryPreparePlan(request, out var dungeon, out var profile, out var entrances, out var hasReviewedImportantRooms)) { return false; } RejectSummary rejectSummary = new RejectSummary(); Candidate best; bool flag = TryBuildPlanForTier(request, dungeon, entrances, hasReviewedImportantRooms, strict: true, "strict", rejectSummary, out best) || TryBuildPlanForTier(request, dungeon, entrances, hasReviewedImportantRooms, strict: false, "relaxed", rejectSummary, out best); string context = $"role={request.Role}"; int num = 0; while (!flag && num < 2) { List entrances2; InteriorEntranceAnchorPolicy.EntranceRecoveryStep entranceRecoveryStep = InteriorAnchorService.TryRecoverEntranceReachability(context, out entrances2); if (entranceRecoveryStep == InteriorEntranceAnchorPolicy.EntranceRecoveryStep.None) { break; } if (entrances2 != null && entrances2.Count > 0) { entrances = entrances2; } string text = RecoveryTierSuffix(entranceRecoveryStep); if (entranceRecoveryStep == InteriorEntranceAnchorPolicy.EntranceRecoveryStep.SuppressVeto) { LogUnvalidatedAnchorScanNotice(request); } rejectSummary = new RejectSummary(); flag = TryBuildPlanForTier(request, dungeon, entrances, hasReviewedImportantRooms, strict: true, "strict" + text, rejectSummary, out best) || TryBuildPlanForTier(request, dungeon, entrances, hasReviewedImportantRooms, strict: false, "relaxed" + text, rejectSummary, out best); num++; } if (!flag) { LogPlanFail(request, profile, rejectSummary); return false; } IReadOnlyList readOnlyList = MergeReasons(best.Validation.Reasons, best.ExpensiveValidation.Reasons); plan = new InteriorPlacementPlan(request.Role, profile, best.Pose, best.FallbackTier, readOnlyList); LogPlanOk(request, profile, best, readOnlyList); return true; } public static IEnumerator TryBuildPlanBudgeted(InteriorPlacementRequest request, Action onComplete, Func shouldYield) { if (!TryPreparePlan(request, out var dungeon, out var profile, out var entrances, out var hasReviewedImportantRooms)) { onComplete?.Invoke(arg1: false, null); yield break; } RejectSummary rejectSummary = new RejectSummary(); Candidate best = default(Candidate); bool selected = false; Action accept = delegate(Candidate candidate) { best = candidate; selected = true; }; IEnumerator tiers = RunTiersBudgeted(request, dungeon, entrances, hasReviewedImportantRooms, rejectSummary, string.Empty, accept, shouldYield); while (tiers.MoveNext()) { yield return tiers.Current; } string recoveryContext = $"role={request.Role}"; int pass = 0; while (!selected && pass < 2) { List entrances2; InteriorEntranceAnchorPolicy.EntranceRecoveryStep entranceRecoveryStep = InteriorAnchorService.TryRecoverEntranceReachability(recoveryContext, out entrances2); if (entranceRecoveryStep == InteriorEntranceAnchorPolicy.EntranceRecoveryStep.None) { break; } if (entrances2 != null && entrances2.Count > 0) { entrances = entrances2; } if (entranceRecoveryStep == InteriorEntranceAnchorPolicy.EntranceRecoveryStep.SuppressVeto) { LogUnvalidatedAnchorScanNotice(request); } rejectSummary = new RejectSummary(); IEnumerator recoveryTiers = RunTiersBudgeted(request, dungeon, entrances, hasReviewedImportantRooms, rejectSummary, RecoveryTierSuffix(entranceRecoveryStep), accept, shouldYield); while (recoveryTiers.MoveNext()) { yield return recoveryTiers.Current; } pass++; } if (!selected) { LogPlanFail(request, profile, rejectSummary); onComplete?.Invoke(arg1: false, null); yield break; } IReadOnlyList readOnlyList = MergeReasons(best.Validation.Reasons, best.ExpensiveValidation.Reasons); InteriorPlacementPlan arg = new InteriorPlacementPlan(request.Role, profile, best.Pose, best.FallbackTier, readOnlyList); LogPlanOk(request, profile, best, readOnlyList); onComplete?.Invoke(arg1: true, arg); } private static string RecoveryTierSuffix(InteriorEntranceAnchorPolicy.EntranceRecoveryStep step) { if (step != InteriorEntranceAnchorPolicy.EntranceRecoveryStep.RefreshAnchors) { return "-failopen"; } return "-recheck"; } private static bool IsRecoveryTier(string tier) { if (tier != null) { if (!tier.EndsWith("-recheck", StringComparison.Ordinal)) { return tier.EndsWith("-failopen", StringComparison.Ordinal); } return true; } return false; } private static void LogUnvalidatedAnchorScanNotice(InteriorPlacementRequest request) { if (!InteriorAnchorService.AreEntranceAnchorsValidated) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZ.InteriorPlacement] REACHABILITY_FAIL_OPEN_SCAN role={request.Role} anchorsValidated=false minEntranceDistance={request.MinEntranceDistance:0.0} allowEntranceRoom={request.AllowEntranceRoom}. Entrance-distance and entrance-room rules are advisory for this scan; the fixture may land closer to a facility entrance than the request asked for."); } } } private static IEnumerator RunTiersBudgeted(InteriorPlacementRequest request, Dungeon dungeon, IReadOnlyList entrances, bool hasReviewedImportantRooms, RejectSummary rejectSummary, string tierSuffix, Action onSelected, Func shouldYield) { bool selected = false; Action accept = delegate(Candidate candidate) { selected = true; onSelected?.Invoke(candidate); }; List strictCandidates = new List(32); IEnumerator buildStrict = BuildCandidatesBudgeted(request, dungeon, entrances, hasReviewedImportantRooms, strict: true, "strict" + tierSuffix, rejectSummary, strictCandidates, shouldYield); while (buildStrict.MoveNext()) { yield return buildStrict.Current; } if (strictCandidates.Count > 0) { strictCandidates.Sort(CompareCandidates); IEnumerator selectStrict = TrySelectFinalCandidateBudgeted(request, strictCandidates, entrances, rejectSummary, accept, shouldYield); while (selectStrict.MoveNext()) { yield return selectStrict.Current; } } if (selected) { yield break; } List relaxedCandidates = new List(32); IEnumerator buildRelaxed = BuildCandidatesBudgeted(request, dungeon, entrances, hasReviewedImportantRooms, strict: false, "relaxed" + tierSuffix, rejectSummary, relaxedCandidates, shouldYield); while (buildRelaxed.MoveNext()) { yield return buildRelaxed.Current; } if (relaxedCandidates.Count != 0) { relaxedCandidates.Sort(CompareCandidates); IEnumerator selectRelaxed = TrySelectFinalCandidateBudgeted(request, relaxedCandidates, entrances, rejectSummary, accept, shouldYield); while (selectRelaxed.MoveNext()) { yield return selectRelaxed.Current; } } } private static bool TryPreparePlan(InteriorPlacementRequest request, out Dungeon dungeon, out InteriorPlacementProfile profile, out List entrances, out bool hasReviewedImportantRooms) { dungeon = null; profile = null; entrances = null; hasReviewedImportantRooms = false; if (request == null) { return false; } RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } dungeon = (Dungeon)obj; Dungeon obj2 = dungeon; if (((obj2 != null) ? obj2.AllTiles : null) == null || dungeon.AllTiles.Count == 0) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZ.InteriorPlacement] PLAN_FAIL role={request.Role} reason=no-current-dungeon"); } return false; } InteriorProbeExporter.LogLoadedFlowInventory(); profile = InteriorPlacementProfile.Detect(dungeon); InteriorProbeExporter.ExportCurrentDungeonProbe(profile); entrances = InteriorAnchorService.GetInteriorEntrancePositions(); InteriorAnchorService.ReevaluateReachabilitySuppression(); hasReviewedImportantRooms = HasReviewedImportantRooms(dungeon, request); PlacementReviewRoundReport.NoteImportantRoomGate(request.Role.ToString(), request.RequireImportantRoomWhenReviewed & hasReviewedImportantRooms); return true; } private static bool TryBuildPlanForTier(InteriorPlacementRequest request, Dungeon dungeon, IReadOnlyList entrances, bool hasReviewedImportantRooms, bool strict, string tier, RejectSummary rejectSummary, out Candidate best) { best = default(Candidate); List list = BuildCandidates(request, dungeon, entrances, hasReviewedImportantRooms, strict, tier, rejectSummary); if (list.Count == 0) { return false; } list.Sort(CompareCandidates); return TrySelectFinalCandidate(request, list, entrances, rejectSummary, out best); } private static List BuildCandidates(InteriorPlacementRequest request, Dungeon dungeon, IReadOnlyList entrances, bool hasReviewedImportantRooms, bool strict, string tier, RejectSummary rejectSummary) { List result = new List(32); for (int i = 0; i < dungeon.AllTiles.Count; i++) { Tile val = dungeon.AllTiles[i]; if (!((Object)(object)val == (Object)null)) { ProcessTileCandidates(request, val, entrances, hasReviewedImportantRooms, strict, tier, rejectSummary, result); } } return result; } private static void ProcessTileCandidates(InteriorPlacementRequest request, Tile tile, IReadOnlyList entrances, bool hasReviewedImportantRooms, bool strict, string tier, RejectSummary rejectSummary, List result) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if ((request.ForcePreferredTile && (Object)(object)request.PreferredTile != (Object)null && tile != request.PreferredTile) || IsExcludedTile(request, tile)) { return; } Bounds bounds = tile.Bounds; float tileArea = InteriorAnchorService.GetTileArea(tile); if (!request.ForcePreferredTile || !((Object)(object)request.PreferredTile != (Object)null) || tile != request.PreferredTile) { if (tileArea < MinAreaForRole(request.Role, strict) || (request.DisallowHallway && LooksHallwayLike(bounds, tileArea, strict)) || (!request.AllowEntranceRoom && PlacementValidator.IsEntranceTile(tile, entrances))) { return; } if (!InteriorAnchorService.IsTileReachableFromEntrance(tile, entrances)) { rejectSummary.Record("tile", tier, "tile-unreachable-from-entrance"); if (DetailedRejectLogging) { LogDetailedReject($"[Y4NGZ.InteriorPlacement] PLAN_REJECT role={request.Role} tile='{((Object)tile).name}' source=tile tier={tier} reasons=tile-unreachable-from-entrance"); } return; } } InteriorPlacementReviewHint hint; bool flag = InteriorPlacementReviewHints.TryGet(tile, out hint); bool flag2 = request.RequireImportantRoomWhenReviewed && hasReviewedImportantRooms && (!flag || !IsAppropriateImportantRoomHint(request, hint)); bool flag3 = !IsRecoveryTier(tier); if (flag2) { if (strict) { if (flag3) { PlacementReviewRoundReport.NoteEngineAVeto("review-important-room-mismatch"); } return; } if (flag3) { PlacementReviewRoundReport.NoteEngineADemotion("review-important-room-mismatch"); } if (DetailedRejectLogging) { LogDetailedReject($"[Y4NGZ.InteriorPlacement] PLAN_DEMOTE role={request.Role} tile='{((Object)tile).name}' source=review tier={tier} reasons=review-important-room-mismatch penalty={600f:0}"); } } if (flag && UsesImportantRoomHints(request) && HasObjectiveSafetyReject(request, hint)) { if (!strict) { if (flag3) { PlacementReviewRoundReport.NoteEngineAVeto("review-hard-reject"); } string text = $"review-hard-reject skybox={hint.SkyboxRejectCount} furniture={hint.FurnitureRejectCount} hard={hint.HardRejectCount} mainframe={hint.MainframeRejectCount} stash={hint.CompanyStashRejectCount}"; rejectSummary.Record("review", tier, text); if (DetailedRejectLogging) { LogDetailedReject($"[Y4NGZ.InteriorPlacement] PLAN_REJECT role={request.Role} tile='{((Object)tile).name}' source=review tier={tier} reasons={text}"); } } } else { AddWallCandidates(request, tile, entrances, flag, hint, flag2, strict, tier, rejectSummary, result); if (request.Role == InteriorPlacementRole.BreachRoomProp) { AddFloorCandidate(request, tile, entrances, flag, hint, flag2, strict, tier, rejectSummary, result); } } } private static IEnumerator BuildCandidatesBudgeted(InteriorPlacementRequest request, Dungeon dungeon, IReadOnlyList entrances, bool hasReviewedImportantRooms, bool strict, string tier, RejectSummary rejectSummary, List result, Func shouldYield) { for (int i = 0; i < dungeon.AllTiles.Count; i++) { Tile val = dungeon.AllTiles[i]; if (!((Object)(object)val == (Object)null)) { ProcessTileCandidates(request, val, entrances, hasReviewedImportantRooms, strict, tier, rejectSummary, result); if (shouldYield != null && shouldYield()) { yield return null; } } } } private static void AddWallCandidates(InteriorPlacementRequest request, Tile tile, IReadOnlyList entrances, bool hasReviewHint, InteriorPlacementReviewHint reviewHint, bool importantRoomMismatch, bool strict, string tier, RejectSummary rejectSummary, List result) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: 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_0297: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: 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_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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) //IL_0159: 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_0199: 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_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: 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_0207: 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_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = tile.Bounds; Vector3 val = InteriorAnchorService.ResolveFloorPosition(((Bounds)(ref bounds)).center); float num = MountHeightForRole(request.Role); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((Bounds)(ref bounds)).center.x, val.y + num, ((Bounds)(ref bounds)).center.z); Vector3[] array = WallDirections(tile, request.VariantIndex); int num2 = ResolveCollisionMask(); bool flag = false; RaycastHit val6 = default(RaycastHit); for (int i = 0; i < array.Length; i++) { Vector3 val3 = array[i]; val3.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude < 0.001f) { continue; } ((Vector3)(ref val3)).Normalize(); Vector3 val4 = Vector3.Cross(Vector3.up, val3); Vector3 normalized = ((Vector3)(ref val4)).normalized; for (int j = -1; j <= 1; j++) { Vector3 val5 = val2 + normalized * ((float)j * 0.75f); InteriorAnchorService.RecordPhysicsQuery(); if (!Physics.Raycast(val5, val3, ref val6, 22f, num2, (QueryTriggerInteraction)1)) { continue; } flag = true; if (((RaycastHit)(ref val6)).distance < 0.35f) { continue; } Vector3 normal = ((RaycastHit)(ref val6)).normal; normal.y = 0f; if (((Vector3)(ref normal)).sqrMagnitude < 0.05f) { continue; } ((Vector3)(ref normal)).Normalize(); if (!(Vector3.Dot(normal, val3) > -0.15f)) { Vector3 position = ((RaycastHit)(ref val6)).point + normal * Mathf.Max(0.12f, request.Footprint.BackPlaneOffset); if (IsWallMountedRole(request.Role)) { position.y = val.y + Mathf.Max(0f, request.Footprint.BottomOffset); } else { position.y = val.y; } position = ClampToBounds(bounds, position, 0.35f); Quaternion rotation = BuildFixtureRotation(request, normal); Vector3 fixtureWorldFront = GetFixtureWorldFront(request, rotation, normal); Vector3 interactionPoint = position + fixtureWorldFront * Mathf.Max(0.65f, request.Footprint.FrontClearance * 0.55f) + Vector3.up * request.Footprint.InteractionHeight; TryAddCandidate(request, tile, entrances, hasReviewHint, reviewHint, importantRoomMismatch, position, rotation, normal, interactionPoint, "raycast-wall", tier, strict, rejectSummary, result); } } } if (!(flag && strict)) { Vector3[] array2 = WallDirections(tile, request.VariantIndex + 2); int num3 = (strict ? 2 : array2.Length); for (int k = 0; k < num3; k++) { Vector3 normal2; Vector3 val7 = ResolveBoundsWallPose(tile, array2[k], val.y, request, out normal2); Quaternion rotation2 = BuildFixtureRotation(request, normal2); Vector3 fixtureWorldFront2 = GetFixtureWorldFront(request, rotation2, normal2); Vector3 interactionPoint2 = val7 + fixtureWorldFront2 * Mathf.Max(0.65f, request.Footprint.FrontClearance * 0.55f) + Vector3.up * request.Footprint.InteractionHeight; TryAddCandidate(request, tile, entrances, hasReviewHint, reviewHint, importantRoomMismatch, val7, rotation2, normal2, interactionPoint2, "bounds-wall", strict ? "strict-bounds" : "relaxed-bounds", strict, rejectSummary, result); } } } private static void AddFloorCandidate(InteriorPlacementRequest request, Tile tile, IReadOnlyList entrances, bool hasReviewHint, InteriorPlacementReviewHint reviewHint, bool importantRoomMismatch, bool strict, string tier, RejectSummary rejectSummary, List result) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_0117: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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) //IL_0147: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: 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_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_005e: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = tile.Bounds; Vector3 val = InteriorAnchorService.ResolveFloorPosition(((Bounds)(ref bounds)).center); Vector3 nearestEntrancePoint = InteriorAnchorService.GetNearestEntrancePoint(entrances, val); Vector3 val2 = val - nearestEntrancePoint; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.001f) { val2 = (((Object)(object)((Component)tile).transform != (Object)null) ? ((Component)tile).transform.forward : Vector3.forward); } val2.y = 0f; ((Vector3)(ref val2)).Normalize(); float num = ((request.VariantIndex % 2 == 0) ? (-1f) : 1f); Vector3 val3 = Vector3.Cross(Vector3.up, val2); Vector3 val4 = ((Vector3)(ref val3)).normalized * num; Vector3 val5 = ClampToBounds(bounds, val + val4 * Mathf.Clamp(Mathf.Min(((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.z) * 0.35f, 0.8f, 2.2f), 0.65f); val5 = InteriorAnchorService.ResolveFloorPosition(val5 + Vector3.up * 1f); Quaternion rotation = BuildFixtureRotation(request, val2); Vector3 fixtureWorldFront = GetFixtureWorldFront(request, rotation, val2); Vector3 interactionPoint = val5 + fixtureWorldFront * Mathf.Max(0.75f, request.Footprint.FrontClearance) + Vector3.up * request.Footprint.InteractionHeight; TryAddCandidate(request, tile, entrances, hasReviewHint, reviewHint, importantRoomMismatch, val5, rotation, Vector3.zero, interactionPoint, "floor", tier, strict, rejectSummary, result); } private static Quaternion BuildFixtureRotation(InteriorPlacementRequest request, Vector3 worldFront) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = SafeHorizontalAxis(worldFront, Vector3.forward); Vector3 val2 = SafeHorizontalAxis(request.Footprint.LocalFront, Vector3.forward); Vector3 val3 = SafeAxis(request.Footprint.LocalUp, Vector3.up); if (Mathf.Abs(Vector3.Dot(val2, val3)) > 0.98f) { val3 = Vector3.up; } return Quaternion.LookRotation(val, Vector3.up) * Quaternion.Inverse(Quaternion.LookRotation(val2, val3)); } private static Vector3 GetFixtureWorldFront(InteriorPlacementRequest request, Quaternion rotation, Vector3 fallback) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) return SafeHorizontalAxis(rotation * request.Footprint.LocalFront, fallback); } private static Vector3 SafeHorizontalAxis(Vector3 value, Vector3 fallback) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) value.y = 0f; if (((Vector3)(ref value)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref value)).normalized; } fallback.y = 0f; if (((Vector3)(ref fallback)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref fallback)).normalized; } return Vector3.forward; } private static Vector3 SafeAxis(Vector3 value, Vector3 fallback) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref value)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref value)).normalized; } if (((Vector3)(ref fallback)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref fallback)).normalized; } return Vector3.up; } private static void TryAddCandidate(InteriorPlacementRequest request, Tile tile, IReadOnlyList entrances, bool hasReviewHint, InteriorPlacementReviewHint reviewHint, bool importantRoomMismatch, Vector3 position, Quaternion rotation, Vector3 wallNormal, Vector3 interactionPoint, string source, string tier, bool strict, RejectSummary rejectSummary, List result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) float num = InteriorAnchorService.EstimateTileEntrancePathDistance(tile, entrances); if (!PlacementValidator.ValidateCheap(request, tile, position, rotation, wallNormal, interactionPoint, entrances, num, out var result2)) { if (!strict) { rejectSummary.Record(source, tier, result2.PrimaryFailureName()); if (DetailedRejectLogging) { LogDetailedReject($"[Y4NGZ.InteriorPlacement] PLAN_REJECT role={request.Role} tile='{((Object)tile).name}' source={source} tier={tier} reasons={InteriorProbeExporter.FormatReasons(result2.Reasons)}"); } } } else { float score = ScoreCandidate(request, tile, hasReviewHint, reviewHint, importantRoomMismatch, position, rotation, num, source, strict); Vector3 fixtureWorldFront = GetFixtureWorldFront(request, rotation, wallNormal); PlacementPose pose = new PlacementPose(position, rotation, wallNormal, interactionPoint, tile, source, score, num, fixtureWorldFront); result.Add(new Candidate(pose, score, tier, result2)); } } private static bool TrySelectFinalCandidate(InteriorPlacementRequest request, List candidates, IReadOnlyList entrances, RejectSummary rejectSummary, out Candidate best) { best = default(Candidate); for (int i = 0; i < candidates.Count; i++) { if (TryPromoteCandidate(request, candidates[i], entrances, rejectSummary, out best)) { return true; } } return false; } private static IEnumerator TrySelectFinalCandidateBudgeted(InteriorPlacementRequest request, List candidates, IReadOnlyList entrances, RejectSummary rejectSummary, Action onSelected, Func shouldYield) { for (int i = 0; i < candidates.Count; i++) { if (TryPromoteCandidate(request, candidates[i], entrances, rejectSummary, out var promoted)) { onSelected?.Invoke(promoted); break; } if (shouldYield != null && shouldYield()) { yield return null; } } } private static bool TryPromoteCandidate(InteriorPlacementRequest request, Candidate candidate, IReadOnlyList entrances, RejectSummary rejectSummary, out Candidate promoted) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //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_00c8: 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) promoted = default(Candidate); PlacementPose pose = candidate.Pose; if (!PlacementValidator.ValidateExpensive(request, pose.Tile, pose.Position, pose.Rotation, pose.InteractionPoint, entrances, out var entranceDistance, out var result)) { rejectSummary.Record(pose.Source, candidate.FallbackTier, result.PrimaryFailureName()); if (DetailedRejectLogging) { LogDetailedReject($"[Y4NGZ.InteriorPlacement] PLAN_REJECT role={request.Role} tile='{pose.TileName}' source={pose.Source} tier={candidate.FallbackTier} stage=expensive reasons={InteriorProbeExporter.FormatReasons(result.Reasons)}"); } return false; } float score = candidate.Score - pose.EntrancePathDistance + entranceDistance; PlacementPose pose2 = new PlacementPose(pose.Position, pose.Rotation, pose.WallNormal, pose.InteractionPoint, pose.Tile, pose.Source, score, entranceDistance, pose.Forward); promoted = new Candidate(pose2, score, candidate.FallbackTier, candidate.Validation, result); return true; } private static IReadOnlyList MergeReasons(IReadOnlyList cheapReasons, IReadOnlyList expensiveReasons) { List list = new List((cheapReasons?.Count ?? 0) + (expensiveReasons?.Count ?? 0)); if (cheapReasons != null) { list.AddRange(cheapReasons); } if (expensiveReasons != null) { list.AddRange(expensiveReasons); } return list; } private static float ScoreCandidate(InteriorPlacementRequest request, Tile tile, bool hasReviewHint, InteriorPlacementReviewHint reviewHint, bool importantRoomMismatch, Vector3 position, Quaternion rotation, float path, string source, bool strict) { //IL_0001: 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_014c: Unknown result type (might be due to invalid IL or missing references) _ = tile.Bounds; float tileArea = InteriorAnchorService.GetTileArea(tile); float tileDepth = InteriorAnchorService.GetTileDepth(tile); int num = ((tile.UsedDoorways != null) ? tile.UsedDoorways.Count : 0); bool flag = tile.Placement != null && !tile.Placement.IsOnMainPath; float num2 = path + tileDepth * 260f + (flag ? 95f : 0f) - (float)num * 14f; switch (request.Role) { case InteriorPlacementRole.MainframeStandingBackToWall: num2 += SmallerSideRoomScore(tileArea) + (flag ? 125f : (-40f)); break; case InteriorPlacementRole.LargeFloorFixtureBackToWall: num2 += SmallerSideRoomScore(tileArea) * 0.7f + (flag ? 210f : (-90f)) + tileDepth * 85f; break; case InteriorPlacementRole.AlarmWallMounted: num2 += 60f + Mathf.Min(tileArea, 160f) * 0.18f; break; case InteriorPlacementRole.VaultWallOrFloorSafe: num2 += SmallerSideRoomScore(tileArea) * 0.55f - (float)request.VariantIndex * 1.5f; break; case InteriorPlacementRole.SupportCoverageCamera: if (request.PreferredTarget.HasValue) { num2 -= Vector3.Distance(position, request.PreferredTarget.Value) * 0.8f; } break; } if (source == "raycast-wall") { num2 += 90f; } if (!strict) { num2 -= 140f; } if ((Object)(object)request.PreferredTile != (Object)null && tile == request.PreferredTile) { num2 += 180f; } if (UsesImportantRoomHints(request) && hasReviewHint) { num2 += ReviewHintScore(request, reviewHint); } if (importantRoomMismatch) { num2 -= 600f; } return num2; } private static bool HasReviewedImportantRooms(Dungeon dungeon, InteriorPlacementRequest request) { if (((dungeon != null) ? dungeon.AllTiles : null) == null || !UsesImportantRoomHints(request)) { return false; } for (int i = 0; i < dungeon.AllTiles.Count; i++) { Tile val = dungeon.AllTiles[i]; if (!((Object)(object)val == (Object)null) && InteriorPlacementReviewHints.TryGet(val, out var hint) && IsAppropriateImportantRoomHint(request, hint)) { return true; } } return false; } private static void LogPlanOk(InteriorPlacementRequest request, InteriorPlacementProfile profile, Candidate best, IReadOnlyList reasons) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = CoreDiagnostics.Log; if (log != null) { object[] obj = new object[11] { profile.ProfileKey, request.Role, best.Pose.TileName, best.Pose.Source, best.FallbackTier, best.Pose.Score, best.Pose.Position.x, best.Pose.Position.y, best.Pose.Position.z, null, null }; Quaternion rotation = best.Pose.Rotation; obj[9] = ((Quaternion)(ref rotation)).eulerAngles.y; obj[10] = InteriorProbeExporter.FormatReasons(reasons); log.LogInfo((object)string.Format("[Y4NGZ.InteriorPlacement] PLAN_OK profile='{0}' role={1} tile='{2}' source={3} tier={4} score={5:0.0} pos=({6:0.00},{7:0.00},{8:0.00}) yaw={9:0.0} reasons={10}", obj)); } } private static void LogPlanFail(InteriorPlacementRequest request, InteriorPlacementProfile profile, RejectSummary rejectSummary) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZ.InteriorPlacement] PLAN_FAIL role={request.Role} profile='{profile.ProfileKey}' reason=no-valid-candidates {rejectSummary.Format()}"); } } private static bool UsesImportantRoomHints(InteriorPlacementRequest request) { if (request != null) { if (!request.PreferImportantRoom && !request.RequireImportantRoomWhenReviewed && request.Role != InteriorPlacementRole.MainframeStandingBackToWall) { return request.Role == InteriorPlacementRole.VaultWallOrFloorSafe; } return true; } return false; } private static bool IsAppropriateImportantRoomHint(InteriorPlacementRequest request, InteriorPlacementReviewHint hint) { if (HasRoleSpecificReject(request, hint)) { return false; } switch (request.Role) { case InteriorPlacementRole.MainframeStandingBackToWall: if (!hint.MainframeCandidate) { return hint.ImportantRoom; } return true; case InteriorPlacementRole.VaultWallOrFloorSafe: if (!hint.CompanyStashCandidate) { return hint.ImportantRoom; } return true; default: if (request.PreferImportantRoom || request.RequireImportantRoomWhenReviewed) { return hint.ImportantRoom; } return false; } } private static bool HasObjectiveSafetyReject(InteriorPlacementRequest request, InteriorPlacementReviewHint hint) { if (hint.SkyboxRejectCount <= 0 && hint.FurnitureRejectCount <= 0 && !HasRoleSpecificReject(request, hint)) { return hint.HardRejectCount >= 2; } return true; } private static bool HasRoleSpecificReject(InteriorPlacementRequest request, InteriorPlacementReviewHint hint) { if (request == null) { return false; } return request.Role switch { InteriorPlacementRole.MainframeStandingBackToWall => hint.MainframeRejectCount > 0, InteriorPlacementRole.VaultWallOrFloorSafe => hint.CompanyStashRejectCount > 0, _ => false, }; } private static float ReviewHintScore(InteriorPlacementRequest request, InteriorPlacementReviewHint hint) { float num = 0f; if (IsAppropriateImportantRoomHint(request, hint)) { num += 220f; } else if (hint.ImportantRoom) { num += 120f; } num += Mathf.Clamp(hint.ObjectiveScore, -100f, 160f); num += (float)Mathf.Clamp(hint.PositiveCount, 0, 8) * 18f; num -= (float)Mathf.Clamp(hint.HardRejectCount, 0, 4) * 55f; num -= (float)Mathf.Clamp(hint.SkyboxRejectCount + hint.FurnitureRejectCount, 0, 4) * 75f; if (request != null) { switch (request.Role) { case InteriorPlacementRole.MainframeStandingBackToWall: num -= (float)Mathf.Clamp(hint.MainframeRejectCount, 0, 4) * 140f; break; case InteriorPlacementRole.VaultWallOrFloorSafe: num -= (float)Mathf.Clamp(hint.CompanyStashRejectCount, 0, 4) * 140f; break; } } return Mathf.Clamp(num, -260f, 480f); } private static bool IsExcludedTile(InteriorPlacementRequest request, Tile tile) { if (request == null || (Object)(object)tile == (Object)null) { return false; } if ((Object)(object)request.ExcludedTile != (Object)null && tile == request.ExcludedTile) { return true; } IReadOnlyCollection excludedTiles = request.ExcludedTiles; if (excludedTiles == null || excludedTiles.Count == 0) { return false; } foreach (Tile item in excludedTiles) { if ((Object)(object)item != (Object)null && tile == item) { return true; } } return false; } private static float SmallerSideRoomScore(float area) { return 70f - Mathf.Abs(area - 85f) * 0.45f; } private static Vector3 ResolveBoundsWallPose(Tile tile, Vector3 direction, float floorY, InteriorPlacementRequest request, out Vector3 normal) { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0173: 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_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: 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) Bounds bounds = tile.Bounds; Vector3 val = direction; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = Vector3.forward; } ((Vector3)(ref val)).Normalize(); Vector3 center = ((Bounds)(ref bounds)).center; float num = 0.65f; if (Mathf.Abs(val.x) >= Mathf.Abs(val.z)) { float num2 = Mathf.Sign(val.x); float num3 = Mathf.Clamp(center.z + val.z * ((Bounds)(ref bounds)).extents.z * 0.42f, ((Bounds)(ref bounds)).min.z + num, ((Bounds)(ref bounds)).max.z - num); Vector3 result = default(Vector3); ((Vector3)(ref result))..ctor(center.x + num2 * Mathf.Max(0.25f, ((Bounds)(ref bounds)).extents.x - num), floorY, num3); normal = new Vector3(0f - num2, 0f, 0f); if (IsWallMountedRole(request.Role)) { result.y += Mathf.Max(0f, request.Footprint.BottomOffset); } return result; } float num4 = Mathf.Sign(val.z); float num5 = Mathf.Clamp(center.x + val.x * ((Bounds)(ref bounds)).extents.x * 0.42f, ((Bounds)(ref bounds)).min.x + num, ((Bounds)(ref bounds)).max.x - num); Vector3 result2 = default(Vector3); ((Vector3)(ref result2))..ctor(num5, floorY, center.z + num4 * Mathf.Max(0.25f, ((Bounds)(ref bounds)).extents.z - num)); normal = new Vector3(0f, 0f, 0f - num4); if (IsWallMountedRole(request.Role)) { result2.y += Mathf.Max(0f, request.Footprint.BottomOffset); } return result2; } private static Vector3[] WallDirections(Tile tile, int variant) { //IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)tile != (Object)null && (Object)(object)((Component)tile).transform != (Object)null) ? ((Component)tile).transform.forward : Vector3.forward); Vector3 val2 = (((Object)(object)tile != (Object)null && (Object)(object)((Component)tile).transform != (Object)null) ? ((Component)tile).transform.right : Vector3.right); Vector3[] array = (Vector3[])(object)new Vector3[8] { val, val2, -val, -val2, val + val2, val - val2, -val + val2, -val - val2 }; int num = (variant % array.Length + array.Length) % array.Length; if (num == 0) { return array; } Vector3[] array2 = (Vector3[])(object)new Vector3[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = array[(i + num) % array.Length]; } return array2; } internal static float MinAreaForRole(InteriorPlacementRole role, bool strict) { switch (role) { case InteriorPlacementRole.MainframeStandingBackToWall: if (!strict) { return 30f; } return 50f; case InteriorPlacementRole.LargeFloorFixtureBackToWall: if (!strict) { return 36f; } return 58f; case InteriorPlacementRole.AlarmWallMounted: if (!strict) { return 18f; } return 30f; case InteriorPlacementRole.VaultWallOrFloorSafe: if (!strict) { return 18f; } return 34f; case InteriorPlacementRole.BreachRoomProp: if (!strict) { return 24f; } return 44f; default: if (!strict) { return 12f; } return 20f; } } private static float MountHeightForRole(InteriorPlacementRole role) { return role switch { InteriorPlacementRole.AlarmWallMounted => 1.25f, InteriorPlacementRole.GenericWallFixture => 1.35f, InteriorPlacementRole.SupportCoverageCamera => 2.2f, _ => 1f, }; } private static bool IsWallMountedRole(InteriorPlacementRole role) { if (role != InteriorPlacementRole.AlarmWallMounted) { return role == InteriorPlacementRole.GenericWallFixture; } return true; } private static bool LooksHallwayLike(Bounds bounds, float area, bool strict) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return TileShapeClassifier.LooksHallwayLike(bounds, area, strict); } private static int ResolveCollisionMask() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null) { return instance.collidersAndRoomMaskAndDefault; } int num = LayerMask.NameToLayer("Room"); if (num < 0) { return -1; } return 1 << num; } private static void LogDetailedReject(string message) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogDebug((object)message); } } private static Vector3 ClampToBounds(Bounds bounds, Vector3 position, float inset) { //IL_0002: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_005c: Unknown result type (might be due to invalid IL or missing references) position.x = Mathf.Clamp(position.x, ((Bounds)(ref bounds)).min.x + inset, ((Bounds)(ref bounds)).max.x - inset); position.z = Mathf.Clamp(position.z, ((Bounds)(ref bounds)).min.z + inset, ((Bounds)(ref bounds)).max.z - inset); return position; } private static int CompareCandidates(Candidate a, Candidate b) { int num = b.Score.CompareTo(a.Score); if (num != 0) { return num; } num = string.CompareOrdinal(a.Pose.TileName, b.Pose.TileName); if (num != 0) { return num; } return string.CompareOrdinal(a.Pose.Source, b.Pose.Source); } } public static class InteriorProbeExporter { private static bool _flowInventoryLogged; private static int _lastDungeonHash; public static void ResetRunState() { _lastDungeonHash = 0; } public static void LogLoadedFlowInventory() { if (_flowInventoryLogged) { return; } _flowInventoryLogged = true; DungeonFlow[] array = Resources.FindObjectsOfTypeAll(); Array.Sort(array, (DungeonFlow a, DungeonFlow b) => string.Compare(((Object)(object)a != (Object)null) ? ((Object)a).name : string.Empty, ((Object)(object)b != (Object)null) ? ((Object)b).name : string.Empty, StringComparison.Ordinal)); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.InteriorPlacement] FLOW_INVENTORY loadedFlows={array.Length}"); } for (int num = 0; num < array.Length; num++) { DungeonFlow val = array[num]; if (!((Object)(object)val == (Object)null)) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)$"[Y4NGZ.InteriorPlacement] FLOW idx={num} name='{((Object)val).name}' nodes={SafeCount(val)}"); } } } } public static void ExportCurrentDungeonProbe(InteriorPlacementProfile profile) { //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: 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_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_020f: 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_0237: Unknown result type (might be due to invalid IL or missing references) RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null) { return; } int num = 17; for (int i = 0; i < val.AllTiles.Count; i++) { num = num * 31 + (((Object)(object)val.AllTiles[i] != (Object)null) ? ((Object)val.AllTiles[i]).name.GetHashCode() : 0); } if (_lastDungeonHash == num) { return; } _lastDungeonHash = num; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.InteriorPlacement] DUNGEON_PROFILE key='{profile.ProfileKey}' flow='{profile.FlowName}' interior='{profile.InteriorName}' authoredRules={profile.HasAuthoredRules} tileCount={val.AllTiles.Count}"); } if (!CoreDiagnostics.DetailedPlacementRejectLogging) { return; } List interiorEntrancePositions = InteriorAnchorService.GetInteriorEntrancePositions(); for (int j = 0; j < val.AllTiles.Count; j++) { Tile val2 = val.AllTiles[j]; if (!((Object)(object)val2 == (Object)null)) { Bounds bounds = val2.Bounds; float num2 = Mathf.Max(0f, ((Bounds)(ref bounds)).size.x) * Mathf.Max(0f, ((Bounds)(ref bounds)).size.z); int num3 = ((val2.UsedDoorways != null) ? val2.UsedDoorways.Count : 0); bool flag = PlacementValidator.IsEntranceTile(val2, interiorEntrancePositions); float tileDepth = InteriorAnchorService.GetTileDepth(val2); float num4 = InteriorAnchorService.EstimateTileEntrancePathDistance(val2, interiorEntrancePositions); string text = BuildRoleVerdict(val2, interiorEntrancePositions, flag, num2, num4); ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)$"[Y4NGZ.InteriorPlacement] TILE idx={j} name='{((Object)val2).name}' center=({((Bounds)(ref bounds)).center.x:0.00},{((Bounds)(ref bounds)).center.y:0.00},{((Bounds)(ref bounds)).center.z:0.00}) size=({((Bounds)(ref bounds)).size.x:0.00},{((Bounds)(ref bounds)).size.y:0.00},{((Bounds)(ref bounds)).size.z:0.00}) area={num2:0.0} doorways={num3} depth={tileDepth:0.00} entrance={flag} nearestEntrancePath={num4:0.0} verdicts={text}"); } } } } internal static string FormatReasons(IReadOnlyList reasons) { if (reasons == null || reasons.Count == 0) { return "none"; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < reasons.Count; i++) { if (i > 0) { stringBuilder.Append('|'); } stringBuilder.Append(reasons[i]); } return stringBuilder.ToString(); } private static int SafeCount(DungeonFlow flow) { try { return (flow.Nodes != null) ? flow.Nodes.Count : 0; } catch { return 0; } } private static string BuildRoleVerdict(Tile tile, IReadOnlyList entrances, bool entrance, float area, float path) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) bool flag = LooksHallwayLike(tile.Bounds, area); bool flag2 = path >= 24f; return "Mainframe=" + Verdict(!entrance && !flag && area >= 45f && flag2) + ",Alarm=" + Verdict(!flag && area >= 28f && flag2) + ",Vault=" + Verdict(!entrance && !flag && area >= 32f) + ",Camera=" + Verdict(!flag && area >= 18f); } private static bool LooksHallwayLike(Bounds bounds, float area) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return TileShapeClassifier.LooksHallwayLike(bounds, area, strict: true); } private static string Verdict(bool ok) { if (!ok) { return "fallback/reject"; } return "usable"; } } public readonly struct PlacementPose { public readonly Vector3 Position; public readonly Quaternion Rotation; public readonly Vector3 Forward; public readonly Vector3 WallNormal; public readonly Vector3 InteractionPoint; public readonly Tile Tile; public readonly string TileName; public readonly string Source; public readonly float Score; public readonly float EntrancePathDistance; public PlacementPose(Vector3 position, Quaternion rotation, Vector3 wallNormal, Vector3 interactionPoint, Tile tile, string source, float score, float entrancePathDistance) : this(position, rotation, wallNormal, interactionPoint, tile, source, score, entrancePathDistance, null) { }//IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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) public PlacementPose(Vector3 position, Quaternion rotation, Vector3 wallNormal, Vector3 interactionPoint, Tile tile, string source, float score, float entrancePathDistance, Vector3? logicalForward = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Position = position; Rotation = rotation; Forward = SafeForward(logicalForward.HasValue ? logicalForward.Value : (rotation * Vector3.forward), rotation); WallNormal = wallNormal; InteractionPoint = interactionPoint; Tile = tile; TileName = (((Object)(object)tile != (Object)null) ? ((Object)tile).name : ""); Source = source ?? "unknown"; Score = score; EntrancePathDistance = entrancePathDistance; } private static Vector3 SafeForward(Vector3 forward, Quaternion rotation) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref forward)).normalized; } Vector3 val = rotation * Vector3.forward; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref val)).normalized; } return Vector3.forward; } } public static class PlacementReviewRoundReport { private sealed class ReferenceComparer : IEqualityComparer { internal static readonly ReferenceComparer Instance = new ReferenceComparer(); private ReferenceComparer() { } public new bool Equals(object x, object y) { return x == y; } public int GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } } public const string VetoImportantRoomMismatch = "review-important-room-mismatch"; public const string VetoHardReject = "review-hard-reject"; private static readonly HashSet FlowEligible = new HashSet(ReferenceComparer.Instance); private static readonly HashSet OtherFlow = new HashSet(ReferenceComparer.Instance); private static readonly HashSet Resolved = new HashSet(ReferenceComparer.Instance); private static readonly HashSet NameRescued = new HashSet(ReferenceComparer.Instance); private static readonly HashSet BoundsPenalized = new HashSet(ReferenceComparer.Instance); private static readonly HashSet TilesQueried = new HashSet(); private static readonly Dictionary EngineAVetoes = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary EngineADemotions = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary EngineBVetoes = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary ReviewedPoseRejects = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary ImportantRoomGate = new Dictionary(StringComparer.Ordinal); private static int _localProfileCount; private static int _packProfileCount; private static bool _flushed; public static void ResetRound() { FlowEligible.Clear(); OtherFlow.Clear(); Resolved.Clear(); NameRescued.Clear(); BoundsPenalized.Clear(); TilesQueried.Clear(); EngineAVetoes.Clear(); EngineADemotions.Clear(); EngineBVetoes.Clear(); ReviewedPoseRejects.Clear(); ImportantRoomGate.Clear(); _flushed = false; } public static void NoteProfileSizes(int localCount, int packCount) { _localProfileCount = Math.Max(0, localCount); _packProfileCount = Math.Max(0, packCount); } public static void NoteOtherFlow(object review) { if (review != null) { OtherFlow.Add(review); } } public static void NoteTileQueried(int tileInstanceId) { TilesQueried.Add(tileInstanceId); } public static void NoteFlowEligible(object review) { if (review != null) { FlowEligible.Add(review); } } public static void NoteResolved(object review, bool nameRescued, bool boundsPenalized) { if (review != null) { Resolved.Add(review); if (nameRescued) { NameRescued.Add(review); } if (boundsPenalized) { BoundsPenalized.Add(review); } } } public static void NoteEngineAVeto(string reason) { Increment(EngineAVetoes, reason); } public static void NoteEngineADemotion(string reason) { Increment(EngineADemotions, reason); } public static void NoteEngineBVeto(string reason) { Increment(EngineBVetoes, reason); } public static void NoteReviewedPoseReject(string category) { Increment(ReviewedPoseRejects, category); } public static void NoteImportantRoomGate(string role, bool armed) { if (!string.IsNullOrEmpty(role)) { ImportantRoomGate.TryGetValue(role, out var value); ImportantRoomGate[role] = value || armed; } } public static void Flush(string scope) { if (_flushed) { return; } _flushed = true; int count = FlowEligible.Count; int count2 = OtherFlow.Count; int count3 = Resolved.Count; int value = Math.Max(0, count - count3); int num = count + count2; int num2 = _localProfileCount + _packProfileCount; StringBuilder stringBuilder = new StringBuilder(512); stringBuilder.Append("[Y4NGZ.PlacementReview] REVIEW_ROUND_REPORT scope=").Append(scope ?? "unknown"); stringBuilder.AppendLine(); stringBuilder.Append(" profile local=").Append(_localProfileCount).Append(" pack=") .Append(_packProfileCount) .Append(" total=") .Append(num2) .Append(" distinct-enumerated=") .Append(num); if (num != num2) { stringBuilder.Append(" (delta=").Append(num - num2).Append(" duplicate-or-unvisited)"); } stringBuilder.AppendLine(); stringBuilder.Append(" tiles-queried=").Append(TilesQueried.Count).Append(" flow-eligible=") .Append(count) .Append(" other-flow=") .Append(count2) .AppendLine(); stringBuilder.Append(" resolved=").Append(count3).Append(" dormant=") .Append(value) .Append(" name-normalizer-rescued=") .Append(NameRescued.Count) .Append(" bounds-penalized=") .Append(BoundsPenalized.Count) .AppendLine(); AppendVetoes(stringBuilder, " vetoes-engineA", EngineAVetoes); AppendVetoes(stringBuilder, " demotions-engineA", EngineADemotions); AppendVetoes(stringBuilder, " vetoes-engineB", EngineBVetoes); AppendVetoes(stringBuilder, " reviewed-pose-rejects", ReviewedPoseRejects); AppendImportantRoomGate(stringBuilder); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } if (NameRescued.Count > 0) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)$"[Y4NGZ.PlacementReview] REVIEW_NAME_RESCUE count={NameRescued.Count} — these reviews only matched because of canonical tile-name normalization; before Phase 3e they were silently dormant."); } } } private static void AppendImportantRoomGate(StringBuilder builder) { builder.Append(" important-room-gate"); if (ImportantRoomGate.Count == 0) { builder.Append(" not-consulted").AppendLine(); return; } bool flag = false; foreach (KeyValuePair item in ImportantRoomGate) { builder.Append(' ').Append(item.Key).Append('=') .Append(item.Value ? "armed" : "inert"); flag |= item.Value; } if (!flag) { builder.Append(" (no reviewed important room in this dungeon - relaxed-tier demotion path untested this round)"); } builder.AppendLine(); } private static void AppendVetoes(StringBuilder builder, string label, Dictionary vetoes) { builder.Append(label).Append(" total="); int num = 0; foreach (KeyValuePair veto in vetoes) { num += veto.Value; } builder.Append(num); foreach (KeyValuePair veto2 in vetoes) { builder.Append(' ').Append(veto2.Key).Append('=') .Append(veto2.Value); } builder.AppendLine(); } private static void Increment(Dictionary counters, string reason) { if (!string.IsNullOrEmpty(reason)) { counters.TryGetValue(reason, out var value); counters[reason] = value + 1; } } } [Flags] internal enum PlacementCheck { None = 0, Tile = 1, Request = 2, DifferentRoom = 4, RoomBounds = 8, Facing = 0x10, DoorwayBlocking = 0x20, EntranceRoom = 0x40, EntranceDistance = 0x80, ReservationConflict = 0x100, FloorContact = 0x200, InteractionBounds = 0x400, WallContact = 0x800, FrontClearance = 0x1000, BodyClearance = 0x2000, CctvLineOfSight = 0x4000, FloorSupport = 0x8000, Reachability = 0x10000, AuthoredFloorSnap = 0x20000, AuthoredRoomBounds = 0x40000, AuthoredBodyClearance = 0x80000 } internal readonly struct PlacementValidationResult { private static readonly PlacementCheck[] Order = new PlacementCheck[20] { PlacementCheck.Tile, PlacementCheck.Request, PlacementCheck.DifferentRoom, PlacementCheck.RoomBounds, PlacementCheck.Facing, PlacementCheck.DoorwayBlocking, PlacementCheck.EntranceRoom, PlacementCheck.EntranceDistance, PlacementCheck.ReservationConflict, PlacementCheck.FloorContact, PlacementCheck.InteractionBounds, PlacementCheck.WallContact, PlacementCheck.FrontClearance, PlacementCheck.BodyClearance, PlacementCheck.CctvLineOfSight, PlacementCheck.FloorSupport, PlacementCheck.Reachability, PlacementCheck.AuthoredFloorSnap, PlacementCheck.AuthoredRoomBounds, PlacementCheck.AuthoredBodyClearance }; private static readonly string[] FailNames = new string[20] { "tile=null", "request=null", "different-room-fail", "room-bounds-fail", "facing-fail", "doorway-blocking-fail", "entrance-room-fail", "entrance-distance-provisional-fail", "reservation-conflict-fail", "floor-contact-fail", "interaction-bounds-fail", "wall-contact-fail", "front-clearance-fail", "body-clearance-fail", "cctv-los-fail", "floor-support-fail", "reachability-fail", "authored-floor-snap-fail", "authored-room-bounds-fail", "authored-body-clearance-fail" }; private static readonly string[] OkNames = new string[20] { "tile-ok", "request-ok", "different-room-ok", "room-bounds-ok", "facing-ok", "doorway-blocking-ok", "entrance-room-ok", "entrance-distance-provisional-ok", "reservation-conflict-ok", "floor-contact-ok", "interaction-bounds-ok", "wall-contact-ok", "front-clearance-ok", "body-clearance-ok", "cctv-los-ok", "floor-support-ok", "reachability-ok", "authored-floor-snap-ok", "authored-room-bounds-ok", "authored-body-clearance-ok" }; private static readonly string[] SkippedNames = new string[20] { "tile-skipped", "request-skipped", "different-room-skipped", "room-bounds-skipped", "facing-skipped", "doorway-blocking-skipped", "entrance-room-skipped", "entrance-distance-provisional-skipped", "reservation-conflict-skipped", "floor-contact-skipped", "interaction-bounds-skipped", "wall-contact-skipped", "front-clearance-skipped", "body-clearance-skipped", "cctv-los-skipped", "floor-support-skipped", "reachability-skipped", "authored-floor-snap-skipped", "authored-room-bounds-skipped", "authored-body-clearance-skipped" }; internal readonly PlacementCheck Evaluated; internal readonly PlacementCheck Failed; internal readonly PlacementCheck Skipped; private readonly List _detailReasons; internal bool Passed => Failed == PlacementCheck.None; internal IReadOnlyList Reasons { get { IReadOnlyList detailReasons = _detailReasons; return detailReasons ?? BuildCompactReasons(); } } internal PlacementValidationResult(PlacementCheck evaluated, PlacementCheck failed, PlacementCheck skipped, List detailReasons) { Evaluated = evaluated; Failed = failed; Skipped = skipped; _detailReasons = detailReasons; } internal string PrimaryFailureName() { if (Failed == PlacementCheck.None) { return "none"; } for (int i = 0; i < Order.Length; i++) { if ((Failed & Order[i]) != PlacementCheck.None) { return FailNames[i]; } } return "unknown"; } private IReadOnlyList BuildCompactReasons() { List list = new List(12); for (int i = 0; i < Order.Length; i++) { PlacementCheck placementCheck = Order[i]; if ((Failed & placementCheck) != PlacementCheck.None) { list.Add(FailNames[i]); } else if ((Evaluated & placementCheck) != PlacementCheck.None) { list.Add(OkNames[i]); } else if ((Skipped & placementCheck) != PlacementCheck.None) { list.Add(SkippedNames[i]); } } return list; } } internal static class PlacementValidator { private struct Checklist { private PlacementCheck _evaluated; private PlacementCheck _failed; private PlacementCheck _skipped; private readonly List _detail; internal bool WantsDetail => _detail != null; internal Checklist(List detail) { _evaluated = PlacementCheck.None; _failed = PlacementCheck.None; _skipped = PlacementCheck.None; _detail = detail; } internal void Pass(PlacementCheck check, string reason) { _evaluated |= check; if (_detail != null && reason != null) { _detail.Add(reason); } } internal void Fail(PlacementCheck check, string reason) { _evaluated |= check; _failed |= check; if (_detail != null && reason != null) { _detail.Add(reason); } } internal void Skip(PlacementCheck check, string reason) { _skipped |= check; if (_detail != null && reason != null) { _detail.Add(reason); } } internal PlacementValidationResult Build() { return new PlacementValidationResult(_evaluated, _failed, _skipped, _detail); } } private const float AuthoredFloorSnapToleranceM = 0.85f; private const float AuthoredFloorProbeHeightM = 0.25f; private const float FloorSupportEdgeToleranceM = 0.3f; private const float FloorSupportCornerScale = 0.42f; private static bool DetailedLogging => CoreDiagnostics.DetailedPlacementRejectLogging; internal static bool ValidateCheap(InteriorPlacementRequest request, Tile tile, Vector3 position, Quaternion rotation, Vector3 wallNormal, Vector3 interactionPoint, IReadOnlyList entrances, float provisionalEntranceDistance, out PlacementValidationResult result) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00ce: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0101: 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_0127: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_0537: Unknown result type (might be due to invalid IL or missing references) //IL_04f5: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) Checklist list = new Checklist(DetailedLogging ? new List(14) : null); if (request == null) { return Reject(ref list, PlacementCheck.Request, "request=null", out result); } if ((Object)(object)tile == (Object)null) { return Reject(ref list, PlacementCheck.Tile, "tile=null", out result); } Bounds bounds = tile.Bounds; bool flag = request.ForcePreferredTile && (Object)(object)request.PreferredTile != (Object)null && tile == request.PreferredTile; if ((Object)(object)request.MustDifferFromTile != (Object)null && tile == request.MustDifferFromTile) { return Reject(ref list, PlacementCheck.DifferentRoom, "different-room-fail", out result); } list.Pass(PlacementCheck.DifferentRoom, "different-room-ok"); if (!ContainsXZ(bounds, position, 0.18f)) { return Reject(ref list, PlacementCheck.RoomBounds, "room-bounds-fail", out result); } list.Pass(PlacementCheck.RoomBounds, "room-bounds-ok"); Vector3 fixtureForward = GetFixtureForward(request, rotation); if (((Vector3)(ref fixtureForward)).sqrMagnitude < 1E-06f) { return Reject(ref list, PlacementCheck.Facing, "facing-fail zero-forward", out result); } Vector3 val = ((Bounds)(ref bounds)).center - position; val.y = 0f; float num = ((((Vector3)(ref val)).sqrMagnitude > 1E-06f) ? Vector3.Dot(fixtureForward, ((Vector3)(ref val)).normalized) : 0f); if (num < -0.35f) { return Reject(ref list, PlacementCheck.Facing, list.WantsDetail ? $"facing-fail away-from-room dot={num:0.00}" : null, out result); } list.Pass(PlacementCheck.Facing, list.WantsDetail ? $"facing-ok dot={num:0.00}" : null); if (BlocksDoorway(tile, position)) { return Reject(ref list, PlacementCheck.DoorwayBlocking, "doorway-blocking-fail", out result); } list.Pass(PlacementCheck.DoorwayBlocking, "doorway-blocking-ok"); if (!flag && !request.AllowEntranceRoom && IsEntranceTile(tile, entrances)) { return Reject(ref list, PlacementCheck.EntranceRoom, "entrance-room-fail", out result); } list.Pass(PlacementCheck.EntranceRoom, "entrance-room-ok"); if (!flag && provisionalEntranceDistance < request.MinEntranceDistance) { return Reject(ref list, PlacementCheck.EntranceDistance, list.WantsDetail ? $"entrance-distance-provisional-fail {provisionalEntranceDistance:0.0}<{request.MinEntranceDistance:0.0}" : null, out result); } list.Pass(PlacementCheck.EntranceDistance, list.WantsDetail ? $"entrance-distance-provisional-ok {provisionalEntranceDistance:0.0}" : null); if (FixtureReservationRegistry.TryGetConflict(request.Footprint, position, rotation, out var conflict)) { return Reject(ref list, PlacementCheck.ReservationConflict, list.WantsDetail ? FormatReservationConflict(conflict) : null, out result); } list.Pass(PlacementCheck.ReservationConflict, "reservation-conflict-ok"); bool flag2 = RequiresFloorSupport(request); if (flag2) { float num2 = Mathf.Abs(InteriorAnchorService.ResolveFloorPosition(position + Vector3.up * 0.75f).y - position.y); if (num2 > 0.35f) { return Reject(ref list, PlacementCheck.FloorContact, list.WantsDetail ? $"floor-contact-fail delta={num2:0.00}" : null, out result); } list.Pass(PlacementCheck.FloorContact, list.WantsDetail ? $"floor-contact-ok delta={num2:0.00}" : null); } else { list.Skip(PlacementCheck.FloorContact, "floor-contact-skipped"); } if (!HasInteractionPointSanity(bounds, position, interactionPoint, list.WantsDetail, out var reason)) { return Reject(ref list, PlacementCheck.InteractionBounds, list.WantsDetail ? ("interaction-bounds-fail " + reason) : null, out result); } list.Pass(PlacementCheck.InteractionBounds, list.WantsDetail ? ("interaction-bounds-ok " + reason) : null); if (request.RequireWallContact) { if (((Vector3)(ref wallNormal)).sqrMagnitude < 0.25f) { return Reject(ref list, PlacementCheck.WallContact, "wall-contact-fail no-normal", out result); } if (!HasBackWallContact(request, position, rotation, wallNormal, list.WantsDetail, out var reason2)) { return Reject(ref list, PlacementCheck.WallContact, list.WantsDetail ? ("wall-contact-fail " + reason2) : null, out result); } list.Pass(PlacementCheck.WallContact, list.WantsDetail ? ("wall-contact-ok " + reason2) : null); } if (!HasFrontClearance(request, position, rotation, fixtureForward)) { return Reject(ref list, PlacementCheck.FrontClearance, "front-clearance-fail", out result); } list.Pass(PlacementCheck.FrontClearance, "front-clearance-ok"); if (request.RequireBodyClearance) { if (!HasBodyClearance(request, bounds, position, rotation, fixtureForward, list.WantsDetail, out var reason3)) { return Reject(ref list, PlacementCheck.BodyClearance, list.WantsDetail ? ("body-clearance-fail " + reason3) : null, out result); } list.Pass(PlacementCheck.BodyClearance, list.WantsDetail ? ("body-clearance-ok " + reason3) : null); } else { list.Skip(PlacementCheck.BodyClearance, "body-clearance-skipped"); } if (request.RequireCctvLineOfSight && request.PreferredTarget.HasValue) { if (!HasLineOfSight(position, request.PreferredTarget.Value)) { return Reject(ref list, PlacementCheck.CctvLineOfSight, "cctv-los-fail", out result); } list.Pass(PlacementCheck.CctvLineOfSight, "cctv-los-ok"); } if (flag2) { if (!HasStableFloorSupport(request, position, rotation, list.WantsDetail, out var delta, out var detail)) { return Reject(ref list, PlacementCheck.FloorSupport, list.WantsDetail ? $"floor-support-fail {detail} delta={delta:0.00}" : null, out result); } list.Pass(PlacementCheck.FloorSupport, list.WantsDetail ? $"floor-support-ok {detail} delta={delta:0.00}" : null); } else { list.Skip(PlacementCheck.FloorSupport, "floor-support-skipped"); } list.Skip(PlacementCheck.Reachability, request.RequireReachableInteractionPoint ? "reachability-deferred" : "reachability-skipped"); result = list.Build(); return true; } internal static bool ValidateExpensive(InteriorPlacementRequest request, Tile tile, Vector3 position, Quaternion rotation, Vector3 interactionPoint, IReadOnlyList entrances, out float entranceDistance, out PlacementValidationResult result) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) Checklist list = new Checklist(DetailedLogging ? new List(4) : null); entranceDistance = 0f; if (request == null) { return Reject(ref list, PlacementCheck.Request, "request=null", out result); } if ((Object)(object)tile == (Object)null) { return Reject(ref list, PlacementCheck.Tile, "tile=null", out result); } if (FixtureReservationRegistry.TryGetConflict(request.Footprint, position, rotation, out var conflict)) { return Reject(ref list, PlacementCheck.ReservationConflict, list.WantsDetail ? FormatReservationConflict(conflict) : null, out result); } list.Pass(PlacementCheck.ReservationConflict, "reservation-conflict-ok"); bool num = request.ForcePreferredTile && (Object)(object)request.PreferredTile != (Object)null && tile == request.PreferredTile; entranceDistance = InteriorAnchorService.EstimateNearestPathDistance(entrances, position); if (!num && entranceDistance < request.MinEntranceDistance) { return Reject(ref list, PlacementCheck.EntranceDistance, list.WantsDetail ? $"entrance-distance-fail {entranceDistance:0.0}<{request.MinEntranceDistance:0.0}" : null, out result); } list.Pass(PlacementCheck.EntranceDistance, list.WantsDetail ? $"entrance-distance-ok {entranceDistance:0.0}" : null); if (request.RequireReachableInteractionPoint) { if (!Reachable(position, interactionPoint)) { return Reject(ref list, PlacementCheck.Reachability, "reachability-fail", out result); } list.Pass(PlacementCheck.Reachability, "reachability-ok"); } else { list.Skip(PlacementCheck.Reachability, "reachability-skipped"); } result = list.Build(); return true; } internal static bool ValidateAuthoredRelaxed(InteriorPlacementRequest request, Tile tile, Vector3 position, Quaternion rotation, out Vector3 snappedPosition, out PlacementValidationResult result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) snappedPosition = position; Checklist list = new Checklist(new List(6)); if (request == null) { return Reject(ref list, PlacementCheck.Request, "request=null", out result); } if ((Object)(object)tile == (Object)null) { return Reject(ref list, PlacementCheck.Tile, "tile=null", out result); } if (TrySnapAuthoredPoseToFloor(position, out var floorPosition, out var delta, out var detail)) { snappedPosition.y = floorPosition.y; list.Pass(PlacementCheck.AuthoredFloorSnap, $"authored-floor-snap-ok delta={delta:0.00} adjustment={snappedPosition.y - position.y:0.00} {detail}"); } else { list.Fail(PlacementCheck.AuthoredFloorSnap, $"authored-floor-snap-fail delta={delta:0.00} {detail}"); } if (!ContainsXZ(tile.Bounds, snappedPosition, -0.35f)) { list.Fail(PlacementCheck.AuthoredRoomBounds, "authored-room-bounds-fail"); } else { list.Pass(PlacementCheck.AuthoredRoomBounds, "authored-room-bounds-ok"); } Vector3 fixtureForward = GetFixtureForward(request, rotation); if (!HasAuthoredBodyClearance(request, snappedPosition, rotation, fixtureForward, out var reason)) { list.Fail(PlacementCheck.AuthoredBodyClearance, "authored-body-clearance-fail " + reason); } else { list.Pass(PlacementCheck.AuthoredBodyClearance, "authored-body-clearance-ok " + reason); } if (BlocksDoorway(tile, snappedPosition)) { list.Fail(PlacementCheck.DoorwayBlocking, "doorway-blocking-fail"); } else { list.Pass(PlacementCheck.DoorwayBlocking, "doorway-blocking-ok"); } if ((Object)(object)request.MustDifferFromTile != (Object)null && tile == request.MustDifferFromTile) { list.Fail(PlacementCheck.DifferentRoom, "different-room-fail"); } else { list.Pass(PlacementCheck.DifferentRoom, "different-room-ok"); } if (FixtureReservationRegistry.TryGetConflict(request.Footprint, snappedPosition, rotation, out var conflict)) { list.Fail(PlacementCheck.ReservationConflict, FormatReservationConflict(conflict)); } else { list.Pass(PlacementCheck.ReservationConflict, "reservation-conflict-ok"); } result = list.Build(); return result.Passed; } private static bool Reject(ref Checklist list, PlacementCheck check, string reason, out PlacementValidationResult result) { list.Fail(check, reason); result = list.Build(); return false; } private static bool RequiresFloorSupport(InteriorPlacementRequest request) { if (!request.RequireFloorContact && request.Role != InteriorPlacementRole.MainframeStandingBackToWall && request.Role != InteriorPlacementRole.VaultWallOrFloorSafe && request.Role != InteriorPlacementRole.BreachRoomProp) { return request.Role == InteriorPlacementRole.LargeFloorFixtureBackToWall; } return true; } private static string FormatReservationConflict(FixtureReservationConflict conflict) { return "reservation-conflict-fail existing-label='" + conflict.ExistingLabel + "' existing-source='" + conflict.ExistingSource + "'"; } internal static bool IsEntranceTile(Tile tile, IReadOnlyList entrances) { //IL_004e: 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_0069: 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_0071: 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) if ((Object)(object)tile == (Object)null) { return false; } string value = ((Object)tile).name ?? string.Empty; if (Contains(value, "StartRoom") || Contains(value, "Entrance") || Contains(value, "EntryRoom")) { return true; } if (entrances == null) { return false; } for (int i = 0; i < entrances.Count; i++) { if (ContainsXZ(tile.Bounds, entrances[i], 0.5f)) { return true; } Bounds bounds = tile.Bounds; if (InteriorAnchorService.HorizontalDistance(((Bounds)(ref bounds)).center, entrances[i]) < 4f) { return true; } } return false; } private static Vector3 GetFixtureForward(InteriorPlacementRequest request, Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = rotation * Vector3.forward; Vector3 val2 = rotation * request.Footprint.LocalFront; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref val2)).normalized; } val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude >= 1E-06f) { return ((Vector3)(ref val)).normalized; } return Vector3.forward; } private static bool Reachable(Vector3 position, Vector3 interactionPoint) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(interactionPoint, ref val, 2f, -1)) { return false; } NavMeshHit val2 = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref val2, 2.5f, -1)) { return true; } NavMeshPath val3 = new NavMeshPath(); InteriorAnchorService.RecordNavMeshPathCalculation(); if (NavMesh.CalculatePath(((NavMeshHit)(ref val)).position, ((NavMeshHit)(ref val2)).position, -1, val3)) { return (int)val3.status == 0; } return false; } private static bool HasInteractionPointSanity(Bounds roomBounds, Vector3 position, Vector3 interactionPoint, bool wantDetail, out string reason) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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) if (!ContainsXZ(roomBounds, interactionPoint, -0.35f)) { reason = (wantDetail ? $"xz-outside point=({interactionPoint.x:0.00},{interactionPoint.z:0.00})" : null); return false; } float num = interactionPoint.y - position.y; if (num < 0.05f || num > 2.85f) { reason = (wantDetail ? $"height-from-position={num:0.00}" : null); return false; } Vector3 val = InteriorAnchorService.ResolveFloorPosition(interactionPoint + Vector3.up * 0.35f); float num2 = Mathf.Abs(interactionPoint.y - val.y); if (num2 > 3.1f) { reason = (wantDetail ? $"floor-gap={num2:0.00}" : null); return false; } reason = (wantDetail ? $"height={num:0.00} floor-gap={num2:0.00}" : null); return true; } private static bool HasStableFloorSupport(InteriorPlacementRequest request, Vector3 position, Quaternion rotation, bool wantDetail, out float delta, out string detail) { //IL_0021: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003e: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_017d: 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_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: 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) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) delta = 0f; StartOfRound instance = StartOfRound.Instance; int num = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Vector3 val = position + Vector3.up * 0.65f; InteriorAnchorService.RecordPhysicsQuery(); RaycastHit val2 = default(RaycastHit); if (!Physics.Raycast(val, Vector3.down, ref val2, 2.25f, num, (QueryTriggerInteraction)1)) { delta = 99f; detail = "no-hit"; return false; } delta = Mathf.Abs(((RaycastHit)(ref val2)).point.y - position.y); if (delta > 0.38f) { detail = "center-gap"; return false; } if (Vector3.Dot(((RaycastHit)(ref val2)).normal, Vector3.up) <= 0.45f) { detail = "sloped"; return false; } if (IsPropSupportSurface(((RaycastHit)(ref val2)).collider)) { object obj; if (!wantDetail) { obj = "prop-surface"; } else { Collider collider = ((RaycastHit)(ref val2)).collider; obj = "prop-surface hit=" + (((collider != null) ? ((Object)collider).name : null) ?? ""); } detail = (string)obj; return false; } Vector3 size = request.Footprint.Size; float num2 = Mathf.Clamp(size.x * 0.42f, 0.22f, 0.8f); float num3 = Mathf.Clamp(size.z * 0.42f, 0.22f, 0.8f); Vector3 val3 = rotation * Vector3.right; Vector3 val4 = rotation * Vector3.forward; val3.y = 0f; val4.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude < 1E-06f) { val3 = Vector3.right; } else { ((Vector3)(ref val3)).Normalize(); } if (((Vector3)(ref val4)).sqrMagnitude < 1E-06f) { val4 = Vector3.forward; } else { ((Vector3)(ref val4)).Normalize(); } RaycastHit val6 = default(RaycastHit); for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { Vector3 val5 = val + val3 * (num2 * (float)i) + val4 * (num3 * (float)j); InteriorAnchorService.RecordPhysicsQuery(); if (!Physics.Raycast(val5, Vector3.down, ref val6, 2.25f, num, (QueryTriggerInteraction)1)) { detail = (wantDetail ? $"corner-no-hit sx={i} sz={j}" : "corner-no-hit"); return false; } if (Mathf.Abs(((RaycastHit)(ref val6)).point.y - ((RaycastHit)(ref val2)).point.y) > 0.3f) { detail = (wantDetail ? $"corner-edge sx={i} sz={j} gap={Mathf.Abs(((RaycastHit)(ref val6)).point.y - ((RaycastHit)(ref val2)).point.y):0.00}" : "corner-edge"); return false; } if (IsPropSupportSurface(((RaycastHit)(ref val6)).collider)) { object obj2; if (!wantDetail) { obj2 = "corner-prop"; } else { Collider collider2 = ((RaycastHit)(ref val6)).collider; obj2 = "corner-prop hit=" + (((collider2 != null) ? ((Object)collider2).name : null) ?? ""); } detail = (string)obj2; return false; } } } detail = "floor"; return true; } private static bool TrySnapAuthoredPoseToFloor(Vector3 position, out Vector3 floorPosition, out float delta, out string detail) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) floorPosition = position; delta = 99f; StartOfRound instance = StartOfRound.Instance; int num = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Vector3 val = position + Vector3.up * 0.25f; InteriorAnchorService.RecordPhysicsQuery(); RaycastHit val2 = default(RaycastHit); if (!Physics.Raycast(val, Vector3.down, ref val2, 1.25f, num, (QueryTriggerInteraction)1)) { detail = "center-no-hit"; return false; } floorPosition = ((RaycastHit)(ref val2)).point; delta = Mathf.Abs(((RaycastHit)(ref val2)).point.y - position.y); if (delta > 0.85f) { detail = $"outside-tolerance max={0.85f:0.00}"; return false; } if (Vector3.Dot(((RaycastHit)(ref val2)).normal, Vector3.up) <= 0.45f) { detail = "center-sloped"; return false; } if (IsPropSupportSurface(((RaycastHit)(ref val2)).collider)) { Collider collider = ((RaycastHit)(ref val2)).collider; detail = "center-prop-surface hit=" + (((collider != null) ? ((Object)collider).name : null) ?? ""); return false; } Collider collider2 = ((RaycastHit)(ref val2)).collider; detail = "center-floor hit=" + (((collider2 != null) ? ((Object)collider2).name : null) ?? ""); return true; } private static bool HasAuthoredBodyClearance(InteriorPlacementRequest request, Vector3 position, Quaternion rotation, Vector3 forward, out string reason) { //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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00dd: 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_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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018b: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) if (!request.RequireBodyClearance) { reason = "skipped"; return true; } if (((Vector3)(ref forward)).sqrMagnitude < 1E-06f) { reason = "zero-forward"; return false; } Vector3 size = request.Footprint.Size; float num = Mathf.Clamp(size.x * 0.3f, 0.22f, 0.9f); float num2 = Mathf.Clamp(size.y * 0.36f, 0.35f, 1.2f); float num3 = Mathf.Clamp(size.z * 0.2f, 0.12f, 0.45f); float num4 = Mathf.Max(0.08f, num3 - Mathf.Min(request.Footprint.BackPlaneOffset, num3 * 0.75f)); Vector3 val = position + ((Vector3)(ref forward)).normalized * num4 + Vector3.up * Mathf.Max(num2 + 0.1f, request.Footprint.BottomOffset + num2); StartOfRound instance = StartOfRound.Instance; int num5 = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref forward)).normalized, Vector3.up); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(num, num2, num3); InteriorAnchorService.RecordPhysicsQuery(); if (Physics.CheckBox(val, val3, val2, num5, (QueryTriggerInteraction)1)) { reason = $"core-embedded center=({val.x:0.00},{val.y:0.00},{val.z:0.00})"; return false; } reason = $"core-clear center=({val.x:0.00},{val.y:0.00},{val.z:0.00})"; return true; } private static bool IsPropSupportSurface(Collider collider) { if ((Object)(object)collider == (Object)null) { return true; } if ((Object)(object)collider.attachedRigidbody != (Object)null) { return true; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return true; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return true; } return false; } private static bool HasBackWallContact(InteriorPlacementRequest request, Vector3 position, Quaternion rotation, Vector3 wallNormal, bool wantDetail, out string reason) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00e6: 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_00f6: 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_0116: 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) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Vector3 fixtureForward = GetFixtureForward(request, rotation); Vector3 val = wallNormal; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.25f) { reason = "no-normal"; return false; } ((Vector3)(ref val)).Normalize(); float num = ((((Vector3)(ref fixtureForward)).sqrMagnitude >= 1E-06f) ? Vector3.Dot(fixtureForward, val) : 0f); if (num < 0.45f) { reason = (wantDetail ? $"normal-mismatch dot={num:0.00}" : "normal-mismatch"); return false; } StartOfRound instance = StartOfRound.Instance; int num2 = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); float num3 = Mathf.Clamp(request.Footprint.BackPlaneOffset + 0.55f, 0.45f, 1.4f); Vector3 val2 = position + fixtureForward * 0.18f + Vector3.up * Mathf.Clamp(request.Footprint.InteractionHeight, 0.55f, 1.45f); InteriorAnchorService.RecordPhysicsQuery(); RaycastHit val3 = default(RaycastHit); if (!Physics.Raycast(val2, -fixtureForward, ref val3, num3, num2, (QueryTriggerInteraction)1)) { reason = "no-surface"; return false; } Vector3 normal = ((RaycastHit)(ref val3)).normal; normal.y = 0f; float num4 = ((((Vector3)(ref normal)).sqrMagnitude >= 1E-06f) ? Vector3.Dot(((Vector3)(ref normal)).normalized, val) : 0f); if (num4 < 0.35f) { reason = (wantDetail ? $"surface-normal-mismatch dot={num4:0.00}" : "surface-normal-mismatch"); return false; } reason = (wantDetail ? $"surface distance={((RaycastHit)(ref val3)).distance:0.00}" : "surface"); return true; } private static bool HasFrontClearance(InteriorPlacementRequest request, Vector3 position, Quaternion rotation, Vector3 forward) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; int num = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Vector3 val = position + forward * (request.Footprint.FrontClearance * 0.55f) + Vector3.up * request.Footprint.InteractionHeight; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Max(0.35f, request.Footprint.Size.x * 0.36f), 0.62f, Mathf.Max(0.35f, request.Footprint.FrontClearance * 0.45f)); Quaternion val3 = ((((Vector3)(ref forward)).sqrMagnitude >= 1E-06f) ? Quaternion.LookRotation(forward, Vector3.up) : rotation); InteriorAnchorService.RecordPhysicsQuery(); return !Physics.CheckBox(val, val2, val3, num, (QueryTriggerInteraction)1); } private static bool HasBodyClearance(InteriorPlacementRequest request, Bounds roomBounds, Vector3 position, Quaternion rotation, Vector3 forward, bool wantDetail, out string reason) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00ad: 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_00d5: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019c: 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_0152: 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_016a: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref forward)).sqrMagnitude < 1E-06f) { reason = "zero-forward"; return false; } Vector3 size = request.Footprint.Size; float num = Mathf.Clamp(size.x * 0.46f, 0.28f, 1.4f); float num2 = Mathf.Clamp(size.y * 0.46f, 0.45f, 1.8f); float num3 = Mathf.Clamp(size.z * 0.34f, 0.18f, 0.75f); float num4 = Mathf.Max(0.08f, num3 - Mathf.Min(request.Footprint.BackPlaneOffset, num3 * 0.75f)); Vector3 val = position + ((Vector3)(ref forward)).normalized * num4 + Vector3.up * Mathf.Max(num2 + 0.05f, request.Footprint.BottomOffset + num2); if (!ContainsXZ(roomBounds, val, 0.05f)) { reason = "outside-room"; return false; } StartOfRound instance = StartOfRound.Instance; int num5 = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref forward)).normalized, Vector3.up); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(num, num2, num3); InteriorAnchorService.RecordPhysicsQuery(); if (Physics.CheckBox(val, val3, val2, num5, (QueryTriggerInteraction)1)) { reason = (wantDetail ? $"blocked center=({val.x:0.00},{val.y:0.00},{val.z:0.00})" : "blocked"); return false; } reason = (wantDetail ? $"clear center=({val.x:0.00},{val.y:0.00},{val.z:0.00})" : "clear"); return true; } private static bool BlocksDoorway(Tile tile, Vector3 position) { //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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (tile?.UsedDoorways == null) { return false; } for (int i = 0; i < tile.UsedDoorways.Count; i++) { Doorway val = tile.UsedDoorways[i]; if (!((Object)(object)val == (Object)null)) { Vector3 position2 = ((Component)val).transform.position; position2.y = position.y; if (Vector3.Distance(position2, position) < 1.85f) { return true; } } } return false; } private static bool HasLineOfSight(Vector3 from, Vector3 to) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; int num = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Vector3 val = from + Vector3.up * 0.15f; Vector3 val2 = to + Vector3.up * 0.85f; InteriorAnchorService.RecordPhysicsQuery(); return !Physics.Linecast(val, val2, num, (QueryTriggerInteraction)1); } private static bool ContainsXZ(Bounds bounds, Vector3 point, float inset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (point.x >= ((Bounds)(ref bounds)).min.x + inset && point.x <= ((Bounds)(ref bounds)).max.x - inset && point.z >= ((Bounds)(ref bounds)).min.z + inset) { return point.z <= ((Bounds)(ref bounds)).max.z - inset; } return false; } private static bool Contains(string value, string token) { return value.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } } public delegate bool ShipScopedSavedPoseResolver(string objectKind, string objectId, out Vector3 worldPosition, out Quaternion worldRotation); public static class ShipScopedPlacementHooks { public static Func SaveHandler { get; set; } public static ShipScopedSavedPoseResolver SavedPoseResolver { get; set; } public static Func DeleteHandler { get; set; } public static string Save(string objectKind, string objectId, Transform sourceTransform, string metadataJson) { Func saveHandler = SaveHandler; if (saveHandler == null) { return "save failed: no ship-scoped placement handler registered (is LethalCCTV loaded?)"; } try { return saveHandler(objectKind, objectId, sourceTransform, metadataJson) ?? "save failed: handler declined the kind"; } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Placement] Ship-scoped save handler failed for kind '" + objectKind + "': " + ex.GetType().Name + ": " + ex.Message)); } return "save failed: " + ex.Message; } } public static bool TryGetSavedPose(string objectKind, string objectId, out Vector3 worldPosition, out Quaternion worldRotation) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) worldPosition = Vector3.zero; worldRotation = Quaternion.identity; ShipScopedSavedPoseResolver savedPoseResolver = SavedPoseResolver; if (savedPoseResolver == null) { return false; } try { return savedPoseResolver(objectKind, objectId, out worldPosition, out worldRotation); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Placement] Ship-scoped pose resolver failed for kind '" + objectKind + "': " + ex.GetType().Name + ": " + ex.Message)); } return false; } } public static string Delete(string objectKind, string objectId) { Func deleteHandler = DeleteHandler; if (deleteHandler == null) { return "delete failed: no ship-scoped placement handler registered (is LethalCCTV loaded?)"; } try { return deleteHandler(objectKind, objectId) ?? "delete failed: handler declined the kind"; } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Placement] Ship-scoped delete handler failed for kind '" + objectKind + "': " + ex.GetType().Name + ": " + ex.Message)); } return "delete failed: " + ex.Message; } } } internal enum TileClearanceCellState : byte { Clear, OutsideTile, NoFloor, FloorPlane, Ceiling, Clutter, NavMesh } internal sealed class TileClearanceGridSettings { internal float MinCeilingMeters = 3.5f; internal float CeilingProbeMeters = 9f; internal float ClutterProbeHeightMeters = 2f; internal float FloorPlaneToleranceMeters = 0.25f; internal float NavSampleRadiusMeters = 0.5f; internal double FrameBudgetMilliseconds = 3.0; } internal sealed class TileClearanceGrid { internal const float CellSizeMeters = 0.5f; internal const int MaxCellsPerAxis = 64; private static readonly Collider[] OverlapBuffer = (Collider[])(object)new Collider[16]; internal Tile Tile; internal int CellsX; internal int CellsZ; internal Vector3 Pivot; internal Vector3 Right; internal Vector3 Forward; internal Quaternion TileRotation; internal float Yaw; internal float DominantFloorY; internal bool HasFloorPlane; internal TileClearanceCellState[] States; internal Vector3[] FloorPoints; internal float[] Ceilings; internal int CellCount => CellsX * CellsZ; internal Vector3 GridPoint(float i, float j) { //IL_0001: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_002f: Unknown result type (might be due to invalid IL or missing references) return Pivot + Right * (i * 0.5f) + Forward * (j * 0.5f); } internal Vector3 CellCenter(int i, int j) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) return GridPoint((float)i + 0.5f, (float)j + 0.5f); } internal bool IsClear(int i, int j) { if (i < 0 || j < 0 || i >= CellsX || j >= CellsZ) { return false; } return States[j * CellsX + i] == TileClearanceCellState.Clear; } internal static IEnumerator Build(Tile tile, TileClearanceGridSettings settings, bool budgeted, Stopwatch frame, TileClearanceGrid result) { Bounds bounds = tile.Bounds; Quaternion tileRotation = ((Component)tile).transform.rotation; Vector3 right = tileRotation * Vector3.right; Vector3 forward = tileRotation * Vector3.forward; result.Tile = tile; result.TileRotation = tileRotation; result.Right = right; result.Forward = forward; result.Yaw = ((Quaternion)(ref tileRotation)).eulerAngles.y; Vector3 size = ((Bounds)(ref bounds)).size; float num = 0.5f * (Mathf.Abs(right.x) * size.x + Mathf.Abs(right.y) * size.y + Mathf.Abs(right.z) * size.z); float num2 = 0.5f * (Mathf.Abs(forward.x) * size.x + Mathf.Abs(forward.y) * size.y + Mathf.Abs(forward.z) * size.z); int cellsX = Mathf.Clamp(Mathf.FloorToInt(num * 2f / 0.5f), 0, 64); int cellsZ = Mathf.Clamp(Mathf.FloorToInt(num2 * 2f / 0.5f), 0, 64); result.CellsX = cellsX; result.CellsZ = cellsZ; if (cellsX <= 0 || cellsZ <= 0) { yield break; } Vector3 val = InteriorAnchorService.ResolveFloorPosition(((Bounds)(ref bounds)).center); Vector3 pivot = (result.Pivot = new Vector3(((Bounds)(ref bounds)).center.x, val.y, ((Bounds)(ref bounds)).center.z) - right * ((float)cellsX * 0.5f * 0.5f) - forward * ((float)cellsZ * 0.5f * 0.5f)); int num3 = cellsX * cellsZ; TileClearanceCellState[] states = new TileClearanceCellState[num3]; Vector3[] floorPoints = (Vector3[])(object)new Vector3[num3]; Collider[] floorColliders = (Collider[])(object)new Collider[num3]; float[] ceilings = new float[num3]; result.States = states; result.FloorPoints = floorPoints; result.Ceilings = ceilings; StartOfRound instance = StartOfRound.Instance; int mask = (((Object)(object)instance != (Object)null) ? instance.collidersAndRoomMaskAndDefault : (-1)); Dictionary planeVotes = new Dictionary(); RaycastHit val3 = default(RaycastHit); for (int j = 0; j < cellsZ; j++) { for (int i = 0; i < cellsX; i++) { int num4 = j * cellsX + i; Vector3 val2 = (floorPoints[num4] = pivot + right * (((float)i + 0.5f) * 0.5f) + forward * (((float)j + 0.5f) * 0.5f)); if (val2.x < ((Bounds)(ref bounds)).min.x || val2.x > ((Bounds)(ref bounds)).max.x || val2.z < ((Bounds)(ref bounds)).min.z || val2.z > ((Bounds)(ref bounds)).max.z) { states[num4] = TileClearanceCellState.OutsideTile; continue; } InteriorAnchorService.RecordPhysicsQuery(); if (!Physics.Raycast(val2 + Vector3.up * 5f, Vector3.down, ref val3, 12f, mask, (QueryTriggerInteraction)1)) { states[num4] = TileClearanceCellState.NoFloor; continue; } floorPoints[num4] = ((RaycastHit)(ref val3)).point; floorColliders[num4] = ((RaycastHit)(ref val3)).collider; int key = Mathf.RoundToInt(((RaycastHit)(ref val3)).point.y / settings.FloorPlaneToleranceMeters); planeVotes.TryGetValue(key, out var value); planeVotes[key] = value + 1; } if (budgeted && frame.Elapsed.TotalMilliseconds >= settings.FrameBudgetMilliseconds) { frame.Restart(); yield return null; } } if (planeVotes.Count == 0) { yield break; } int num5 = 0; int num6 = -1; foreach (KeyValuePair item in planeVotes) { if (item.Value > num6) { num6 = item.Value; num5 = item.Key; } } float dominantFloorY = (result.DominantFloorY = (float)num5 * settings.FloorPlaneToleranceMeters); result.HasFloorPlane = true; RaycastHit val5 = default(RaycastHit); NavMeshHit val6 = default(NavMeshHit); for (int j = 0; j < cellsZ; j++) { for (int k = 0; k < cellsX; k++) { int num7 = j * cellsX + k; if (states[num7] != TileClearanceCellState.Clear) { continue; } Vector3 val4 = floorPoints[num7]; if (Mathf.Abs(val4.y - dominantFloorY) > settings.FloorPlaneToleranceMeters) { states[num7] = TileClearanceCellState.FloorPlane; continue; } InteriorAnchorService.RecordPhysicsQuery(); float num8 = settings.CeilingProbeMeters; if (Physics.Raycast(val4 + Vector3.up * 0.1f, Vector3.up, ref val5, settings.CeilingProbeMeters, mask, (QueryTriggerInteraction)1)) { num8 = ((RaycastHit)(ref val5)).distance + 0.1f; } if (num8 < settings.MinCeilingMeters) { states[num7] = TileClearanceCellState.Ceiling; continue; } ceilings[num7] = num8; if (HasClutter(val4, tileRotation, floorColliders[num7], mask, settings.ClutterProbeHeightMeters)) { states[num7] = TileClearanceCellState.Clutter; } else if (!NavMesh.SamplePosition(val4 + Vector3.up * 0.1f, ref val6, settings.NavSampleRadiusMeters, -1)) { states[num7] = TileClearanceCellState.NavMesh; } else { floorPoints[num7] = new Vector3(val4.x, ((NavMeshHit)(ref val6)).position.y, val4.z); } } if (budgeted && frame.Elapsed.TotalMilliseconds >= settings.FrameBudgetMilliseconds) { frame.Restart(); yield return null; } } } private static bool HasClutter(Vector3 floor, Quaternion tileRotation, Collider floorCollider, int mask, float probeHeightMeters) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Vector3 val = floor + Vector3.up * (probeHeightMeters * 0.5f + 0.05f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(0.225f, probeHeightMeters * 0.5f, 0.225f); InteriorAnchorService.RecordPhysicsQuery(); int num = Physics.OverlapBoxNonAlloc(val, val2, OverlapBuffer, tileRotation, mask, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider val3 = OverlapBuffer[i]; if (!((Object)(object)val3 == (Object)null) && val3 != floorCollider) { return true; } } return false; } } } namespace Y4NGZCompany.Facility.Interior.Placement.Authored { public static class AuthoredInteriorPlacementKinds { public const string Mainframe = "mainframe"; public const string CctvCamera = "cctv-camera"; public const string CameraDeleted = "camera-deleted"; public const string CameraDisabled = "camera-disabled"; public const string BlacksiteContainer = "blacksite-container"; public const string DeadDropBomb = "dead-drop-bomb"; public const string Vault = "vault"; public const string PestTrap = "pest-trap"; public const string WasteIncinerator = "waste-incinerator"; public const string CctvNote = "cctv-note"; public static string Normalize(string value) { if (string.IsNullOrWhiteSpace(value)) { return "unknown"; } string text = value.Trim().ToLowerInvariant().Replace("_", "-") .Replace(" ", "-"); switch (text) { case "camera": case "cctv": case "cctvcamera": case "cctv-camera": return "cctv-camera"; case "camera-deleted": return "camera-deleted"; case "camera-disabled": return "camera-disabled"; case "container": case "blacksite": case "blacksitecontainer": case "shipping-container": case "blacksite-container": return "blacksite-container"; case "defuse": case "bomb": case "dead-drop-bomb": case "dead-drop": case "deaddrop": case "dead-dropbomb": case "deaddrop-bomb": case "deaddropbomb": case "defusal": return "dead-drop-bomb"; case "mainframe": return "mainframe"; case "mini-vault": case "minivault": case "vault": return "vault"; case "pest": case "pestcontrol": case "pestcontroltrap": case "pest-control": return "pest-trap"; case "incinerator": case "waste-disposal": case "wastedisposal": case "wasteincinerator": case "waste-incinerator": return "waste-incinerator"; case "note": case "stickynote": case "sticky-note": case "cctv-note": case "cctvnote": case "cctv-sticky-note": return "cctv-note"; default: return text; } } public static bool CanForceTile(string objectKind) { string a = Normalize(objectKind); if (!string.Equals(a, "blacksite-container", StringComparison.OrdinalIgnoreCase)) { return string.Equals(a, "dead-drop-bomb", StringComparison.OrdinalIgnoreCase); } return true; } public static bool IsShipScoped(string objectKind) { return string.Equals(Normalize(objectKind), "cctv-note", StringComparison.OrdinalIgnoreCase); } public static bool IsCctvCamera(string objectKind) { return string.Equals(Normalize(objectKind), "cctv-camera", StringComparison.OrdinalIgnoreCase); } public static string DisplayLabel(string objectKind) { switch (Normalize(objectKind)) { case "mainframe": return "Mainframe"; case "cctv-camera": return "CCTV Camera"; case "blacksite-container": return "Blacksite Container"; case "dead-drop-bomb": return "Dead Drop Bomb"; case "vault": return "Company Stash"; case "pest-trap": return "Pest Control Trap"; case "waste-incinerator": return "Waste Incinerator"; case "cctv-note": return "CCTV Sticky Note"; default: if (!string.IsNullOrWhiteSpace(objectKind)) { return objectKind.Trim(); } return "Unknown"; } } } [Serializable] public sealed class BlacksiteContainerPlacementMetadata { public string containerSize = "medium"; } [Serializable] public sealed class CctvCameraPlacementMetadata { public string cameraLabel = ""; public string source = ""; } [Serializable] public sealed class VaultPlacementMetadata { public string assetName = ""; public string displayName = ""; public int displayIndex = -1; } public static class AuthoredInteriorPlacementMetadata { public static string Container(string containerSize) { return JsonUtility.ToJson((object)new BlacksiteContainerPlacementMetadata { containerSize = NormalizeContainerSize(containerSize) }); } public static string CctvCamera(string cameraLabel, string source) { return JsonUtility.ToJson((object)new CctvCameraPlacementMetadata { cameraLabel = (cameraLabel ?? string.Empty), source = (source ?? string.Empty) }); } public static string Vault(string assetName, string displayName, int displayIndex) { return JsonUtility.ToJson((object)new VaultPlacementMetadata { assetName = (assetName ?? string.Empty), displayName = (displayName ?? string.Empty), displayIndex = displayIndex }); } public static BlacksiteContainerPlacementMetadata ReadContainer(string json) { BlacksiteContainerPlacementMetadata blacksiteContainerPlacementMetadata = Read(json, new BlacksiteContainerPlacementMetadata()); blacksiteContainerPlacementMetadata.containerSize = NormalizeContainerSize(blacksiteContainerPlacementMetadata.containerSize); return blacksiteContainerPlacementMetadata; } public static CctvCameraPlacementMetadata ReadCctvCamera(string json) { CctvCameraPlacementMetadata cctvCameraPlacementMetadata = Read(json, new CctvCameraPlacementMetadata()); cctvCameraPlacementMetadata.cameraLabel = cctvCameraPlacementMetadata.cameraLabel ?? string.Empty; cctvCameraPlacementMetadata.source = cctvCameraPlacementMetadata.source ?? string.Empty; return cctvCameraPlacementMetadata; } public static VaultPlacementMetadata ReadVault(string json) { VaultPlacementMetadata vaultPlacementMetadata = Read(json, new VaultPlacementMetadata()); vaultPlacementMetadata.assetName = vaultPlacementMetadata.assetName ?? string.Empty; vaultPlacementMetadata.displayName = vaultPlacementMetadata.displayName ?? string.Empty; return vaultPlacementMetadata; } public static string NormalizeContainerSize(string size) { if (string.IsNullOrWhiteSpace(size)) { return "medium"; } switch (size.Trim().ToLowerInvariant()) { case "s": case "small": case "10": case "10ft": return "small"; case "l": case "large": case "40": case "40ft": return "large"; default: return "medium"; } } private static T Read(string json, T fallback) where T : class { if (string.IsNullOrWhiteSpace(json)) { return fallback; } try { return JsonUtility.FromJson(json) ?? fallback; } catch { return fallback; } } } [Serializable] public sealed class AuthoredInteriorPlacementProfile { public int schemaVersion = 1; public List placements = new List(); public List legacyLocalImportKeys = new List(); } [Serializable] public sealed class AuthoredInteriorPlacementRecord { public string objectKind; public string objectId; public string timestampUtc; public string flowName; public string dungeonName; public string dungeonFingerprint; public string tileName; public int tileSourceIndex = -1; public Vector3 tileWorldCenter; public Vector3 tileBoundsSize; public int tileDoorwayCount; public float normalizedPathDepth; public float normalizedBranchDepth; public bool isOnMainPath; public string containerSize; public Vector3 tileLocalPosition; public Vector3 tileLocalEuler; public string metadataJson; } public readonly struct AuthoredInteriorPlacementPose { public readonly Tile Tile; public readonly Vector3 WorldPosition; public readonly Quaternion WorldRotation; public readonly string Source; public readonly AuthoredInteriorPlacementRecord Record; public AuthoredInteriorPlacementPose(Tile tile, Vector3 worldPosition, Quaternion worldRotation, string source, AuthoredInteriorPlacementRecord record) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Tile = tile; WorldPosition = worldPosition; WorldRotation = worldRotation; Source = source ?? string.Empty; Record = record; } } internal readonly struct AuthoredInteriorRecordEntry { internal readonly AuthoredInteriorPlacementRecord Record; internal readonly bool IsLocal; internal readonly string Source; internal AuthoredInteriorRecordEntry(AuthoredInteriorPlacementRecord record, bool isLocal, string source) { Record = record; IsLocal = isLocal; Source = source ?? string.Empty; } } internal readonly struct AuthoredInteriorTileMatch { internal readonly Tile Tile; internal readonly int Index; internal readonly float Score; internal AuthoredInteriorTileMatch(Tile tile, int index, float score) { Tile = tile; Index = index; Score = score; } } public sealed class AuthoredInteriorTileMarker : MonoBehaviour { public string FlowName; public string TileName; public string TileRequestKey; } public static class AuthoredInteriorPlacementStore { private const string LocalFolderName = "Y4NGZCompany"; private const string LocalFileName = "interior-authored-placements.local.json"; private const string PackFileName = "interior-authored-placements.json"; private const string CommunityPackFolderName = "placement-packs"; private const string PluginAdjacentPackPattern = "*.placement-pack.json"; private const string CommunityPackSourcePrefix = "community-pack:"; private const string LegacyLocalInteriorImportKey = "legacy-local-interior"; private const string LegacyLocalCameraSuppressionImportKey = "legacy-local-camera-suppression"; private const string LegacyLocalDefuseImportKey = "legacy-local-defuse"; private const string LegacyLocalBreachImportKey = "legacy-local-breach"; private const string LegacyBreachFileName = "breach-authored-placements.local.json"; private const float MaxTilePlacementScore = 35f; private const float MaxTilePlacementHorizontalDistance = 3.5f; private const float MaxTilePlacementVerticalPenalty = 6f; public const float BoundsMismatchScorePenalty = 1000f; private const string StableFingerprintMarker = "_fnv1a64_"; private const ulong Fnv1a64OffsetBasis = 14695981039346656037uL; private const ulong Fnv1a64Prime = 1099511628211uL; private static readonly Regex TrailingTileInstanceMarker = new Regex("(?:\\s*\\(\\s*clone\\s*\\)\\s*|\\s*\\(\\s*\\d+\\s*\\)\\s*|[_\\s-]+\\d+\\s*)$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); private static readonly List PackRecords = new List(); private static readonly List CommunityPackRecords = new List(); private static AuthoredInteriorPlacementProfile _localProfile = new AuthoredInteriorPlacementProfile(); private static bool _loaded; private static DateTime _localWriteUtc; private static DateTime _packWriteUtc; private static Dictionary _communityPackWriteUtc = new Dictionary(StringComparer.OrdinalIgnoreCase); private static int _communityPackFileCount; private static readonly object LoadLock = new object(); public static string LocalProfilePath => Path.Combine(Paths.ConfigPath, "Y4NGZCompany", "interior-authored-placements.local.json"); public static string CommunityPackFolderPath => Path.Combine(Paths.ConfigPath, "Y4NGZCompany", "placement-packs"); private static string PackProfilePath => Path.Combine(Path.GetDirectoryName(typeof(AuthoredInteriorPlacementStore).Assembly.Location) ?? string.Empty, "interior-authored-placements.json"); public static void Load() { lock (LoadLock) { List list = DiscoverCommunityPackPaths(); Dictionary dictionary = BuildWriteTimeSnapshot(list); DateTime lastWriteUtc = GetLastWriteUtc(LocalProfilePath); DateTime lastWriteUtc2 = GetLastWriteUtc(PackProfilePath); if (!_loaded || !(lastWriteUtc == _localWriteUtc) || !(lastWriteUtc2 == _packWriteUtc) || !WriteTimeSnapshotsMatch(_communityPackWriteUtc, dictionary)) { _loaded = true; _localWriteUtc = lastWriteUtc; _packWriteUtc = lastWriteUtc2; _communityPackWriteUtc = dictionary; _communityPackFileCount = list.Count; PackRecords.Clear(); CommunityPackRecords.Clear(); _localProfile = new AuthoredInteriorPlacementProfile(); EnsureProfileCollections(_localProfile); LoadProfile(PackProfilePath, PackRecords, isLocal: false, "pack"); LoadCanonicalLocalProfile(); ImportLegacyLocalProfiles(); LoadCommunityPacks(list); int num = CountLegacyFingerprintRecords(); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.AuthoredPlacement] FINGERPRINT_MIGRATION legacyRecords={num}; records refresh to FNV-1a after their next successful fallback resolve and persist on the next local save."); } ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)$"[Y4NGZ.AuthoredPlacement] Loaded pack={PackRecords.Count}, communityPacks={_communityPackFileCount}, communityRecords={CommunityPackRecords.Count}, local={((_localProfile.placements != null) ? _localProfile.placements.Count : 0)}, localPath='{LocalProfilePath}', communityPath='{CommunityPackFolderPath}'."); } } } } public static IReadOnlyList GetConfiguredFlowNames(params string[] objectKinds) { Load(); HashSet kinds = BuildKindSet(objectKinds); return (from entry in EnumerateMergedRecords() where entry.Record != null where kinds.Count == 0 || kinds.Contains(AuthoredInteriorPlacementKinds.Normalize(entry.Record.objectKind)) select entry.Record.flowName into flow where !string.IsNullOrWhiteSpace(flow) select flow.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy((string flow) => flow, StringComparer.OrdinalIgnoreCase).ToList(); } public static IReadOnlyList GetRecordsForFlow(string objectKind, string flowName) { Load(); string kind = AuthoredInteriorPlacementKinds.Normalize(objectKind); if (string.IsNullOrWhiteSpace(flowName)) { return Array.Empty(); } return (from entry in EnumerateMergedRecords() where entry.Record != null where string.Equals(AuthoredInteriorPlacementKinds.Normalize(entry.Record.objectKind), kind, StringComparison.OrdinalIgnoreCase) where string.Equals(entry.Record.flowName ?? string.Empty, flowName, StringComparison.OrdinalIgnoreCase) select entry.Record).OrderBy((AuthoredInteriorPlacementRecord record) => record.objectId ?? string.Empty, StringComparer.OrdinalIgnoreCase).ThenBy((AuthoredInteriorPlacementRecord record) => record.tileName ?? string.Empty, StringComparer.OrdinalIgnoreCase).ToList(); } public static bool RecordPlacement(Transform transform, string objectKind, string objectId, string metadataJson, out string message) { //IL_001c: 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) message = string.Empty; if ((Object)(object)transform == (Object)null) { message = "missing placement transform"; return false; } return RecordWorldPose(transform.position, transform.rotation, objectKind, objectId, metadataJson, out message); } public static bool RecordCameraView(string objectId, Vector3 position, Quaternion rotation, out string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) string metadataJson = AuthoredInteriorPlacementMetadata.CctvCamera(objectId, "debugtools-ghost"); return RecordWorldPose(position, rotation, "cctv-camera", objectId, metadataJson, out message); } public static bool RecordCameraSuppression(Vector3 worldPosition, Quaternion worldRotation, bool authoredCamera, string authoredCameraId, out string message) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Load(); message = string.Empty; RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null || val.AllTiles.Count == 0) { message = "load an interior before suppressing a camera"; return false; } if (!TryFindBestTileAtPosition(val, worldPosition, out var tile, out var tileIndex)) { message = "camera is not inside a generated interior tile"; return false; } string objectKind = (authoredCamera ? "camera-deleted" : "camera-disabled"); string id = ((authoredCamera && !string.IsNullOrWhiteSpace(authoredCameraId)) ? authoredCameraId.Trim() : "auto"); AuthoredInteriorPlacementRecord record = CreateRecord(worldPosition, worldRotation, tile, tileIndex, objectKind, id, string.Empty); lock (LoadLock) { EnsureProfileCollections(_localProfile); if (authoredCamera) { _localProfile.placements.RemoveAll((AuthoredInteriorPlacementRecord existing) => existing != null && AuthoredInteriorPlacementKinds.IsCctvCamera(existing.objectKind) && string.Equals(existing.objectId ?? string.Empty, id, StringComparison.OrdinalIgnoreCase) && string.Equals(existing.flowName ?? string.Empty, record.flowName ?? string.Empty, StringComparison.OrdinalIgnoreCase) && string.Equals(NormalizeTileNameForMatch(existing.tileName), NormalizeTileNameForMatch(record.tileName), StringComparison.OrdinalIgnoreCase)); } _localProfile.placements.RemoveAll((AuthoredInteriorPlacementRecord existing) => SamePlacementSlot(existing, record)); _localProfile.placements.Add(record); SaveLocalProfile(); } message = (authoredCamera ? ("deleted authored camera " + id) : ("disabled auto camera " + ((Object)tile).name)); return true; } public static bool TryGetAuthoredCameraDeletion(AuthoredInteriorPlacementRecord cameraRecord, Tile cameraTile, out AuthoredInteriorPlacementRecord suppressionRecord, out string source) { suppressionRecord = null; source = null; if (cameraRecord == null || (Object)(object)cameraTile == (Object)null || !AuthoredInteriorPlacementKinds.IsCctvCamera(cameraRecord.objectKind)) { return false; } return TryGetCameraSuppression("camera-deleted", cameraTile, (AuthoredInteriorPlacementRecord record) => string.Equals(record.objectId ?? string.Empty, cameraRecord.objectId ?? string.Empty, StringComparison.OrdinalIgnoreCase), out suppressionRecord, out source); } public static bool TryGetCameraTileSuppression(Tile tile, out AuthoredInteriorPlacementRecord suppressionRecord, out string source) { return TryGetCameraSuppression("camera-disabled", tile, null, out suppressionRecord, out source); } public static bool TryResolveFirstPose(string objectKind, out AuthoredInteriorPlacementPose pose) { pose = default(AuthoredInteriorPlacementPose); if (!TryResolvePoses(objectKind, out var poses) || poses.Count == 0) { return false; } pose = poses[0]; return true; } public static bool TryResolvePoses(string objectKind, out List poses) { //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) Load(); poses = new List(); RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null || val.AllTiles.Count == 0) { return false; } string text = AuthoredInteriorPlacementKinds.Normalize(objectKind); string text2 = ResolveFlowName(); IReadOnlyList recordsForFlow = GetRecordsForFlow(text, text2); if (AuthoredPlacementRoundReport.BeginResolutionKind(text2, CountRecordsForOtherFlows(text2), text)) { ReportMatchingShadows(val.AllTiles, text, text2); } for (int i = 0; i < recordsForFlow.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = recordsForFlow[i]; string source = ResolveRecordSource(authoredInteriorPlacementRecord); AuthoredPlacementRoundReport.RecordConsidered(authoredInteriorPlacementRecord, source); if (!TryFindBestTileForRecord(val.AllTiles, authoredInteriorPlacementRecord, out var tile, out var rejectReason, out var matchOutcome, out var candidateCount)) { AuthoredPlacementRoundReport.RecordTileAbsent(authoredInteriorPlacementRecord, source, rejectReason); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)("[Y4NGZ.AuthoredPlacement] RESOLVE_SKIP kind=" + text + " id='" + authoredInteriorPlacementRecord?.objectId + "' tile='" + authoredInteriorPlacementRecord?.tileName + "' reason=" + rejectReason + ".")); } } else { AuthoredPlacementRoundReport.RecordMatched(authoredInteriorPlacementRecord, source, matchOutcome, candidateCount, (tile != null) ? ((Object)tile).name : null); poses.Add(new AuthoredInteriorPlacementPose(tile, TileLocalToWorld(tile, authoredInteriorPlacementRecord.tileLocalPosition), tile.Placement.Rotation * Quaternion.Euler(authoredInteriorPlacementRecord.tileLocalEuler), BuildPoseSource(source), authoredInteriorPlacementRecord)); } } return poses.Count > 0; } public static string BuildTileRequestKey(AuthoredInteriorPlacementRecord record) { if (record == null) { return string.Empty; } return string.Join("|", record.flowName ?? string.Empty, record.tileName ?? string.Empty, Mathf.RoundToInt(Mathf.Abs(record.tileBoundsSize.x) * 10f).ToString(), Mathf.RoundToInt(Mathf.Abs(record.tileBoundsSize.y) * 10f).ToString(), Mathf.RoundToInt(Mathf.Abs(record.tileBoundsSize.z) * 10f).ToString()); } public static string DeletePlacement(string objectKind, string objectId) { Load(); string kind = AuthoredInteriorPlacementKinds.Normalize(objectKind); string id = (string.IsNullOrWhiteSpace(objectId) ? kind : objectId.Trim()); string flow = ResolveFlowName(); if (_localProfile.placements == null) { _localProfile.placements = new List(); } int num = _localProfile.placements.RemoveAll((AuthoredInteriorPlacementRecord record) => record != null && string.Equals(AuthoredInteriorPlacementKinds.Normalize(record.objectKind), kind, StringComparison.OrdinalIgnoreCase) && string.Equals(record.objectId ?? string.Empty, id, StringComparison.OrdinalIgnoreCase) && string.Equals(record.flowName ?? string.Empty, flow, StringComparison.OrdinalIgnoreCase)); if (num > 0) { SaveLocalProfile(); } if (num <= 0) { return "no local " + AuthoredInteriorPlacementKinds.DisplayLabel(kind) + " " + id + " placement found"; } return "deleted " + AuthoredInteriorPlacementKinds.DisplayLabel(kind) + " " + id; } public static string BuildStatus() { Load(); int num = ((_localProfile.placements != null) ? _localProfile.placements.Count : 0); return $"Authored placements loaded. local={num}, pack={PackRecords.Count}, communityPacks={_communityPackFileCount}, communityRecords={CommunityPackRecords.Count}, path={LocalProfilePath}"; } public static bool ExportLocalProfile(string flowName, out string exportPath, out int recordCount, out string message) { Load(); exportPath = null; recordCount = 0; message = string.Empty; string flowFilter = (string.IsNullOrWhiteSpace(flowName) ? null : flowName.Trim()); lock (LoadLock) { EnsureProfileCollections(_localProfile); List list = (from record in _localProfile.placements where record != null where flowFilter == null || string.Equals(record.flowName ?? string.Empty, flowFilter, StringComparison.OrdinalIgnoreCase) select record).ToList(); if (list.Count == 0) { message = ((flowFilter == null) ? "the local profile has no placements to export" : ("the local profile has no placements for flow '" + flowFilter + "'")); return false; } try { Directory.CreateDirectory(CommunityPackFolderPath); string exportBaseName = BuildExportBaseName(flowFilter); exportPath = FindAvailableExportPath(exportBaseName); AuthoredInteriorPlacementProfile authoredInteriorPlacementProfile = new AuthoredInteriorPlacementProfile { schemaVersion = 1, placements = list, legacyLocalImportKeys = new List() }; File.WriteAllText(exportPath, JsonUtility.ToJson((object)authoredInteriorPlacementProfile, true)); recordCount = list.Count; message = $"exported {recordCount} local placement(s) to '{exportPath}'"; return true; } catch (Exception ex) { exportPath = null; message = "failed writing placement pack: " + ex.Message; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed exporting local profile to '" + CommunityPackFolderPath + "': " + ex.Message)); } return false; } } } private static bool RecordWorldPose(Vector3 worldPosition, Quaternion worldRotation, string objectKind, string objectId, string metadataJson, out string message) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Load(); RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null || val.AllTiles.Count == 0) { message = "load an interior before saving placement"; return false; } if (!TryFindBestTileAtPosition(val, worldPosition, out var tile, out var tileIndex)) { message = "move placement inside a generated interior tile"; return false; } AuthoredInteriorPlacementRecord record = CreateRecord(worldPosition, worldRotation, tile, tileIndex, objectKind, objectId, metadataJson); lock (LoadLock) { if (_localProfile.placements == null) { _localProfile.placements = new List(); } _localProfile.placements.RemoveAll((AuthoredInteriorPlacementRecord existing) => SamePlacementSlot(existing, record)); _localProfile.placements.Add(record); SaveLocalProfile(); } message = "saved " + AuthoredInteriorPlacementKinds.DisplayLabel(record.objectKind) + " " + record.objectId + " on " + record.flowName + " / " + record.tileName; return true; } private static AuthoredInteriorPlacementRecord CreateRecord(Vector3 worldPosition, Quaternion worldRotation, Tile tile, int tileIndex, string objectKind, string objectId, string metadataJson) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_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_0115: 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) string text = AuthoredInteriorPlacementKinds.Normalize(objectKind); string objectId2 = (string.IsNullOrWhiteSpace(objectId) ? text : objectId.Trim()); Quaternion val = Quaternion.Inverse(tile.Placement.Rotation) * worldRotation; ReadTileDepth(tile, out var pathDepth, out var branchDepth, out var onMainPath); AuthoredInteriorPlacementRecord obj = new AuthoredInteriorPlacementRecord { objectKind = text, objectId = objectId2, timestampUtc = DateTime.UtcNow.ToString("o"), flowName = ResolveFlowName(), dungeonName = ResolveDungeonName(), dungeonFingerprint = BuildDungeonFingerprint(), tileName = (((Object)tile).name ?? ""), tileSourceIndex = tileIndex }; Bounds bounds = tile.Bounds; obj.tileWorldCenter = ((Bounds)(ref bounds)).center; bounds = tile.Bounds; obj.tileBoundsSize = ((Bounds)(ref bounds)).size; obj.tileDoorwayCount = ((tile.UsedDoorways != null) ? tile.UsedDoorways.Count : 0); obj.normalizedPathDepth = pathDepth; obj.normalizedBranchDepth = branchDepth; obj.isOnMainPath = onMainPath; obj.tileLocalPosition = WorldToTileLocal(tile, worldPosition); obj.tileLocalEuler = ((Quaternion)(ref val)).eulerAngles; obj.metadataJson = metadataJson ?? string.Empty; return obj; } private static List DiscoverCommunityPackPaths() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); try { Directory.CreateDirectory(CommunityPackFolderPath); foreach (string item in Directory.EnumerateFiles(CommunityPackFolderPath, "*.json", SearchOption.TopDirectoryOnly)) { hashSet.Add(Path.GetFullPath(item)); } } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed scanning community pack folder '" + CommunityPackFolderPath + "': " + ex.Message)); } } try { if (!string.IsNullOrWhiteSpace(Paths.PluginPath) && Directory.Exists(Paths.PluginPath)) { foreach (string item2 in Directory.EnumerateFiles(Paths.PluginPath, "*.placement-pack.json", SearchOption.AllDirectories)) { if (DirectoryContainsPluginDll(Path.GetDirectoryName(item2))) { hashSet.Add(Path.GetFullPath(item2)); } } } } catch (Exception ex2) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed scanning plugin-adjacent community packs under '" + Paths.PluginPath + "': " + ex2.Message)); } } return hashSet.OrderBy((string path) => Path.GetFileName(path), StringComparer.OrdinalIgnoreCase).ThenBy((string path) => path, StringComparer.OrdinalIgnoreCase).ThenBy((string path) => path, StringComparer.Ordinal) .ToList(); } private static bool DirectoryContainsPluginDll(string directory) { if (string.IsNullOrWhiteSpace(directory) || !Directory.Exists(directory)) { return false; } try { return Directory.EnumerateFiles(directory, "*.dll", SearchOption.TopDirectoryOnly).Any(); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed checking community pack directory '" + directory + "' for plugin DLLs: " + ex.Message)); } return false; } } private static Dictionary BuildWriteTimeSnapshot(IReadOnlyList paths) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (paths == null) { return dictionary; } for (int i = 0; i < paths.Count; i++) { dictionary[paths[i]] = GetLastWriteUtc(paths[i]); } return dictionary; } private static bool WriteTimeSnapshotsMatch(IReadOnlyDictionary current, IReadOnlyDictionary next) { if (current == next) { return true; } if (current == null || next == null || current.Count != next.Count) { return false; } foreach (KeyValuePair item in next) { if (!current.TryGetValue(item.Key, out var value) || value != item.Value) { return false; } } return true; } private static void LoadCommunityPacks(IReadOnlyList packPaths) { if (packPaths == null) { return; } for (int i = 0; i < packPaths.Count; i++) { string text = packPaths[i]; string fileName = Path.GetFileName(text); string source = "community-pack:" + text; List list = new List(); bool flag = LoadProfile(text, list, source); int num = 0; int num2 = 0; HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (flag) { for (int j = 0; j < list.Count; j++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = list[j]; if (authoredInteriorPlacementRecord == null) { continue; } if (!string.IsNullOrWhiteSpace(authoredInteriorPlacementRecord.flowName)) { hashSet.Add(authoredInteriorPlacementRecord.flowName.Trim()); } string text2 = FindCommunityShadowSource(authoredInteriorPlacementRecord); if (!string.IsNullOrEmpty(text2)) { num2++; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] COMMUNITY_SHADOW pack='" + fileName + "' kind=" + AuthoredInteriorPlacementKinds.Normalize(authoredInteriorPlacementRecord.objectKind) + " id='" + authoredInteriorPlacementRecord.objectId + "' flow='" + authoredInteriorPlacementRecord.flowName + "' shadowedBy='" + text2 + "'.")); } } else { CommunityPackRecords.Add(new AuthoredInteriorRecordEntry(authoredInteriorPlacementRecord, isLocal: false, source)); num++; } } } string text3 = ((hashSet.Count == 0) ? "" : string.Join(",", hashSet.OrderBy((string flow) => flow, StringComparer.OrdinalIgnoreCase))); ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)string.Format("[Y4NGZ.AuthoredPlacement] COMMUNITY_PACK pack='{0}' path='{1}' records={2} recordsLoaded={3} shadowed={4} flowsCovered={5} flows='{6}' status={7}.", fileName, text, list.Count, num, num2, hashSet.Count, text3, flag ? "loaded" : "failed")); } } } private static string FindCommunityShadowSource(AuthoredInteriorPlacementRecord record) { if (record == null) { return null; } if (_localProfile?.placements != null && _localProfile.placements.Any((AuthoredInteriorPlacementRecord local) => SamePlacementSlot(local, record))) { return "local profile"; } for (int num = 0; num < PackRecords.Count; num++) { AuthoredInteriorRecordEntry authoredInteriorRecordEntry = PackRecords[num]; if (SamePlacementSlot(authoredInteriorRecordEntry.Record, record)) { if (!string.Equals(authoredInteriorRecordEntry.Source, "pack", StringComparison.OrdinalIgnoreCase)) { return "shipped pack " + authoredInteriorRecordEntry.Source; } return "shipped pack interior-authored-placements.json"; } } for (int num2 = 0; num2 < CommunityPackRecords.Count; num2++) { AuthoredInteriorRecordEntry authoredInteriorRecordEntry2 = CommunityPackRecords[num2]; if (SamePlacementSlot(authoredInteriorRecordEntry2.Record, record)) { return DescribeCommunityPackSource(authoredInteriorRecordEntry2.Source); } } return null; } private static string DescribeCommunityPackSource(string source) { if (string.IsNullOrWhiteSpace(source) || !source.StartsWith("community-pack:", StringComparison.OrdinalIgnoreCase)) { return "earlier community pack"; } string path = source.Substring("community-pack:".Length); return "community pack " + Path.GetFileName(path); } private static void LoadCanonicalLocalProfile() { if (File.Exists(LocalProfilePath) && TryReadProfile(LocalProfilePath, "local", out var profile)) { _localProfile = profile ?? new AuthoredInteriorPlacementProfile(); EnsureProfileCollections(_localProfile); if (NormalizeAndFilterProfile(_localProfile)) { SaveLocalProfile(); } } } private static void ImportLegacyLocalProfiles() { int num = (int)(0u | (ImportLegacyInteriorAuthoredProfile(Path.Combine(Paths.ConfigPath, "LethalCCTV", "interior-authored-placements.local.json"), isLocal: true, "legacy-local-interior") ? 1u : 0u) | (ImportLegacyInteriorAuthoredProfile(Path.Combine(Paths.ConfigPath, "LethalCCTV", "interior-authored-placements.local.json"), isLocal: true, "legacy-local-camera-suppression", null, suppressionOnly: true) ? 1u : 0u) | (ImportLegacyInteriorAuthoredProfile(Path.Combine(Paths.ConfigPath, "LethalCCTV", "interior-authored-placements.local.json"), isLocal: true, "legacy-local-defuse", "dead-drop-bomb") ? 1u : 0u) | (ImportLegacyBreachProfile(Path.Combine(Paths.ConfigPath, "Y4NGZCompany", "breach-authored-placements.local.json"), isLocal: true, "legacy-local-breach") ? 1u : 0u)) | (ImportLegacyBreachProfile(Path.Combine(Paths.ConfigPath, "LGUContractHUD", "breach-authored-placements.local.json"), isLocal: true, "legacy-local-breach") ? 1 : 0); string? path = Path.GetDirectoryName(typeof(AuthoredInteriorPlacementStore).Assembly.Location) ?? string.Empty; ImportLegacyInteriorAuthoredProfile(Path.Combine(path, "interior-authored-placements.json"), isLocal: false, null); ImportLegacyBreachProfile(Path.Combine(path, "breach-authored-placements.json"), isLocal: false, null); if (num != 0) { SaveLocalProfile(); } } private static bool ImportLegacyInteriorAuthoredProfile(string path, bool isLocal, string legacyLocalImportKey, string requiredKind = null, bool suppressionOnly = false) { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { return false; } if (isLocal && IsLegacyLocalImportComplete(legacyLocalImportKey)) { return false; } List list = new List(); if (!LoadProfile(path, list, isLocal ? "legacy-local-interior" : "legacy-pack-interior")) { return false; } bool changed = false; for (int i = 0; i < list.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = list[i]; if (authoredInteriorPlacementRecord == null) { continue; } string text = AuthoredInteriorPlacementKinds.Normalize(authoredInteriorPlacementRecord.objectKind); if ((!suppressionOnly || IsCameraSuppressionRecord(authoredInteriorPlacementRecord)) && (string.IsNullOrWhiteSpace(requiredKind) || string.Equals(text, AuthoredInteriorPlacementKinds.Normalize(requiredKind), StringComparison.OrdinalIgnoreCase))) { authoredInteriorPlacementRecord.objectKind = text; if (string.Equals(text, "dead-drop", StringComparison.OrdinalIgnoreCase)) { authoredInteriorPlacementRecord.objectKind = "dead-drop-bomb"; } AddImportedRecord(authoredInteriorPlacementRecord, isLocal, isLocal ? "legacy-local-interior" : "legacy-pack-interior", ref changed); } } if (isLocal) { changed |= MarkLegacyLocalImportComplete(legacyLocalImportKey); } return changed && isLocal; } private static bool ImportLegacyBreachProfile(string path, bool isLocal, string legacyLocalImportKey) { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { return false; } if (isLocal && IsLegacyLocalImportComplete(legacyLocalImportKey)) { return false; } List list = new List(); if (!LoadProfile(path, list, isLocal ? "legacy-local-breach" : "legacy-pack-breach")) { return false; } bool changed = false; for (int i = 0; i < list.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = list[i]; if (authoredInteriorPlacementRecord != null && string.Equals(AuthoredInteriorPlacementKinds.Normalize(authoredInteriorPlacementRecord.objectKind), "blacksite-container", StringComparison.OrdinalIgnoreCase)) { authoredInteriorPlacementRecord.objectKind = "blacksite-container"; if (string.IsNullOrWhiteSpace(authoredInteriorPlacementRecord.metadataJson)) { authoredInteriorPlacementRecord.metadataJson = AuthoredInteriorPlacementMetadata.Container(ReadLegacyContainerSize(authoredInteriorPlacementRecord)); } AddImportedRecord(authoredInteriorPlacementRecord, isLocal, isLocal ? "legacy-local-breach" : "legacy-pack-breach", ref changed); } } if (isLocal) { changed |= MarkLegacyLocalImportComplete(legacyLocalImportKey); } return changed && isLocal; } private static void AddImportedRecord(AuthoredInteriorPlacementRecord record, bool isLocal, string source, ref bool changed) { if (record == null) { return; } NormalizeRecord(record); if (isLocal) { if (_localProfile.placements == null) { _localProfile.placements = new List(); } if (!_localProfile.placements.Any((AuthoredInteriorPlacementRecord existing) => SamePlacementSlot(existing, record))) { _localProfile.placements.Add(record); changed = true; } } else if (!PackRecords.Any((AuthoredInteriorRecordEntry entry) => SamePackRecord(entry.Record, record))) { PackRecords.Add(new AuthoredInteriorRecordEntry(record, isLocal: false, source)); } } private static string ReadLegacyContainerSize(AuthoredInteriorPlacementRecord record) { if (record == null) { return "medium"; } try { FieldInfo field = record.GetType().GetField("containerSize"); if (field != null && field.GetValue(record) is string result) { return result; } } catch { } return "medium"; } private static bool LoadProfile(string path, List destination, bool isLocal, string source) { List list = new List(); if (!LoadProfile(path, list, source)) { return false; } for (int i = 0; i < list.Count; i++) { AuthoredInteriorPlacementRecord record = list[i]; if (record != null && (isLocal || !destination.Any((AuthoredInteriorRecordEntry entry) => SamePackRecord(entry.Record, record)))) { destination.Add(new AuthoredInteriorRecordEntry(record, isLocal, source)); } } return true; } private static bool LoadProfile(string path, List destination, string source) { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path) || destination == null) { return false; } if (!TryReadProfile(path, source, out var profile)) { return false; } if (profile?.placements == null) { return true; } for (int i = 0; i < profile.placements.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = profile.placements[i]; if (authoredInteriorPlacementRecord != null) { NormalizeRecord(authoredInteriorPlacementRecord); destination.Add(authoredInteriorPlacementRecord); } } return true; } private static void SaveLocalProfile() { try { Directory.CreateDirectory(Path.GetDirectoryName(LocalProfilePath)); _localProfile.schemaVersion = 1; EnsureProfileCollections(_localProfile); File.WriteAllText(LocalProfilePath, JsonUtility.ToJson((object)_localProfile, true)); _localWriteUtc = GetLastWriteUtc(LocalProfilePath); } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed writing local profile '" + LocalProfilePath + "': " + ex.Message)); } } } private static string BuildExportBaseName(string flowFilter) { string input = (string.IsNullOrWhiteSpace(flowFilter) ? "all-flows" : flowFilter.Trim()); input = Regex.Replace(input, "[^A-Za-z0-9._-]+", "-").Trim('-', '.', '_'); if (string.IsNullOrWhiteSpace(input)) { input = "flow"; } if (input.Length > 80) { input = input.Substring(0, 80).TrimEnd('-', '.', '_'); } return "y4ngz-placement-pack-" + input + "-" + DateTime.UtcNow.ToString("yyyyMMdd-HHmmss", CultureInfo.InvariantCulture); } private static string FindAvailableExportPath(string exportBaseName) { string text = Path.Combine(CommunityPackFolderPath, exportBaseName + ".placement-pack.json"); int num = 2; while (File.Exists(text)) { text = Path.Combine(CommunityPackFolderPath, exportBaseName + "-" + num.ToString(CultureInfo.InvariantCulture) + ".placement-pack.json"); num++; } return text; } private static bool TryReadProfile(string path, string source, out AuthoredInteriorPlacementProfile profile) { profile = null; if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { return false; } try { string text = File.ReadAllText(path); profile = JsonUtility.FromJson(text) ?? new AuthoredInteriorPlacementProfile(); EnsureProfileCollections(profile); return true; } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed loading profile '" + path + "' source=" + source + ": " + ex.Message)); } return false; } } private static void EnsureProfileCollections(AuthoredInteriorPlacementProfile profile) { if (profile != null) { if (profile.placements == null) { profile.placements = new List(); } if (profile.legacyLocalImportKeys == null) { profile.legacyLocalImportKeys = new List(); } } } private static bool NormalizeAndFilterProfile(AuthoredInteriorPlacementProfile profile) { if (profile?.placements == null) { return false; } bool flag = false; for (int num = profile.placements.Count - 1; num >= 0; num--) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = profile.placements[num]; if (authoredInteriorPlacementRecord == null) { profile.placements.RemoveAt(num); flag = true; } else { flag |= NormalizeRecord(authoredInteriorPlacementRecord); } } return flag; } private static bool IsLegacyLocalImportComplete(string importKey) { if (string.IsNullOrWhiteSpace(importKey)) { return false; } EnsureProfileCollections(_localProfile); return _localProfile.legacyLocalImportKeys.Any((string key) => string.Equals(key, importKey, StringComparison.OrdinalIgnoreCase)); } private static bool MarkLegacyLocalImportComplete(string importKey) { if (string.IsNullOrWhiteSpace(importKey)) { return false; } EnsureProfileCollections(_localProfile); if (IsLegacyLocalImportComplete(importKey)) { return false; } _localProfile.legacyLocalImportKeys.Add(importKey); return true; } private static IEnumerable EnumerateMergedRecords() { List list = new List(PackRecords); list.AddRange(CommunityPackRecords); if (_localProfile?.placements != null) { for (int i = 0; i < _localProfile.placements.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = _localProfile.placements[i]; if (authoredInteriorPlacementRecord != null) { string slot = PlacementSlotKey(authoredInteriorPlacementRecord); list.RemoveAll((AuthoredInteriorRecordEntry entry) => string.Equals(PlacementSlotKey(entry.Record), slot, StringComparison.OrdinalIgnoreCase)); list.Add(new AuthoredInteriorRecordEntry(authoredInteriorPlacementRecord, isLocal: true, "local")); } } } return list; } private static int CountRecordsForOtherFlows(string currentFlow) { int num = 0; foreach (AuthoredInteriorRecordEntry item in EnumerateMergedRecords()) { AuthoredInteriorPlacementRecord record = item.Record; if (record != null && !string.Equals(record.flowName ?? string.Empty, currentFlow ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { num++; } } return num; } private static string ResolveRecordSource(AuthoredInteriorPlacementRecord record) { if (record == null) { return "unknown"; } if (IsLocalRecord(record)) { return "local"; } for (int i = 0; i < PackRecords.Count; i++) { AuthoredInteriorRecordEntry authoredInteriorRecordEntry = PackRecords[i]; if (authoredInteriorRecordEntry.Record == record) { if (!string.IsNullOrWhiteSpace(authoredInteriorRecordEntry.Source)) { return authoredInteriorRecordEntry.Source; } return "pack"; } } for (int j = 0; j < CommunityPackRecords.Count; j++) { AuthoredInteriorRecordEntry authoredInteriorRecordEntry2 = CommunityPackRecords[j]; if (authoredInteriorRecordEntry2.Record == record) { if (!string.IsNullOrWhiteSpace(authoredInteriorRecordEntry2.Source)) { return authoredInteriorRecordEntry2.Source; } return "community-pack"; } } return "pack"; } private static string BuildPoseSource(string source) { if (string.Equals(source, "local", StringComparison.OrdinalIgnoreCase)) { return "authored-local"; } if (!string.IsNullOrWhiteSpace(source) && source.StartsWith("community-pack:", StringComparison.OrdinalIgnoreCase)) { return "authored-community-pack"; } return "authored-pack"; } private static void ReportMatchingShadows(IReadOnlyList tiles, string objectKind, string currentFlow) { if (tiles == null || _localProfile?.placements == null || _localProfile.placements.Count == 0) { return; } string text = AuthoredInteriorPlacementKinds.Normalize(objectKind); for (int i = 0; i < PackRecords.Count; i++) { AuthoredInteriorPlacementRecord record = PackRecords[i].Record; if (record == null || !string.Equals(AuthoredInteriorPlacementKinds.Normalize(record.objectKind), text, StringComparison.OrdinalIgnoreCase) || !string.Equals(record.flowName ?? string.Empty, currentFlow ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { continue; } string b = PlacementSlotKey(record); AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = null; for (int num = _localProfile.placements.Count - 1; num >= 0; num--) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord2 = _localProfile.placements[num]; if (authoredInteriorPlacementRecord2 != null && string.Equals(PlacementSlotKey(authoredInteriorPlacementRecord2), b, StringComparison.OrdinalIgnoreCase)) { authoredInteriorPlacementRecord = authoredInteriorPlacementRecord2; break; } } if (authoredInteriorPlacementRecord != null && TryFindBestTileForRecord(tiles, record, out var tile, out var _, out var matchOutcome, out var candidateCount, emitAmbiguityLog: false) && AuthoredPlacementRoundReport.RecordShadowedByLocal(record, "pack", authoredInteriorPlacementRecord, matchOutcome, candidateCount, (tile != null) ? ((Object)tile).name : null)) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] SHADOW_MATCH kind=" + text + " id='" + record.objectId + "' flow='" + currentFlow + "' packTile='" + record.tileName + "' matchedTile='" + ((tile != null) ? ((Object)tile).name : null) + "' localTile='" + authoredInteriorPlacementRecord.tileName + "'; local record overrides a pack record that would have matched this generation.")); } } } } private static bool IsLocalRecord(AuthoredInteriorPlacementRecord record) { if (record == null || _localProfile?.placements == null) { return false; } return _localProfile.placements.Contains(record); } private static HashSet BuildKindSet(string[] objectKinds) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (objectKinds == null) { return hashSet; } for (int i = 0; i < objectKinds.Length; i++) { if (!string.IsNullOrWhiteSpace(objectKinds[i])) { hashSet.Add(AuthoredInteriorPlacementKinds.Normalize(objectKinds[i])); } } return hashSet; } private static bool NormalizeRecord(AuthoredInteriorPlacementRecord record) { if (record == null) { return false; } string text = AuthoredInteriorPlacementKinds.Normalize(record.objectKind); int num = 0 | ((!string.Equals(record.objectKind ?? string.Empty, text, StringComparison.Ordinal)) ? 1 : 0); record.objectKind = text; string text2 = (string.IsNullOrWhiteSpace(record.objectId) ? text : record.objectId.Trim()); int num2 = num | ((!string.Equals(record.objectId ?? string.Empty, text2, StringComparison.Ordinal)) ? 1 : 0); record.objectId = text2; string text3 = record.flowName?.Trim(); int num3 = num2 | ((!string.Equals(record.flowName, text3, StringComparison.Ordinal)) ? 1 : 0); record.flowName = text3; string text4 = record.tileName?.Trim(); int num4 = num3 | ((!string.Equals(record.tileName, text4, StringComparison.Ordinal)) ? 1 : 0); record.tileName = text4; string text5 = record.metadataJson ?? string.Empty; int result = num4 | ((!string.Equals(record.metadataJson, text5, StringComparison.Ordinal)) ? 1 : 0); record.metadataJson = text5; return (byte)result != 0; } private static bool IsCameraSuppressionRecord(AuthoredInteriorPlacementRecord record) { if (record == null) { return false; } string a = AuthoredInteriorPlacementKinds.Normalize(record.objectKind); if (!string.Equals(a, "camera-deleted", StringComparison.OrdinalIgnoreCase)) { return string.Equals(a, "camera-disabled", StringComparison.OrdinalIgnoreCase); } return true; } private static bool TryFindBestTileAtPosition(Dungeon dungeon, Vector3 worldPosition, out Tile tile, out int tileIndex) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_0091: 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_00c3: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) tile = null; tileIndex = -1; if (((dungeon != null) ? dungeon.AllTiles : null) == null) { return false; } float num = float.PositiveInfinity; for (int i = 0; i < dungeon.AllTiles.Count; i++) { Tile val = dungeon.AllTiles[i]; if ((Object)(object)val == (Object)null) { continue; } Bounds bounds = val.Bounds; float num2 = ((worldPosition.x >= ((Bounds)(ref bounds)).min.x - 0.75f && worldPosition.x <= ((Bounds)(ref bounds)).max.x + 0.75f && worldPosition.z >= ((Bounds)(ref bounds)).min.z - 0.75f && worldPosition.z <= ((Bounds)(ref bounds)).max.z + 0.75f) ? 0f : HorizontalDistanceToBounds(worldPosition, bounds)); float num3 = ((worldPosition.y < ((Bounds)(ref bounds)).min.y - 2f) ? (((Bounds)(ref bounds)).min.y - worldPosition.y) : ((worldPosition.y > ((Bounds)(ref bounds)).max.y + 2f) ? (worldPosition.y - ((Bounds)(ref bounds)).max.y) : 0f)); if (!(num2 > 3.5f) && !(num3 > 6f)) { float num4 = num2 * 10f + num3; if (!(num4 >= num)) { num = num4; tile = val; tileIndex = i; } } } if ((Object)(object)tile == (Object)null || num > 35f) { tile = null; tileIndex = -1; return false; } return true; } private static bool TryFindBestTileForRecord(IReadOnlyList tiles, AuthoredInteriorPlacementRecord record, out Tile tile, out string rejectReason, out string matchOutcome, out int candidateCount, bool emitAmbiguityLog = true) { tile = null; rejectReason = null; matchOutcome = null; candidateCount = 0; if (record == null) { rejectReason = "null-record"; return false; } string text = ResolveFlowName(); if (!string.IsNullOrEmpty(record.flowName) && !string.Equals(record.flowName, text, StringComparison.OrdinalIgnoreCase)) { rejectReason = "flow-mismatch current='" + text + "'"; return false; } string text2 = BuildDungeonFingerprint(); if (!string.IsNullOrEmpty(record.dungeonFingerprint) && string.Equals(record.dungeonFingerprint, text2, StringComparison.Ordinal) && record.tileSourceIndex >= 0 && record.tileSourceIndex < tiles.Count && TileMatchesBasic(record, tiles[record.tileSourceIndex]) && TileBoundsMatch(record, tiles[record.tileSourceIndex], out var _, out var _, out var _)) { tile = tiles[record.tileSourceIndex]; matchOutcome = "matched-exact"; candidateCount = 1; return true; } string requestKey = BuildTileRequestKey(record); List list = new List(); List list2 = new List(); for (int i = 0; i < tiles.Count; i++) { Tile val = tiles[i]; if (!((Object)(object)val == (Object)null)) { if (TileHasMatchingMarker(val, requestKey)) { list.Add(new AuthoredInteriorTileMatch(val, i, ScoreTileMatch(record, val, i))); } if (TileMatchesBasic(record, val)) { list2.Add(new AuthoredInteriorTileMatch(val, i, ScoreTileMatch(record, val, i))); } } } if (list.Count > 0) { list.Sort(CompareTileMatches); tile = list[0].Tile; matchOutcome = "matched-marker"; candidateCount = list.Count; RefreshFingerprintAfterFallback(record, text2); WarnIfBoundsMismatch(record, tile, matchOutcome); return true; } if (list2.Count == 0) { rejectReason = "tile-not-present"; return false; } list2.Sort(CompareTileMatches); if (emitAmbiguityLog && list2.Count > 1 && !IsClearBestMatch(list2)) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.AuthoredPlacement] RESOLVE_AMBIGUOUS kind={AuthoredInteriorPlacementKinds.Normalize(record.objectKind)} id='{record.objectId}' tile='{record.tileName}' candidates={list2.Count} picked bestScore={list2[0].Score:0.00} runnerUp={list2[1].Score:0.00}."); } } tile = list2[0].Tile; matchOutcome = "matched-name"; candidateCount = list2.Count; RefreshFingerprintAfterFallback(record, text2); WarnIfBoundsMismatch(record, tile, matchOutcome); return true; } private static bool TryGetCameraSuppression(string suppressionKind, Tile targetTile, Func predicate, out AuthoredInteriorPlacementRecord suppressionRecord, out string source) { Load(); suppressionRecord = null; source = null; if ((Object)(object)targetTile == (Object)null) { return false; } RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null || val.AllTiles.Count == 0) { return false; } string flowName = ResolveFlowName(); IReadOnlyList recordsForFlow = GetRecordsForFlow(suppressionKind, flowName); for (int i = 0; i < recordsForFlow.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = recordsForFlow[i]; if (authoredInteriorPlacementRecord != null && (predicate == null || predicate(authoredInteriorPlacementRecord)) && TryFindBestTileForRecord(val.AllTiles, authoredInteriorPlacementRecord, out var tile, out var _, out var matchOutcome, out var candidateCount, emitAmbiguityLog: false) && tile == targetTile) { source = ResolveRecordSource(authoredInteriorPlacementRecord); AuthoredPlacementRoundReport.RecordConsidered(authoredInteriorPlacementRecord, source); AuthoredPlacementRoundReport.RecordMatched(authoredInteriorPlacementRecord, source, matchOutcome, candidateCount, (tile != null) ? ((Object)tile).name : null); suppressionRecord = authoredInteriorPlacementRecord; return true; } } return false; } private static bool TileHasMatchingMarker(Tile tile, string requestKey) { if ((Object)(object)tile == (Object)null || string.IsNullOrWhiteSpace(requestKey)) { return false; } AuthoredInteriorTileMarker authoredInteriorTileMarker = ((Component)tile).GetComponent() ?? ((Component)tile).GetComponentInChildren(true); if ((Object)(object)authoredInteriorTileMarker == (Object)null) { return false; } string b = ResolveFlowName(); if (string.Equals(authoredInteriorTileMarker.TileRequestKey ?? string.Empty, requestKey, StringComparison.OrdinalIgnoreCase)) { if (!string.IsNullOrWhiteSpace(authoredInteriorTileMarker.FlowName)) { return string.Equals(authoredInteriorTileMarker.FlowName, b, StringComparison.OrdinalIgnoreCase); } return true; } return false; } private static bool TileMatchesBasic(AuthoredInteriorPlacementRecord record, Tile tile) { if (record == null || (Object)(object)tile == (Object)null) { return false; } return string.Equals(NormalizeTileNameForMatch(record.tileName), NormalizeTileNameForMatch(((Object)tile).name), StringComparison.OrdinalIgnoreCase); } private static bool TileBoundsMatch(AuthoredInteriorPlacementRecord record, Tile tile, out float spanError, out float areaError, out float heightError) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) spanError = 0f; areaError = 0f; heightError = 0f; if (record == null || (Object)(object)tile == (Object)null) { return true; } return TileBoundsCompatible(record.tileBoundsSize, tile.Bounds, out spanError, out areaError, out heightError); } public static bool TileBoundsCompatible(Vector3 savedBoundsSize, Bounds bounds, out float spanError, out float areaError, out float heightError) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) spanError = 0f; areaError = 0f; heightError = 0f; if (((Vector3)(ref savedBoundsSize)).sqrMagnitude < 1E-06f) { return true; } float num = Mathf.Min(Mathf.Abs(savedBoundsSize.x), Mathf.Abs(savedBoundsSize.z)); float num2 = Mathf.Max(Mathf.Abs(savedBoundsSize.x), Mathf.Abs(savedBoundsSize.z)); float num3 = Mathf.Min(Mathf.Abs(((Bounds)(ref bounds)).size.x), Mathf.Abs(((Bounds)(ref bounds)).size.z)); float num4 = Mathf.Max(Mathf.Abs(((Bounds)(ref bounds)).size.x), Mathf.Abs(((Bounds)(ref bounds)).size.z)); spanError = Mathf.Abs(num - num3) + Mathf.Abs(num2 - num4); heightError = Mathf.Abs(Mathf.Abs(savedBoundsSize.y) - Mathf.Abs(((Bounds)(ref bounds)).size.y)); float num5 = num * num2; float num6 = num3 * num4; areaError = Mathf.Abs(num5 - num6); if (!(spanError < 2.25f)) { if (areaError < Mathf.Max(6f, num5 * 0.08f)) { return heightError < 2.5f; } return false; } return true; } private static float ScoreTileMatch(AuthoredInteriorPlacementRecord record, Tile tile, int index) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (record == null || (Object)(object)tile == (Object)null) { return float.MaxValue; } float num = 0f; if (((Vector3)(ref record.tileWorldCenter)).sqrMagnitude > 1E-06f) { float num2 = num; Bounds bounds = tile.Bounds; num = num2 + Vector3.Distance(((Bounds)(ref bounds)).center, record.tileWorldCenter) * 0.02f; } if (record.tileSourceIndex >= 0) { num += (float)Mathf.Abs(index - record.tileSourceIndex) * 0.15f; } try { if (HasPlacementDepthMetadata(record)) { num += Mathf.Abs(tile.Placement.NormalizedPathDepth - Mathf.Clamp01(record.normalizedPathDepth)) * 8f; num += Mathf.Abs(tile.Placement.NormalizedBranchDepth - Mathf.Clamp01(record.normalizedBranchDepth)) * 3f; if (record.isOnMainPath != tile.Placement.IsOnMainPath) { num += 2f; } } } catch { } Bounds bounds2 = tile.Bounds; num += Mathf.Abs(((Bounds)(ref bounds2)).size.x - record.tileBoundsSize.x) * 0.1f; num += Mathf.Abs(((Bounds)(ref bounds2)).size.z - record.tileBoundsSize.z) * 0.1f; if (!TileBoundsMatch(record, tile, out var _, out var _, out var _)) { num += 1000f; } return num; } private static void WarnIfBoundsMismatch(AuthoredInteriorPlacementRecord record, Tile tile, string matchOutcome) { if (!TileBoundsMatch(record, tile, out var spanError, out var areaError, out var heightError)) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZ.AuthoredPlacement] RESOLVE_BOUNDS_MISMATCH kind={AuthoredInteriorPlacementKinds.Normalize(record.objectKind)} id='{record.objectId}' savedTile='{record.tileName}' matchedTile='{((Object)tile).name}' pass={matchOutcome} spanError={spanError:0.00}m areaError={areaError:0.00}m2 heightError={heightError:0.00}m penalty={1000f:0}."); } } } public static string NormalizeTileNameForMatch(string value) { string text = (value ?? string.Empty).Trim(); while (text.Length > 0) { string text2 = TrailingTileInstanceMarker.Replace(text, string.Empty, 1).TrimEnd(); if (string.Equals(text2, text, StringComparison.Ordinal)) { break; } text = text2; } return text; } private static void RefreshFingerprintAfterFallback(AuthoredInteriorPlacementRecord record, string currentFingerprint) { if (record != null && !string.IsNullOrEmpty(currentFingerprint) && !string.Equals(record.dungeonFingerprint, currentFingerprint, StringComparison.Ordinal)) { record.dungeonFingerprint = currentFingerprint; } } private static bool HasPlacementDepthMetadata(AuthoredInteriorPlacementRecord record) { if (record != null) { if (!(record.normalizedPathDepth > 0.0001f) && !(record.normalizedBranchDepth > 0.0001f)) { return record.isOnMainPath; } return true; } return false; } private static int CompareTileMatches(AuthoredInteriorTileMatch a, AuthoredInteriorTileMatch b) { int num = a.Score.CompareTo(b.Score); if (num == 0) { return a.Index.CompareTo(b.Index); } return num; } private static bool IsClearBestMatch(IReadOnlyList matches) { if (matches == null || matches.Count == 0) { return false; } if (matches.Count == 1) { return true; } return matches[1].Score - matches[0].Score >= 0.75f; } private static float HorizontalDistanceToBounds(Vector3 point, Bounds bounds) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0037: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_008e: Unknown result type (might be due to invalid IL or missing references) float num = ((point.x < ((Bounds)(ref bounds)).min.x) ? (((Bounds)(ref bounds)).min.x - point.x) : ((point.x > ((Bounds)(ref bounds)).max.x) ? (point.x - ((Bounds)(ref bounds)).max.x) : 0f)); float num2 = ((point.z < ((Bounds)(ref bounds)).min.z) ? (((Bounds)(ref bounds)).min.z - point.z) : ((point.z > ((Bounds)(ref bounds)).max.z) ? (point.z - ((Bounds)(ref bounds)).max.z) : 0f)); return Mathf.Sqrt(num * num + num2 * num2); } private static Vector3 WorldToTileLocal(Tile tile, Vector3 world) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 val = Matrix4x4.TRS(tile.Placement.Position, tile.Placement.Rotation, Vector3.one); Matrix4x4 inverse = ((Matrix4x4)(ref val)).inverse; return ((Matrix4x4)(ref inverse)).MultiplyPoint3x4(world); } private static Vector3 TileLocalToWorld(Tile tile, Vector3 local) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) return tile.Placement.Position + tile.Placement.Rotation * local; } private static bool SamePlacementSlot(AuthoredInteriorPlacementRecord a, AuthoredInteriorPlacementRecord b) { if (a == null || b == null) { return false; } return string.Equals(PlacementSlotKey(a), PlacementSlotKey(b), StringComparison.OrdinalIgnoreCase); } private static bool SamePackRecord(AuthoredInteriorPlacementRecord a, AuthoredInteriorPlacementRecord b) { if (a == null || b == null) { return false; } if (string.Equals(PlacementSlotKey(a), PlacementSlotKey(b), StringComparison.OrdinalIgnoreCase)) { return string.Equals(BuildTileRequestKey(a), BuildTileRequestKey(b), StringComparison.OrdinalIgnoreCase); } return false; } private static string PlacementSlotKey(AuthoredInteriorPlacementRecord record) { if (record == null) { return string.Empty; } string text = string.Join("|", AuthoredInteriorPlacementKinds.Normalize(record.objectKind), record.objectId ?? string.Empty, record.flowName ?? string.Empty); if (!IsCameraSuppressionRecord(record)) { return text; } return text + "|" + NormalizeTileNameForMatch(record.tileName); } private static void ReadTileDepth(Tile tile, out float pathDepth, out float branchDepth, out bool onMainPath) { pathDepth = 0f; branchDepth = 0f; onMainPath = true; if (((tile != null) ? tile.Placement : null) == null) { return; } try { pathDepth = tile.Placement.NormalizedPathDepth; branchDepth = tile.Placement.NormalizedBranchDepth; onMainPath = tile.Placement.IsOnMainPath; } catch { } } private static string ResolveFlowName() { try { DungeonFlow val = RoundManager.Instance?.dungeonGenerator?.Generator?.DungeonFlow; return ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) ? ((Object)val).name : "unknown-flow"; } catch { return "unknown-flow"; } } private static string ResolveDungeonName() { try { RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; return ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) ? ((Object)val).name : "unknown-dungeon"; } catch { return "unknown-dungeon"; } } private static string BuildDungeonFingerprint() { //IL_00b0: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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) RoundManager instance = RoundManager.Instance; object obj; if (instance == null) { obj = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; obj = ((generator != null) ? generator.CurrentDungeon : null); } } Dungeon val = (Dungeon)obj; if (((val != null) ? val.AllTiles : null) == null) { return "tiles0"; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(val.AllTiles.Count.ToString(CultureInfo.InvariantCulture)).Append('|'); for (int i = 0; i < val.AllTiles.Count; i++) { Tile val2 = val.AllTiles[i]; if ((Object)(object)val2 == (Object)null) { stringBuilder.Append("null;"); continue; } string text = ((Object)val2).name ?? string.Empty; Bounds bounds = val2.Bounds; Vector3 center = ((Bounds)(ref bounds)).center; stringBuilder.Append(text.Length.ToString(CultureInfo.InvariantCulture)).Append(':').Append(text) .Append('|') .Append(Mathf.RoundToInt(center.x * 10f).ToString(CultureInfo.InvariantCulture)) .Append(',') .Append(Mathf.RoundToInt(center.z * 10f).ToString(CultureInfo.InvariantCulture)) .Append(';'); } ulong num = ComputeFnv1a64(stringBuilder.ToString()); return "tiles" + val.AllTiles.Count.ToString(CultureInfo.InvariantCulture) + "_fnv1a64_" + num.ToString("X16", CultureInfo.InvariantCulture); } private static ulong ComputeFnv1a64(string value) { byte[] bytes = Encoding.UTF8.GetBytes(value ?? string.Empty); ulong num = 14695981039346656037uL; for (int i = 0; i < bytes.Length; i++) { num ^= bytes[i]; num *= 1099511628211L; } return num; } private static int CountLegacyFingerprintRecords() { int num = 0; for (int i = 0; i < PackRecords.Count; i++) { AuthoredInteriorPlacementRecord record = PackRecords[i].Record; if (record != null && IsLegacyFingerprint(record.dungeonFingerprint)) { num++; } } for (int j = 0; j < CommunityPackRecords.Count; j++) { AuthoredInteriorPlacementRecord record2 = CommunityPackRecords[j].Record; if (record2 != null && IsLegacyFingerprint(record2.dungeonFingerprint)) { num++; } } if (_localProfile?.placements == null) { return num; } for (int k = 0; k < _localProfile.placements.Count; k++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = _localProfile.placements[k]; if (authoredInteriorPlacementRecord != null && IsLegacyFingerprint(authoredInteriorPlacementRecord.dungeonFingerprint)) { num++; } } return num; } private static bool IsLegacyFingerprint(string fingerprint) { if (!string.IsNullOrWhiteSpace(fingerprint)) { return fingerprint.IndexOf("_fnv1a64_", StringComparison.Ordinal) < 0; } return true; } private static DateTime GetLastWriteUtc(string path) { try { return File.Exists(path) ? File.GetLastWriteTimeUtc(path) : DateTime.MinValue; } catch { return DateTime.MinValue; } } } internal static class AuthoredInteriorTileInjectionService { private readonly struct AppliedRule { internal readonly DungeonFlow Flow; internal readonly TileInjectionRule Rule; internal readonly TileSet TileSet; internal readonly GameObject Template; internal AppliedRule(DungeonFlow flow, TileInjectionRule rule, TileSet tileSet, GameObject template) { Flow = flow; Rule = rule; TileSet = tileSet; Template = template; } } private static readonly List AppliedRules = new List(); private static readonly HashSet ActiveRuleKeys = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly Vector3 TemplateHoldingPosition = new Vector3(0f, -10000f, 0f); internal static void ResetRunState() { RestoreInjectedRules("run reset"); } internal static void ApplyForLevel(RoundManager round, params string[] objectKinds) { RestoreInjectedRules("new generation"); if (round?.currentLevel?.dungeonFlowTypes != null && round.dungeonFlowTypes != null) { ApplyForFlowEntries(round, round.currentLevel.dungeonFlowTypes, objectKinds); } } internal static void ApplyForApprovedFlows(RoundManager round, IReadOnlyList approvedFlows, params string[] objectKinds) { ApplyForApprovedFlows(round, approvedFlows, restoreExistingRules: true, objectKinds); } internal static void ApplyForApprovedFlows(RoundManager round, IReadOnlyList approvedFlows, bool restoreExistingRules, params string[] objectKinds) { if (restoreExistingRules) { RestoreInjectedRules("new approved-flow generation"); } ApplyForFlowEntries(round, approvedFlows, objectKinds); } internal static void RestoreInjectedRules(string reason) { if (AppliedRules.Count == 0) { ActiveRuleKeys.Clear(); return; } int num = 0; for (int i = 0; i < AppliedRules.Count; i++) { AppliedRule appliedRule = AppliedRules[i]; if (appliedRule.Flow?.TileInjectionRules != null && appliedRule.Rule != null && appliedRule.Flow.TileInjectionRules.Remove(appliedRule.Rule)) { num++; } if ((Object)(object)appliedRule.Template != (Object)null) { Object.Destroy((Object)(object)appliedRule.Template); } if ((Object)(object)appliedRule.TileSet != (Object)null) { Object.Destroy((Object)(object)appliedRule.TileSet); } } AppliedRules.Clear(); ActiveRuleKeys.Clear(); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZ.AuthoredPlacement] TILE_INJECTION_RESTORE removed={num} ({reason})."); } } private static void ApplyForFlowEntries(RoundManager round, IReadOnlyList flowEntries, params string[] objectKinds) { if (round?.dungeonFlowTypes == null || flowEntries == null || flowEntries.Count == 0) { return; } int num = 0; int num2 = 0; HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < flowEntries.Count; i++) { IntWithRarity val = flowEntries[i]; if (val == null || val.id < 0 || val.id >= round.dungeonFlowTypes.Length) { continue; } DungeonFlow val2 = round.dungeonFlowTypes[val.id]?.dungeonFlow; if ((Object)(object)val2 == (Object)null) { continue; } string text = (string.IsNullOrWhiteSpace(((Object)val2).name) ? $"#{val.id}" : ((Object)val2).name); int num3 = 0; while (objectKinds != null && num3 < objectKinds.Length) { string text2 = AuthoredInteriorPlacementKinds.Normalize(objectKinds[num3]); if (AuthoredInteriorPlacementKinds.CanForceTile(text2)) { IReadOnlyList recordsForFlow = AuthoredInteriorPlacementStore.GetRecordsForFlow(text2, text); int num4 = 0; while (recordsForFlow != null && num4 < recordsForFlow.Count) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = recordsForFlow[num4]; if (authoredInteriorPlacementRecord != null && !string.IsNullOrWhiteSpace(authoredInteriorPlacementRecord.tileName)) { string requestKey = AuthoredInteriorPlacementStore.BuildTileRequestKey(authoredInteriorPlacementRecord); string item = BuildActiveRuleKey(text, text2, requestKey); if (hashSet.Add(item) && !ActiveRuleKeys.Contains(item)) { if (!TryApplyRequiredRule(val2, text, authoredInteriorPlacementRecord, requestKey)) { num2++; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[Y4NGZ.AuthoredPlacement] TILE_INJECTION_SKIP kind=" + text2 + " flow='" + text + "' tile='" + authoredInteriorPlacementRecord.tileName + "' reason=tile-prefab-not-in-flow.")); } } else { num++; ActiveRuleKeys.Add(item); } } } num4++; } } num3++; } } if (num > 0) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)$"[Y4NGZ.AuthoredPlacement] TILE_INJECTION_APPLIED rules={num} missing={num2}."); } } } private static bool TryApplyRequiredRule(DungeonFlow flow, string flowName, AuthoredInteriorPlacementRecord record, string requestKey) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_010c: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown if ((Object)(object)flow == (Object)null || record == null || string.IsNullOrWhiteSpace(requestKey)) { return false; } if (!TryFindTilePrefabInFlow(flow, record, out var prefab, out var sourceTileSet)) { return false; } GameObject val = CreateMarkedTemplate(prefab, flowName, record, requestKey); if ((Object)(object)val == (Object)null) { return false; } TileSet val2 = ScriptableObject.CreateInstance(); ((Object)val2).name = "Y4NGZAuthoredTileSet_" + Sanitize(flowName) + "_" + Sanitize(record.objectKind) + "_" + Sanitize(record.tileName); val2.TileWeights = new GameObjectChanceTable { Weights = new List() }; if (sourceTileSet?.LockPrefabs != null) { val2.LockPrefabs = new List(sourceTileSet.LockPrefabs); } GameObjectChance item = new GameObjectChance(val, 1f, 1f, val2) { Value = val, MainPathWeight = 1f, BranchPathWeight = 1f, TileSet = val2 }; val2.TileWeights.Weights.Add(item); TileInjectionRule val3 = new TileInjectionRule { TileSet = val2, NormalizedPathDepth = BuildDepthRange(record.normalizedPathDepth, 0.15f, 0.9f), NormalizedBranchDepth = BuildDepthRange(record.normalizedBranchDepth, 0f, 1f), CanAppearOnMainPath = true, CanAppearOnBranchPath = true, IsRequired = true, IsLocked = false, LockID = 0 }; if (flow.TileInjectionRules == null) { flow.TileInjectionRules = new List(); } flow.TileInjectionRules.Add(val3); AppliedRules.Add(new AppliedRule(flow, val3, val2, val)); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)("[Y4NGZ.AuthoredPlacement] TILE_INJECTION_RULE kind=" + record.objectKind + " flow='" + flowName + "' tile='" + record.tileName + "' request='" + requestKey + "'.")); } return true; } private static GameObject CreateMarkedTemplate(GameObject sourcePrefab, string flowName, AuthoredInteriorPlacementRecord record, string requestKey) { //IL_0059: 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_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourcePrefab == (Object)null || record == null) { return null; } GameObject val = Object.Instantiate(sourcePrefab); if ((Object)(object)val == (Object)null) { return null; } ((Object)val).name = $"{NormalizeTileName(((Object)sourcePrefab).name)}_Y4NGZAuthoredTemplate_{Mathf.Abs(requestKey.GetHashCode()):X8}"; ((Object)val).hideFlags = (HideFlags)61; val.transform.position = TemplateHoldingPosition; val.transform.rotation = Quaternion.identity; val.transform.localScale = sourcePrefab.transform.localScale; Object.DontDestroyOnLoad((Object)(object)val); AuthoredInteriorTileMarker obj = val.GetComponent() ?? val.AddComponent(); obj.FlowName = flowName ?? string.Empty; obj.TileName = record.tileName ?? string.Empty; obj.TileRequestKey = requestKey ?? string.Empty; return val; } private static bool TryFindTilePrefabInFlow(DungeonFlow flow, AuthoredInteriorPlacementRecord record, out GameObject prefab, out TileSet sourceTileSet) { prefab = null; sourceTileSet = null; if ((Object)(object)flow == (Object)null || record == null) { return false; } foreach (TileSet item in EnumerateNormalTileSets(flow)) { if (item?.TileWeights?.Weights == null) { continue; } for (int i = 0; i < item.TileWeights.Weights.Count; i++) { GameObject val = item.TileWeights.Weights[i]?.Value; if (TilePrefabMatches(val, record)) { prefab = val; sourceTileSet = item; return true; } } } return TryFindTilePrefabGlobally(record, out prefab); } private static bool TryFindTilePrefabGlobally(AuthoredInteriorPlacementRecord record, out GameObject prefab) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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) prefab = null; if (record == null) { return false; } Tile[] array = Resources.FindObjectsOfTypeAll(); foreach (Tile val in array) { GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null); if ((Object)(object)val2 == (Object)null) { continue; } string text = ((Object)val2).name ?? string.Empty; if (text.IndexOf("Y4NGZAuthoredTemplate", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("BreachAuthoredTemplate", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("MainframeAuthoredTemplate", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("DefuseAuthoredTemplate", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("DeadDropAuthoredTemplate", StringComparison.OrdinalIgnoreCase) >= 0) { continue; } Scene scene = val2.scene; if (((Scene)(ref scene)).IsValid()) { scene = val2.scene; if (((Scene)(ref scene)).isLoaded) { continue; } } if (TilePrefabMatches(val2, record)) { prefab = val2; ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)("[Y4NGZ.AuthoredPlacement] TILE_PREFAB_GLOBAL_MATCH kind=" + record.objectKind + " tile='" + record.tileName + "' prefab='" + ((Object)val2).name + "'.")); } return true; } } return false; } private static IEnumerable EnumerateNormalTileSets(DungeonFlow flow) { if ((Object)(object)flow == (Object)null) { yield break; } if (flow.Nodes != null) { foreach (GraphNode node in flow.Nodes) { if (node?.TileSets == null) { continue; } foreach (TileSet tileSet in node.TileSets) { if ((Object)(object)tileSet != (Object)null) { yield return tileSet; } } } } if (flow.Lines != null) { foreach (GraphLine line in flow.Lines) { if (line?.DungeonArchetypes == null) { continue; } foreach (DungeonArchetype dungeonArchetype in line.DungeonArchetypes) { foreach (TileSet item in EnumerateArchetypeTileSets(dungeonArchetype)) { yield return item; } } } } if (flow.TileInjectionRules == null) { yield break; } foreach (TileInjectionRule tileInjectionRule in flow.TileInjectionRules) { if ((Object)(object)tileInjectionRule?.TileSet != (Object)null) { yield return tileInjectionRule.TileSet; } } } private static IEnumerable EnumerateArchetypeTileSets(DungeonArchetype archetype) { if ((Object)(object)archetype == (Object)null) { yield break; } foreach (TileSet item in EnumerateTileSetList(archetype.TileSets)) { yield return item; } foreach (TileSet item2 in EnumerateTileSetList(archetype.BranchStartTileSets)) { yield return item2; } foreach (TileSet item3 in EnumerateTileSetList(archetype.BranchCapTileSets)) { yield return item3; } } private static IEnumerable EnumerateTileSetList(IEnumerable tileSets) { if (tileSets == null) { yield break; } foreach (TileSet tileSet in tileSets) { if ((Object)(object)tileSet != (Object)null) { yield return tileSet; } } } private static bool TilePrefabMatches(GameObject candidate, AuthoredInteriorPlacementRecord record) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)candidate == (Object)null || record == null) { return false; } if (!string.Equals(NormalizeTileName(((Object)candidate).name), NormalizeTileName(record.tileName), StringComparison.OrdinalIgnoreCase)) { return false; } if (!(((Vector3)(ref record.tileBoundsSize)).sqrMagnitude <= 1E-06f)) { return TilePrefabSizeMatches(candidate, record.tileBoundsSize); } return true; } private static bool TilePrefabSizeMatches(GameObject prefab, Vector3 savedSize) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) Tile val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent() : null); if ((Object)(object)val == (Object)null) { return true; } Bounds bounds = val.Bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num = Mathf.Min(Mathf.Abs(savedSize.x), Mathf.Abs(savedSize.z)); float num2 = Mathf.Max(Mathf.Abs(savedSize.x), Mathf.Abs(savedSize.z)); float num3 = Mathf.Min(Mathf.Abs(size.x), Mathf.Abs(size.z)); float num4 = Mathf.Max(Mathf.Abs(size.x), Mathf.Abs(size.z)); float num5 = Mathf.Abs(num - num3) + Mathf.Abs(num2 - num4); float num6 = Mathf.Abs(Mathf.Abs(savedSize.y) - Mathf.Abs(size.y)); float num7 = num * num2; float num8 = num3 * num4; float num9 = Mathf.Abs(num7 - num8); if (!(num5 < 2.25f)) { if (num9 < Mathf.Max(6f, num7 * 0.08f)) { return num6 < 2.5f; } return false; } return true; } private static FloatRange BuildDepthRange(float savedDepth, float fallbackMin, float fallbackMax) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown if (savedDepth > 0.0001f && savedDepth < 0.9999f) { float num = Mathf.Clamp01(savedDepth - 0.18f); float num2 = Mathf.Clamp01(savedDepth + 0.18f); if (num2 - num >= 0.05f) { return new FloatRange(num, num2); } } return new FloatRange(fallbackMin, fallbackMax); } private static string NormalizeTileName(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } return value.Replace("(Clone)", string.Empty).Trim(); } private static string Sanitize(string value) { if (string.IsNullOrWhiteSpace(value)) { return "unknown"; } char[] array = value.ToCharArray(); for (int i = 0; i < array.Length; i++) { if (!char.IsLetterOrDigit(array[i]) && array[i] != '_' && array[i] != '-') { array[i] = '_'; } } return new string(array); } private static string BuildActiveRuleKey(string flowName, string kind, string requestKey) { return (flowName ?? string.Empty) + "|" + AuthoredInteriorPlacementKinds.Normalize(kind) + "|" + (requestKey ?? string.Empty); } } internal static class AuthoredPlacementCoverageReport { private sealed class FlowCounts { internal readonly string FlowName; internal bool LoadedInGame; internal int NodeCount; internal int Total; internal int Mainframes; internal int CompanyStashes; internal int DefuseBombs; internal int ShippingContainers; internal int CctvCameras; internal readonly Dictionary Tiles = new Dictionary(StringComparer.OrdinalIgnoreCase); internal FlowCounts(string flowName) { FlowName = flowName; } internal TileCounts EnsureTile(string tileName) { string text = (string.IsNullOrWhiteSpace(tileName) ? "unknown-tile" : tileName.Trim()); if (Tiles.TryGetValue(text, out var value)) { return value; } TileCounts tileCounts = new TileCounts(text); Tiles[text] = tileCounts; return tileCounts; } } private sealed class TileCounts { internal readonly string TileName; internal int Total; internal int Mainframes; internal int CompanyStashes; internal int DefuseBombs; internal int ShippingContainers; internal int CctvCameras; internal TileCounts(string tileName) { TileName = tileName; } } private const string ReportFileName = "authored-placement-coverage.txt"; private const string ReportFolderName = "Y4NGZCompany"; internal static string ReportPath => Path.Combine(Paths.ConfigPath, "Y4NGZCompany", "authored-placement-coverage.txt"); internal static void WriteReport(string reason) { try { Dictionary dictionary = LoadAuthoredCounts(); AddLoadedDungeonFlows(dictionary); AddRegisteredDungeonFlows(dictionary); string contents = BuildReport(dictionary, reason); Directory.CreateDirectory(Path.GetDirectoryName(ReportPath)); File.WriteAllText(ReportPath, contents); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)string.Format("[Y4NGZ.AuthoredPlacement] Coverage report written to '{0}' ({1} interiors, reason={2}).", ReportPath, dictionary.Count, reason ?? "unspecified")); } } catch (Exception ex) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZ.AuthoredPlacement] Failed writing coverage report '" + ReportPath + "': " + ex.Message)); } } } private static Dictionary LoadAuthoredCounts() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string localProfilePath = AuthoredInteriorPlacementStore.LocalProfilePath; if (string.IsNullOrWhiteSpace(localProfilePath) || !File.Exists(localProfilePath)) { return dictionary; } AuthoredInteriorPlacementProfile authoredInteriorPlacementProfile = JsonUtility.FromJson(File.ReadAllText(localProfilePath)); if (authoredInteriorPlacementProfile?.placements == null) { return dictionary; } for (int i = 0; i < authoredInteriorPlacementProfile.placements.Count; i++) { AuthoredInteriorPlacementRecord authoredInteriorPlacementRecord = authoredInteriorPlacementProfile.placements[i]; if (authoredInteriorPlacementRecord != null && !string.IsNullOrWhiteSpace(authoredInteriorPlacementRecord.flowName)) { FlowCounts flowCounts = EnsureFlow(dictionary, authoredInteriorPlacementRecord.flowName.Trim()); flowCounts.Total++; string text = AuthoredInteriorPlacementKinds.Normalize(authoredInteriorPlacementRecord.objectKind); TileCounts tileCounts = flowCounts.EnsureTile(authoredInteriorPlacementRecord.tileName); tileCounts.Total++; switch (text) { case "mainframe": flowCounts.Mainframes++; tileCounts.Mainframes++; break; case "vault": flowCounts.CompanyStashes++; tileCounts.CompanyStashes++; break; case "dead-drop-bomb": flowCounts.DefuseBombs++; tileCounts.DefuseBombs++; break; case "blacksite-container": flowCounts.ShippingContainers++; tileCounts.ShippingContainers++; break; case "cctv-camera": flowCounts.CctvCameras++; tileCounts.CctvCameras++; break; } } } return dictionary; } private static void AddLoadedDungeonFlows(Dictionary flows) { DungeonFlow[] array = Resources.FindObjectsOfTypeAll(); if (array == null) { return; } foreach (DungeonFlow val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrWhiteSpace(((Object)val).name)) { FlowCounts flowCounts = EnsureFlow(flows, ((Object)val).name.Trim()); flowCounts.LoadedInGame = true; flowCounts.NodeCount = SafeNodeCount(val); } } } private static void AddRegisteredDungeonFlows(Dictionary flows) { try { IndoorMapType[] array = RoundManager.Instance?.dungeonFlowTypes; if (array == null) { return; } for (int i = 0; i < array.Length; i++) { DungeonFlow val = array[i]?.dungeonFlow; if (!((Object)(object)val == (Object)null) && !string.IsNullOrWhiteSpace(((Object)val).name)) { FlowCounts flowCounts = EnsureFlow(flows, ((Object)val).name.Trim()); flowCounts.LoadedInGame = true; flowCounts.NodeCount = SafeNodeCount(val); } } } catch { } } private static FlowCounts EnsureFlow(Dictionary flows, string flowName) { string text = (string.IsNullOrWhiteSpace(flowName) ? "unknown-flow" : flowName.Trim()); if (flows.TryGetValue(text, out var value)) { return value; } return flows[text] = new FlowCounts(text); } private static string BuildReport(Dictionary flows, string reason) { List list = new List(flows.Keys); list.Sort(StringComparer.OrdinalIgnoreCase); int num = 0; int num2 = 0; for (int i = 0; i < list.Count; i++) { if (flows[list[i]].Total > 0) { num++; } else { num2++; } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Y4NGZ Authored Placement Coverage"); stringBuilder.AppendLine("Generated: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); stringBuilder.AppendLine("Reason: " + (string.IsNullOrWhiteSpace(reason) ? "unspecified" : reason.Trim())); stringBuilder.AppendLine("Source: " + AuthoredInteriorPlacementStore.LocalProfilePath); stringBuilder.AppendLine("Note: Counts come from the canonical authored placement JSON. Zero-count interiors come from registered/loaded DungeonFlow resources discovered this run."); stringBuilder.AppendLine(); stringBuilder.AppendLine("Summary"); stringBuilder.AppendLine("interiors listed: " + list.Count); stringBuilder.AppendLine("with authored placements: " + num); stringBuilder.AppendLine("with zero authored placements: " + num2); stringBuilder.AppendLine(); for (int j = 0; j < list.Count; j++) { FlowCounts flowCounts = flows[list[j]]; stringBuilder.Append(flowCounts.FlowName).Append(" authored mainframes: ").Append(flowCounts.Mainframes) .Append(", company stashes: ") .Append(flowCounts.CompanyStashes) .Append(", defuse bombs: ") .Append(flowCounts.DefuseBombs) .Append(", shipping containers (blacksite-container): ") .Append(flowCounts.ShippingContainers) .Append(", cctv cameras: ") .Append(flowCounts.CctvCameras) .Append(", loaded in game: ") .Append(flowCounts.LoadedInGame ? "yes" : "not seen this run") .Append(", dungeon flow nodes: ") .Append(flowCounts.NodeCount) .AppendLine(); List list2 = new List(flowCounts.Tiles.Keys); list2.Sort(StringComparer.OrdinalIgnoreCase); for (int k = 0; k < list2.Count; k++) { TileCounts tileCounts = flowCounts.Tiles[list2[k]]; stringBuilder.Append(" tile: ").Append(tileCounts.TileName).Append(" | total: ") .Append(tileCounts.Total) .Append(" | mainframes: ") .Append(tileCounts.Mainframes) .Append(" | company stashes: ") .Append(tileCounts.CompanyStashes) .Append(" | defuse bombs: ") .Append(tileCounts.DefuseBombs) .Append(" | shipping containers: ") .Append(tileCounts.ShippingContainers) .Append(" | cctv cameras: ") .Append(tileCounts.CctvCameras) .AppendLine(); } } return stringBuilder.ToString(); } private static int SafeNodeCount(DungeonFlow flow) { try { return (flow?.Nodes != null) ? flow.Nodes.Count : 0; } catch { return 0; } } } public static class AuthoredPlacementRoundReport { private sealed class ReportEntry { internal AuthoredInteriorPlacementRecord Record; internal string Source; internal string MatchOutcome; internal int CandidateCount; internal string ResolvedTileName; internal string FinalOutcome; internal string Detail; internal OutcomePriority Priority; } private enum OutcomePriority { None, TileAbsent, ResolvedButUnused, ValidationFailed, Suppressed, Shadowed, Spawned } public const string MatchedExact = "matched-exact"; public const string MatchedMarker = "matched-marker"; public const string MatchedName = "matched-name"; private const string TileAbsent = "tile-absent"; private const string ShadowedByLocal = "shadowed-by-local"; private const string Suppressed = "suppressed"; private const string ValidationFailed = "validation-failed"; private const string Spawned = "spawned"; private const string ResolvedButUnused = "resolved-but-unused"; private static readonly List Entries = new List(); private static readonly HashSet ResolutionKinds = new HashSet(StringComparer.OrdinalIgnoreCase); private static object _roundToken; private static string _flowName = "unknown-flow"; private static string _dungeonName = "unknown-dungeon"; private static int _otherFlowRecordCount; private static bool _cameraPassComplete; private static bool _hostFixturePassComplete; private static bool _hostPeer; private static bool _flushed; public static bool CameraPassComplete => _cameraPassComplete; public static bool HostFixturePassComplete => _hostFixturePassComplete; public static HostFacilityPlacementReadiness HostFacilityPlacementState => new HostFacilityPlacementReadiness(_hostPeer, _cameraPassComplete, _hostFixturePassComplete); public static bool HostFacilityPlacementReady => HostFacilityPlacementState.IsReady; public static void ResetRound() { Entries.Clear(); ResolutionKinds.Clear(); _roundToken = null; _flowName = "unknown-flow"; _dungeonName = "unknown-dungeon"; _otherFlowRecordCount = 0; _cameraPassComplete = false; _hostFixturePassComplete = false; _hostPeer = false; _flushed = false; PlacementReviewRoundReport.ResetRound(); } public static void PrepareRound(object roundToken, string flowName, string dungeonName, int otherFlowRecordCount) { if (_roundToken != null && _roundToken != roundToken) { ResetRound(); } _roundToken = roundToken; _flowName = NormalizeLabel(flowName, "unknown-flow"); _dungeonName = NormalizeLabel(dungeonName, "unknown-dungeon"); _otherFlowRecordCount = Math.Max(0, otherFlowRecordCount); } public static bool BeginResolutionKind(string flowName, int otherFlowRecordCount, string objectKind) { RoundManager instance = RoundManager.Instance; object roundToken; if (instance == null) { roundToken = null; } else { RuntimeDungeon dungeonGenerator = instance.dungeonGenerator; if (dungeonGenerator == null) { roundToken = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; roundToken = ((generator != null) ? generator.CurrentDungeon : null); } } RoundManager instance2 = RoundManager.Instance; object obj; if (instance2 == null) { obj = null; } else { RuntimeDungeon dungeonGenerator2 = instance2.dungeonGenerator; if (dungeonGenerator2 == null) { obj = null; } else { DungeonGenerator generator2 = dungeonGenerator2.Generator; if (generator2 == null) { obj = null; } else { Dungeon currentDungeon = generator2.CurrentDungeon; obj = ((currentDungeon != null) ? ((Object)currentDungeon).name : null); } } } string dungeonName = (string)obj; PrepareRound(roundToken, flowName, dungeonName, otherFlowRecordCount); return ResolutionKinds.Add(NormalizeLabel(objectKind, "unknown")); } public static void RecordConsidered(AuthoredInteriorPlacementRecord record, string source) { if (!_flushed && record != null) { GetOrCreate(record, source); } } public static void RecordMatched(AuthoredInteriorPlacementRecord record, string source, string matchOutcome, int candidateCount, string resolvedTileName) { if (!_flushed && record != null) { ReportEntry orCreate = GetOrCreate(record, source); orCreate.MatchOutcome = NormalizeLabel(matchOutcome, "matched-name"); orCreate.CandidateCount = Math.Max(1, candidateCount); orCreate.ResolvedTileName = NormalizeLabel(resolvedTileName, record.tileName); } } public static void RecordTileAbsent(AuthoredInteriorPlacementRecord record, string source, string reason) { if (!_flushed && record != null) { SetFinalOutcome(GetOrCreate(record, source), "tile-absent", NormalizeDetail(reason), OutcomePriority.TileAbsent); } } public static bool RecordShadowedByLocal(AuthoredInteriorPlacementRecord packRecord, string source, AuthoredInteriorPlacementRecord localRecord, string matchOutcome, int candidateCount, string resolvedTileName) { if (_flushed || packRecord == null) { return false; } ReportEntry reportEntry = FindEntry(packRecord); if (reportEntry != null && string.Equals(reportEntry.FinalOutcome, "shadowed-by-local", StringComparison.Ordinal)) { return false; } ReportEntry obj = reportEntry ?? GetOrCreate(packRecord, source); obj.MatchOutcome = NormalizeLabel(matchOutcome, "matched-name"); obj.CandidateCount = Math.Max(1, candidateCount); obj.ResolvedTileName = NormalizeLabel(resolvedTileName, packRecord.tileName); string value = ((localRecord != null) ? NormalizeLabel(localRecord.tileName, "") : ""); SetFinalOutcome(obj, "shadowed-by-local", "local-tile='" + NormalizeDetail(value) + "'", OutcomePriority.Shadowed); return true; } public static void RecordSuppressed(AuthoredInteriorPlacementRecord record, string reason) { if (!_flushed && record != null) { SetFinalOutcome(GetOrCreate(record, null), "suppressed", NormalizeDetail(reason), OutcomePriority.Suppressed); } } public static void RecordValidationFailed(AuthoredInteriorPlacementRecord record, IReadOnlyList reasons) { if (_flushed || record == null) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("reasons=["); if (reasons == null || reasons.Count == 0) { stringBuilder.Append("validator-returned-no-reasons"); } else { for (int i = 0; i < reasons.Count; i++) { if (i > 0) { stringBuilder.Append("; "); } stringBuilder.Append(NormalizeDetail(reasons[i])); } } stringBuilder.Append(']'); SetFinalOutcome(GetOrCreate(record, null), "validation-failed", stringBuilder.ToString(), OutcomePriority.ValidationFailed); } public static void RecordSpawned(AuthoredInteriorPlacementRecord record) { if (!_flushed && record != null) { SetFinalOutcome(GetOrCreate(record, null), "spawned", string.Empty, OutcomePriority.Spawned); } } public static void RecordResolvedButUnused(AuthoredInteriorPlacementRecord record, string reason) { if (!_flushed && record != null) { SetFinalOutcome(GetOrCreate(record, null), "resolved-but-unused", NormalizeDetail(reason), OutcomePriority.ResolvedButUnused); } } public static void NotifyCameraPassComplete(bool isHostPeer) { if (!_flushed) { _cameraPassComplete = true; _hostPeer = isHostPeer; if (!_hostPeer) { Flush("client-partial"); } } } public static void NotifyHostFixturePassComplete() { if (!_flushed) { _hostPeer = true; _hostFixturePassComplete = true; } } public static void FlushHostIfReady() { if (_cameraPassComplete && _hostFixturePassComplete) { Flush("host-full"); } } private static void Flush(string scope) { if (_flushed) { return; } _flushed = true; PlacementReviewRoundReport.Flush(scope); Entries.Sort(CompareEntries); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; StringBuilder stringBuilder = new StringBuilder(512 + Entries.Count * 160); stringBuilder.Append("[Y4NGZ.AuthoredPlacement] ROUND_REPORT"); stringBuilder.Append(" flow='").Append(NormalizeDetail(_flowName)).Append('\''); stringBuilder.Append(" dungeon='").Append(NormalizeDetail(_dungeonName)).Append('\''); stringBuilder.Append(" scope=").Append(scope); stringBuilder.AppendLine(); stringBuilder.Append(" considered-current-flow=").Append(Entries.Count).AppendLine(); for (int i = 0; i < Entries.Count; i++) { ReportEntry reportEntry = Entries[i]; string text = ResolveDisplayOutcome(reportEntry); if (string.Equals(reportEntry.MatchOutcome, "matched-exact", StringComparison.Ordinal)) { num++; } else if (string.Equals(reportEntry.MatchOutcome, "matched-marker", StringComparison.Ordinal)) { num2++; } else if (string.Equals(reportEntry.MatchOutcome, "matched-name", StringComparison.Ordinal)) { num3++; if (reportEntry.CandidateCount > 1) { num4++; } } switch (text) { case "spawned": num5++; break; case "suppressed": num6++; break; case "validation-failed": num7++; break; case "shadowed-by-local": num8++; break; case "tile-absent": num9++; break; default: num10++; break; } stringBuilder.Append(" - kind=").Append(NormalizeDetail(reportEntry.Record.objectKind)); stringBuilder.Append(" id='").Append(NormalizeDetail(reportEntry.Record.objectId)).Append('\''); stringBuilder.Append(" source=").Append(NormalizeDetail(reportEntry.Source)); stringBuilder.Append(" tile='").Append(NormalizeDetail(reportEntry.Record.tileName)).Append('\''); if (!string.IsNullOrEmpty(reportEntry.MatchOutcome)) { stringBuilder.Append(" match=").Append(reportEntry.MatchOutcome); if (string.Equals(reportEntry.MatchOutcome, "matched-name", StringComparison.Ordinal) && reportEntry.CandidateCount > 1) { stringBuilder.Append(" candidates=").Append(reportEntry.CandidateCount); } if (!string.IsNullOrEmpty(reportEntry.ResolvedTileName) && !string.Equals(reportEntry.ResolvedTileName, reportEntry.Record.tileName, StringComparison.Ordinal)) { stringBuilder.Append(" resolvedTile='").Append(NormalizeDetail(reportEntry.ResolvedTileName)).Append('\''); } } else { stringBuilder.Append(" match=none"); } stringBuilder.Append(" outcome=").Append(text); if (!string.IsNullOrEmpty(reportEntry.Detail)) { stringBuilder.Append(" detail=").Append(reportEntry.Detail); } stringBuilder.AppendLine(); } stringBuilder.Append(" summary matches(exact/marker/name/ambiguous-name)=").Append(num).Append('/') .Append(num2) .Append('/') .Append(num3) .Append('/') .Append(num4) .Append(" outcomes(spawned/suppressed/validation-failed/shadowed/tile-absent/resolved-but-unused)=") .Append(num5) .Append('/') .Append(num6) .Append('/') .Append(num7) .Append('/') .Append(num8) .Append('/') .Append(num9) .Append('/') .Append(num10) .AppendLine(); stringBuilder.Append(" Other flows: ").Append(_otherFlowRecordCount).Append(" merged authored record(s) not listed."); ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } private static string ResolveDisplayOutcome(ReportEntry entry) { if (!string.IsNullOrEmpty(entry.FinalOutcome)) { return entry.FinalOutcome; } if (!string.IsNullOrEmpty(entry.MatchOutcome)) { return "resolved-but-unused"; } return "tile-absent"; } private static ReportEntry GetOrCreate(AuthoredInteriorPlacementRecord record, string source) { ReportEntry reportEntry = FindEntry(record); if (reportEntry != null) { if (string.IsNullOrWhiteSpace(reportEntry.Source) && !string.IsNullOrWhiteSpace(source)) { reportEntry.Source = source.Trim(); } return reportEntry; } reportEntry = new ReportEntry { Record = record, Source = NormalizeLabel(source, "unknown") }; Entries.Add(reportEntry); return reportEntry; } private static ReportEntry FindEntry(AuthoredInteriorPlacementRecord record) { for (int i = 0; i < Entries.Count; i++) { if (Entries[i].Record == record) { return Entries[i]; } } return null; } private static void SetFinalOutcome(ReportEntry entry, string outcome, string detail, OutcomePriority priority) { if (entry != null && priority >= entry.Priority) { entry.FinalOutcome = outcome; entry.Detail = detail ?? string.Empty; entry.Priority = priority; } } private static int CompareEntries(ReportEntry a, ReportEntry b) { int num = string.Compare(a?.Record?.objectKind ?? string.Empty, b?.Record?.objectKind ?? string.Empty, StringComparison.OrdinalIgnoreCase); if (num != 0) { return num; } int num2 = string.Compare(a?.Record?.objectId ?? string.Empty, b?.Record?.objectId ?? string.Empty, StringComparison.OrdinalIgnoreCase); if (num2 != 0) { return num2; } int num3 = string.Compare(a?.Source ?? string.Empty, b?.Source ?? string.Empty, StringComparison.OrdinalIgnoreCase); if (num3 != 0) { return num3; } return string.Compare(a?.Record?.tileName ?? string.Empty, b?.Record?.tileName ?? string.Empty, StringComparison.Ordinal); } private static string NormalizeLabel(string value, string fallback) { if (!string.IsNullOrWhiteSpace(value)) { return value.Trim(); } return fallback; } private static string NormalizeDetail(string value) { if (string.IsNullOrWhiteSpace(value)) { return "none"; } return value.Replace('\r', ' ').Replace('\n', ' ').Trim(); } } public readonly struct HostFacilityPlacementReadiness { public bool HostPeer { get; } public bool CameraPassComplete { get; } public bool HostFixturePassComplete { get; } public bool IsReady { get { if (HostPeer && CameraPassComplete) { return HostFixturePassComplete; } return false; } } public string OutstandingPrerequisites { get { List list = new List(3); if (!HostPeer) { list.Add("host-peer"); } if (!CameraPassComplete) { list.Add("CCTV"); } if (!HostFixturePassComplete) { list.Add("Mainframe/Stash"); } if (list.Count != 0) { return string.Join(",", list); } return "none"; } } public HostFacilityPlacementReadiness(bool hostPeer, bool cameraPassComplete, bool hostFixturePassComplete) { HostPeer = hostPeer; CameraPassComplete = cameraPassComplete; HostFixturePassComplete = hostFixturePassComplete; } public string ToDiagnosticString() { return $"hostPeer={HostPeer} cameraPass={CameraPassComplete} " + $"hostFixtures={HostFixturePassComplete} outstanding=[{OutstandingPrerequisites}]"; } } } namespace Y4NGZCompany.Facility.Cameras.Placement { internal enum CameraTileShape { Room, LongStraightHallway, LShapedHallway } internal static class TileShapeClassifier { private const float LongHallwayAspect = 2.8f; private const float LHallwayMinSpanM = 6f; private const float StrictMinSpanM = 3.5f; private const float RelaxedMinSpanM = 2.5f; private const float StrictAspectRatio = 3.7f; private const float RelaxedAspectRatio = 5.2f; private const float HallwayMaxAreaM2 = 110f; internal static CameraTileShape ClassifyByDoorwaySpans(float spanX, float spanZ) { float num = Mathf.Max(spanX, spanZ); float num2 = Mathf.Max(0.01f, Mathf.Min(spanX, spanZ)); if (num > num2 * 2.8f) { return CameraTileShape.LongStraightHallway; } if (num2 < 6f) { return CameraTileShape.LShapedHallway; } return CameraTileShape.Room; } internal static bool IsHallwayShape(CameraTileShape shape) { if (shape != CameraTileShape.LongStraightHallway) { return shape == CameraTileShape.LShapedHallway; } return true; } internal static bool LooksHallwayLike(Bounds bounds, float area, bool strict) { //IL_0002: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z); float num2 = Mathf.Max(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z); float num3 = (strict ? 3.5f : 2.5f); float num4 = (strict ? 3.7f : 5.2f); if (!(num < num3)) { if (num2 > num * num4) { return area < 110f; } return false; } return true; } } } namespace Y4NGZCompany.Core { internal static class NetcodeRuntimeBootstrap { private static readonly HashSet Initialized = new HashSet(); internal static void Initialize(ManualLogSource log, Assembly assembly, bool requireInitializers = true) { if (assembly == null) { throw new ArgumentNullException("assembly"); } if (Initialized.Contains(assembly)) { return; } int num = 0; Type[] types = assembly.GetTypes(); foreach (Type type in types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0) { if (methodInfo.GetParameters().Length != 0) { throw new InvalidOperationException("Runtime initializer " + type.FullName + "." + methodInfo.Name + " must be parameterless."); } try { methodInfo.Invoke(null, null); } catch (TargetInvocationException ex) { throw new InvalidOperationException("Runtime initializer " + type.FullName + "." + methodInfo.Name + " failed.", ex.InnerException ?? ex); } num++; } } } if (num == 0 && requireInitializers) { throw new InvalidOperationException("No NetcodePatcher runtime initializers were found in " + assembly.GetName().Name + ". Build and deploy the Release-patched assembly."); } Initialized.Add(assembly); if (log != null) { log.LogInfo((object)$"Initialized {num} NetcodePatcher runtime initializer(s) in {assembly.GetName().Name}."); } } } internal static class Y4NGZCompanyPaths { internal const string LocalDataDirName = "Y4NGZCompany"; internal static string LocalDataDir => Path.Combine(Paths.ConfigPath, "Y4NGZCompany"); internal static string LocalDataFile(string fileName) { return Path.Combine(LocalDataDir, fileName); } } } namespace Y4NGZCompany.Core.Compat { internal static class DawnLibCompat { [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void RegisterNetworkPrefab(GameObject prefab) { DawnLib.RegisterNetworkPrefab(prefab); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void RegisterItem(string itemName, Item item) { if (!((Object)(object)item == (Object)null) && !string.IsNullOrWhiteSpace(itemName)) { DawnLib.DefineItem(NamespacedKey.From("lgu_contract_hud", itemName), item, (Action)delegate { }); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void FixMixerGroups(GameObject prefab) { DawnLib.FixMixerGroups(prefab); } } public static class FacilityMeltdownCompat { public const string PLUGIN_GUID = "me.loaforc.facilitymeltdown"; private static readonly bool _isLoaded = Chainloader.PluginInfos.ContainsKey("me.loaforc.facilitymeltdown"); private const string OwnPluginGuid = "com.y4ngz.company"; private static bool _resolved; private static bool _listenerRegistered; private static Type _apiType; private static PropertyInfo _meltdownStartedProperty; private static MethodInfo _startMeltdownMethod; private static int _sampledFrame = -1; private static bool _sampledLightsOn; public static bool IsLoaded => _isLoaded; public static bool IsMeltdownRunning { get { if (!_isLoaded) { return false; } ResolveTypes(); if (_meltdownStartedProperty == null) { return false; } try { object value = _meltdownStartedProperty.GetValue(null); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch (Exception ex) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)("[LethalCCTV] FacilityMeltdown state read failed, integration going inert: " + ex.Message)); } _meltdownStartedProperty = null; return false; } } } public static bool EmergencyLightsOn { get { int frameCount = Time.frameCount; if (frameCount == _sampledFrame) { return _sampledLightsOn; } _sampledFrame = frameCount; _sampledLightsOn = SampleEmergencyLights(); return _sampledLightsOn; } } public static event Action MeltdownStarted; public static void Initialize() { if (_isLoaded) { ResolveTypes(); RegisterMeltdownListener(); } } public static bool TryStartMeltdown() { if (!_isLoaded) { return false; } ResolveTypes(); if (_startMeltdownMethod == null) { return false; } if (IsMeltdownRunning) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogInfo((object)"[LethalCCTV] FacilityMeltdown already running; not starting a second sequence."); } return true; } try { object[] parameters = ((_startMeltdownMethod.GetParameters().Length != 1) ? new object[0] : new object[1] { "com.y4ngz.company" }); _startMeltdownMethod.Invoke(null, parameters); ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)"[LethalCCTV] FacilityMeltdown sequence started."); } return true; } catch (Exception ex) { ManualLogSource log3 = CoreDiagnostics.Log; if (log3 != null) { log3.LogWarning((object)("[LethalCCTV] FacilityMeltdown StartMeltdown failed: " + ex.Message)); } return false; } } private static bool SampleEmergencyLights() { if (!IsMeltdownRunning) { return false; } RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } List allPoweredLightsAnimators = instance.allPoweredLightsAnimators; if (allPoweredLightsAnimators == null) { return false; } for (int i = 0; i < allPoweredLightsAnimators.Count; i++) { Animator val = allPoweredLightsAnimators[i]; if (!((Object)(object)val == (Object)null)) { try { return val.GetBool("on"); } catch { return false; } } } return false; } private static void ResolveTypes() { if (_resolved) { return; } _resolved = true; _apiType = Type.GetType("FacilityMeltdown.API.MeltdownAPI, FacilityMeltdown", throwOnError: false); if (_apiType == null) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)"[LethalCCTV] FacilityMeltdown is installed but MeltdownAPI did not resolve; integration inert."); } return; } _meltdownStartedProperty = _apiType.GetProperty("MeltdownStarted", BindingFlags.Static | BindingFlags.Public); if (_meltdownStartedProperty == null) { ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogWarning((object)"[LethalCCTV] FacilityMeltdown MeltdownStarted not found; alarm-fixture sync inert."); } } _startMeltdownMethod = _apiType.GetMethod("StartMeltdown", BindingFlags.Static | BindingFlags.Public); if (_startMeltdownMethod == null) { ManualLogSource log3 = CoreDiagnostics.Log; if (log3 != null) { log3.LogWarning((object)"[LethalCCTV] FacilityMeltdown StartMeltdown not found; Defuse detonation will use the local blast only."); } } } private static void RegisterMeltdownListener() { if (_listenerRegistered || _apiType == null) { return; } MethodInfo method = _apiType.GetMethod("RegisterMeltdownListener", BindingFlags.Static | BindingFlags.Public); if (method == null) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogWarning((object)"[LethalCCTV] FacilityMeltdown RegisterMeltdownListener not found; apparatus-pull shutdown inert."); } return; } try { method.Invoke(null, new object[1] { new Action(OnMeltdownStarted) }); _listenerRegistered = true; ManualLogSource log2 = CoreDiagnostics.Log; if (log2 != null) { log2.LogInfo((object)"[LethalCCTV] FacilityMeltdown listener registered."); } } catch (Exception ex) { ManualLogSource log3 = CoreDiagnostics.Log; if (log3 != null) { log3.LogWarning((object)("[LethalCCTV] FacilityMeltdown listener registration failed: " + ex.Message)); } } } private static void OnMeltdownStarted() { Action meltdownStarted = FacilityMeltdownCompat.MeltdownStarted; if (meltdownStarted == null) { return; } Delegate[] invocationList = meltdownStarted.GetInvocationList(); foreach (Delegate obj in invocationList) { try { ((Action)obj)(); } catch (Exception arg) { ManualLogSource log = CoreDiagnostics.Log; if (log != null) { log.LogError((object)$"[LethalCCTV] FacilityMeltdown security shutdown failed: {arg}"); } } } } } public static class Y4NGZUpgradesCompat { public const string PLUGIN_GUID = "com.y4ngz.upgrades"; public const string ASSEMBLY_NAME = "Y4NGZUpgrades"; private static readonly bool _isLoaded = Chainloader.PluginInfos.ContainsKey("com.y4ngz.upgrades"); public static bool IsLoaded => _isLoaded; public static void Initialize() { if (_isLoaded) { InitializeImpl(); } } private static void InitializeImpl() { } } } namespace Y4NGZCore { [BepInPlugin("com.y4ngz.core", "Y4NGZCore", "1.0.0")] public sealed class CorePlugin : BaseUnityPlugin { public const string PluginGuid = "com.y4ngz.core"; public const string PluginName = "Y4NGZCore"; public const string PluginVersion = "1.0.0"; public static CorePlugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Y4NGZCore 1.0.0 loaded."); } } public static class CoreDiagnostics { private static ManualLogSource _log; public static ManualLogSource Log { get { if (_log != null) { return _log; } _log = CorePlugin.Log ?? Logger.CreateLogSource("Y4NGZCore"); return _log; } set { _log = value; } } public static Func DetailedPlacementRejectLoggingProvider { get; set; } public static bool DetailedPlacementRejectLogging { get { Func detailedPlacementRejectLoggingProvider = DetailedPlacementRejectLoggingProvider; if (detailedPlacementRejectLoggingProvider == null) { return false; } try { return detailedPlacementRejectLoggingProvider(); } catch { return false; } } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Y4NGZCore"; public const string PLUGIN_NAME = "Y4NGZCore"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }