using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance; using GameNetcodeStuff; using HarmonyLib; using HorrorDirectorMod.Anomaly; using HorrorDirectorMod.Bootstrap; using HorrorDirectorMod.Content; using HorrorDirectorMod.Dev; using HorrorDirectorMod.Diagnostics; using HorrorDirectorMod.Director; using HorrorDirectorMod.Input; using HorrorDirectorMod.Lifecycle; using HorrorDirectorMod.Objectives; using HorrorDirectorMod.Observation; using HorrorDirectorMod.Progression; using HorrorDirectorMod.Terminal; using Microsoft.CodeAnalysis; using TerminalApi; using TerminalApi.Classes; using TerminalApi.Events; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("HorrorDirectorMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("First feasibility probe for a Lethal Company horror director mod.")] [assembly: AssemblyFileVersion("0.1.3.0")] [assembly: AssemblyInformationalVersion("0.1.3+032cd2883379c17aa34138bb9e6452b21b785dc2")] [assembly: AssemblyProduct("HorrorDirectorMod")] [assembly: AssemblyTitle("HorrorDirectorMod")] [assembly: AssemblyVersion("0.1.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HorrorDirectorMod { [BepInPlugin("linar.horrordirector", "Horror Director Mod", "0.1.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "linar.horrordirector"; public const string PluginName = "Horror Director Mod"; public const string PluginVersion = "0.1.3"; private Harmony? _harmony; internal static ManualLogSource ModLogger { get; private set; } private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown ModLogger = ((BaseUnityPlugin)this).Logger; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ConfigService config = new ConfigService(((BaseUnityPlugin)this).Config); ModServices.Initialize(((BaseUnityPlugin)this).Logger, config); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HDM:Bootstrap] Horror Director Mod 0.1.3 loaded."); _harmony = new Harmony("linar.horrordirector"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HDM:Bootstrap] Harmony patches applied."); ModServices.Diagnostics.StartBackgroundHeartbeat(); ModServices.Diagnostics.LogHeartbeat("Awake smoke test"); } private void OnEnable() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HDM:Bootstrap] Plugin enabled."); } private void OnDestroy() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HDM:Bootstrap] Plugin object destroyed; static services may continue for diagnostics."); } private void OnApplicationQuit() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HDM:Bootstrap] Application quitting."); ModServices.Shutdown(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; } } public static class PluginInfo { public const string PLUGIN_GUID = "HorrorDirectorMod"; public const string PLUGIN_NAME = "HorrorDirectorMod"; public const string PLUGIN_VERSION = "0.1.3"; } } namespace HorrorDirectorMod.Terminal { internal sealed class HauntedCaseTerminalService { private const string CommandWord = "hdmcase"; private const string AliasCommandWord = "case"; private readonly ManualLogSource _logger; private readonly ConfigService _config; private readonly WrongPlaceEpisodeDirector _wrongPlaceEpisodeDirector; private bool _registered; public HauntedCaseTerminalService(ManualLogSource logger, ConfigService config, WrongPlaceEpisodeDirector wrongPlaceEpisodeDirector) { _logger = logger; _config = config; _wrongPlaceEpisodeDirector = wrongPlaceEpisodeDirector; } public void Initialize() { //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_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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //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) //IL_0062: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if (!_registered) { TerminalApi.AddCommand("hdmcase", new CommandInfo { Title = "HDM Case", Category = "Other", Description = "Displays the Horror Director case file.", DisplayTextSupplier = DisplayCaseFile }, (string)null, true); TerminalApi.AddCommand("case", new CommandInfo { Title = "Case", Category = "Other", Description = "Alias for the Horror Director case file.", DisplayTextSupplier = DisplayCaseFile }, (string)null, true); _registered = true; _logger.LogInfo((object)"[HDM:Terminal] Registered hdmcase/case commands."); } } public void Shutdown() { _registered = false; } private string DisplayCaseFile() { if (!_config.WrongPlaceAllowTerminalWrongness) { return "HDM CASE FILE\n\nTerminal wrongness is disabled by config.\n\n"; } return "HDM CASE FILE\n\n" + $"State: {_wrongPlaceEpisodeDirector.State}\n" + "Episode: " + FormatEpisodeId() + "\nSignal: " + _wrongPlaceEpisodeDirector.TerminalStatus + "\n\nNotes:\n- ship safety signal unreliable\n- facility return route under observation\n- do not trust repeated sounds\n\n"; } private string FormatEpisodeId() { if (!(_wrongPlaceEpisodeDirector.EpisodeId == Guid.Empty)) { return _wrongPlaceEpisodeDirector.EpisodeId.ToString("N").Substring(0, 8); } return "none"; } } internal sealed class TerminalAnomalyDebugService { private const string CommandWord = "hdmaudio"; private const string AliasCommandWord = "audio"; private readonly ManualLogSource _logger; private readonly GameObserver _observer; private readonly AnomalyEventBus _anomalyEventBus; private bool _registered; public TerminalAnomalyDebugService(ManualLogSource logger, GameObserver observer, AnomalyEventBus anomalyEventBus) { _logger = logger; _observer = observer; _anomalyEventBus = anomalyEventBus; } public void Initialize() { //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_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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //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) //IL_0062: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if (!_registered) { TerminalApi.AddCommand("hdmaudio", new CommandInfo { Title = "HDM Audio", Category = "Other", Description = "Debug trigger for the Horror Director fake audio cue.", DisplayTextSupplier = TriggerFakeAudioCue }, (string)null, true); TerminalApi.AddCommand("audio", new CommandInfo { Title = "Audio", Category = "Other", Description = "Alias for the Horror Director fake audio cue debug trigger.", DisplayTextSupplier = TriggerFakeAudioCue }, (string)null, true); _registered = true; _logger.LogInfo((object)"[HDM:Terminal] Registered hdmaudio/audio commands."); } } public void Shutdown() { _registered = false; } private string TriggerFakeAudioCue() { StartOfRound round = Object.FindObjectOfType(); GameObservation observation = _observer.Observe(round); AnomalyTriggerResult anomalyTriggerResult = _anomalyEventBus.TryTriggerDebugFakeAudioCue(observation, "terminal command hdmaudio/audio"); if (anomalyTriggerResult.Success) { return "HDM AUDIO PROBE\n\nFake audio cue dispatched.\n" + $"Event id: {anomalyTriggerResult.EventId}\n\n"; } return "HDM AUDIO PROBE\n\nFake audio cue was not dispatched.\nReason: " + anomalyTriggerResult.Message + "\n\n"; } } internal sealed class TerminalFacilityObjectiveService { private const string SpawnCommandWord = "objspawn"; private const string SpawnSelfCommandWord = "objself"; private const string StartCommandWord = "objstart"; private readonly ManualLogSource _logger; private readonly ConfigService _config; private readonly FacilityObjectiveService _objectives; private bool _registered; public TerminalFacilityObjectiveService(ManualLogSource logger, ConfigService config, FacilityObjectiveService objectives) { _logger = logger; _config = config; _objectives = objectives; } public void Initialize() { //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_003c: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_00af: Expected O, but got Unknown //IL_00b4: 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_00c4: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown if (!_registered) { if (!_config.FacilityObjectiveEnabled) { _logger.LogInfo((object)"[HDM:Terminal] Facility objective commands disabled by config."); return; } TerminalApi.AddCommand("objspawn", new CommandInfo { Title = "HDM Objective Spawn", Category = "Other", Description = "Spawns a local facility objective debug panel near the player.", DisplayTextSupplier = SpawnObjective }, (string)null, true); TerminalApi.AddCommand("objself", new CommandInfo { Title = "HDM Objective Self", Category = "Other", Description = "Spawns a local facility objective debug panel at the player position.", DisplayTextSupplier = SpawnObjectiveAtPlayer }, (string)null, true); TerminalApi.AddCommand("objstart", new CommandInfo { Title = "HDM Objective Start", Category = "Other", Description = "Starts the pipe-routing facility objective probe.", DisplayTextSupplier = StartPipePuzzle }, (string)null, true); _registered = true; _logger.LogInfo((object)"[HDM:Terminal] Registered objspawn/objself/objstart commands."); } } public void Shutdown() { if (_registered) { _registered = false; } } private string SpawnObjective() { return FormatSpawnResult(_objectives.SpawnDebugObjective("terminal command objspawn"), "near you"); } private string SpawnObjectiveAtPlayer() { return FormatSpawnResult(_objectives.SpawnDebugObjectiveAtPlayer("terminal command objself"), "at your position"); } private string StartPipePuzzle() { return FormatPuzzleOpened(_objectives.StartPipePuzzleFromDebugCommand("terminal command objstart")); } private static string FormatSpawnResult(ObjectiveProbeResult result, string locationText) { if (result.Success) { return "HDM FACILITY OBJECTIVE\n\nObjective panel spawned " + locationText + ".\nObject: " + result.ObjectiveName + "\n\nLook at the panel and press E, or type objstart to open its local terminal.\n\n"; } return "HDM FACILITY OBJECTIVE\n\nObjective panel was not spawned.\nReason: " + result.Message + "\n\n"; } private static string FormatPuzzleOpened(PipePuzzle puzzle) { return "HDM FACILITY OBJECTIVE\n\nLocal objective terminal opened.\nUse the panel UI that appeared on your screen.\n\n" + $"Reward: {puzzle.RewardCredits} credits.\n\n"; } } internal sealed class TerminalMathGameService { private sealed class MathPuzzle { public string Expression { get; } public int Answer { get; } public int RewardCredits { get; } public MathPuzzle(string expression, int answer, int rewardCredits) { Expression = expression; Answer = answer; RewardCredits = rewardCredits; } } private const string CommandWord = "math"; private readonly ManualLogSource _logger; private readonly ConfigService _config; private readonly Random _random = new Random(); private MathPuzzle? _pendingPuzzle; private bool _registered; public TerminalMathGameService(ManualLogSource logger, ConfigService config) { _logger = logger; _config = config; } public void Initialize() { //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_003c: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if (!_registered) { if (!_config.TerminalMathEnabled) { _logger.LogInfo((object)"[HDM:Terminal] Math command disabled by config."); return; } TerminalApi.AddCommand("math", new CommandInfo { Title = "Math", Category = "Other", Description = "Solve a small arithmetic task for credits.", DisplayTextSupplier = StartPuzzle }, (string)null, true); Events.TerminalParsedSentence += new TerminalParseSentenceEventHandler(OnTerminalParsedSentence); _registered = true; _logger.LogInfo((object)"[HDM:Terminal] Registered math command."); } } public void Shutdown() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown if (_registered) { Events.TerminalParsedSentence -= new TerminalParseSentenceEventHandler(OnTerminalParsedSentence); _registered = false; _pendingPuzzle = null; } } private string StartPuzzle() { _pendingPuzzle = GeneratePuzzle(); _logger.LogInfo((object)$"[HDM:Terminal] Math puzzle generated: expression='{_pendingPuzzle.Expression}', answer={_pendingPuzzle.Answer}, reward={_pendingPuzzle.RewardCredits}."); return FormatPuzzlePrompt(_pendingPuzzle); } private void OnTerminalParsedSentence(object sender, TerminalParseSentenceEventArgs e) { if (_pendingPuzzle == null || e.ReturnedNode == null) { return; } string text = (e.SubmittedText ?? string.Empty).Trim(); if (!text.Equals("math", StringComparison.OrdinalIgnoreCase)) { if (!int.TryParse(text, out var result)) { e.ReturnedNode.displayText = FormatInvalidAnswer(_pendingPuzzle); e.ReturnedNode.clearPreviousText = true; return; } if (result != _pendingPuzzle.Answer) { _logger.LogInfo((object)$"[HDM:Terminal] Math puzzle answered incorrectly: submitted={result}, expected={_pendingPuzzle.Answer}."); e.ReturnedNode.displayText = FormatWrongAnswer(_pendingPuzzle); e.ReturnedNode.clearPreviousText = true; return; } int rewardCredits = _pendingPuzzle.RewardCredits; int num = AwardCredits(((TerminalEventArgs)e).Terminal, rewardCredits); _logger.LogInfo((object)$"[HDM:Terminal] Math puzzle solved. reward={rewardCredits}, credits={num}."); e.ReturnedNode.displayText = FormatSuccess(rewardCredits, num); e.ReturnedNode.clearPreviousText = true; _pendingPuzzle = null; } } private MathPuzzle GeneratePuzzle() { if (_random.Next(0, 2) == 0) { int num = _random.Next(2, 13); int num2 = _random.Next(2, 13); return new MathPuzzle($"{num} * {num2}", num * num2, _config.TerminalMathRewardCredits); } int num3 = _random.Next(1, 51); int num4 = _random.Next(1, 51); return new MathPuzzle($"{num3} + {num4}", num3 + num4, _config.TerminalMathRewardCredits); } private static int AwardCredits(Terminal terminal, int reward) { if (terminal == null || reward <= 0) { return terminal?.groupCredits ?? 0; } terminal.groupCredits += reward; return terminal.groupCredits; } private static string FormatPuzzlePrompt(MathPuzzle puzzle) { return "HORROR DIRECTOR MATH PROBE\n\nSolve: " + puzzle.Expression + " = ?\n\nType only the answer and press enter.\n" + $"Reward: {puzzle.RewardCredits} credits.\n\n"; } private static string FormatInvalidAnswer(MathPuzzle puzzle) { return "Enter a number to answer the active math task.\n\nSolve: " + puzzle.Expression + " = ?\n\n"; } private static string FormatWrongAnswer(MathPuzzle puzzle) { return "Incorrect. Try again.\n\nSolve: " + puzzle.Expression + " = ?\n\n"; } private static string FormatSuccess(int reward, int credits) { return "Correct.\n\n" + $"Awarded {reward} credits.\n" + $"Current group credits: {credits}.\n\n" + "Type math for another task.\n\n"; } } internal sealed class TerminalPropDebugService { private const string SpawnCommandWord = "propspawn"; private const string SpawnSelfCommandWord = "propself"; private const string AnomalyCommandWord = "propanomaly"; private const string AnomalyAliasCommandWord = "propgo"; private const string NearbyAnomalyCommandWord = "propnear"; private readonly ManualLogSource _logger; private readonly PropAnomalyService _propAnomaly; private bool _registered; public TerminalPropDebugService(ManualLogSource logger, PropAnomalyService propAnomaly) { _logger = logger; _propAnomaly = propAnomaly; } public void Initialize() { //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_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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //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) //IL_0062: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //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_00a6: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_015d: Expected O, but got Unknown if (!_registered) { TerminalApi.AddCommand("propspawn", new CommandInfo { Title = "HDM Prop Spawn", Category = "Other", Description = "Spawns a local debug prop near the player.", DisplayTextSupplier = SpawnDebugProp }, (string)null, true); TerminalApi.AddCommand("propanomaly", new CommandInfo { Title = "HDM Prop Anomaly", Category = "Other", Description = "Triggers a local anomaly on the last debug prop.", DisplayTextSupplier = TriggerPropAnomaly }, (string)null, true); TerminalApi.AddCommand("propself", new CommandInfo { Title = "HDM Prop Self", Category = "Other", Description = "Spawns a local debug prop directly at the player position.", DisplayTextSupplier = SpawnDebugPropAtPlayer }, (string)null, true); TerminalApi.AddCommand("propnear", new CommandInfo { Title = "HDM Prop Near", Category = "Other", Description = "Triggers an anomaly on the nearest real grabbable item.", DisplayTextSupplier = TriggerNearestGrabbableAnomaly }, (string)null, true); TerminalApi.AddCommand("propgo", new CommandInfo { Title = "HDM Prop Go", Category = "Other", Description = "Alias for the debug prop anomaly.", DisplayTextSupplier = TriggerPropAnomaly }, (string)null, true); _registered = true; _logger.LogInfo((object)"[HDM:Terminal] Registered propspawn/propself/propanomaly/propgo/propnear commands."); } } public void Shutdown() { _registered = false; } private string SpawnDebugProp() { PropProbeResult propProbeResult = _propAnomaly.SpawnDebugProp("terminal command propspawn"); if (propProbeResult.Success) { return "HDM PROP PROBE\n\nDebug prop spawned near you.\nProp: " + propProbeResult.PropName + "\n\nRun propanomaly or propgo to make it move.\n\n"; } return "HDM PROP PROBE\n\nDebug prop was not spawned.\nReason: " + propProbeResult.Message + "\n\n"; } private string SpawnDebugPropAtPlayer() { PropProbeResult propProbeResult = _propAnomaly.SpawnDebugPropAtPlayerPosition("terminal command propself"); if (propProbeResult.Success) { return "HDM PROP PROBE\n\nDebug prop spawned at your position.\nProp: " + propProbeResult.PropName + "\n\nRun propanomaly or propgo to make it move.\n\n"; } return "HDM PROP PROBE\n\nDebug prop was not spawned at your position.\nReason: " + propProbeResult.Message + "\n\n"; } private string TriggerPropAnomaly() { PropProbeResult propProbeResult = _propAnomaly.TriggerDebugAnomaly("terminal command propanomaly/propgo"); if (propProbeResult.Success) { return "HDM PROP PROBE\n\nProp anomaly triggered.\nProp: " + propProbeResult.PropName + "\n\n"; } return "HDM PROP PROBE\n\nProp anomaly was not triggered.\nReason: " + propProbeResult.Message + "\n\n"; } private string TriggerNearestGrabbableAnomaly() { PropProbeResult propProbeResult = _propAnomaly.TriggerNearestGrabbableAnomaly("terminal command propnear"); if (propProbeResult.Success) { return "HDM PROP PROBE\n\nNearest real item anomaly triggered.\nItem: " + propProbeResult.PropName + "\n\n"; } return "HDM PROP PROBE\n\nNearest real item anomaly was not triggered.\nReason: " + propProbeResult.Message + "\n\n"; } } } namespace HorrorDirectorMod.Progression { internal interface IModifierApplier { void Apply(PlayerControllerB player, ProgressionTotals totals, string reason); void Restore(PlayerControllerB? player, string reason); } internal sealed class PlayerStatApplier : IModifierApplier { private readonly struct PlayerBaseline { public ulong PlayerClientId { get; } public int Health { get; } public float MovementSpeed { get; } public float SprintTime { get; } public float GrabDistance { get; } public PlayerBaseline(ulong playerClientId, int health, float movementSpeed, float sprintTime, float grabDistance) { PlayerClientId = playerClientId; Health = health; MovementSpeed = movementSpeed; SprintTime = sprintTime; GrabDistance = grabDistance; } } private readonly ManualLogSource _logger; private PlayerBaseline? _baseline; private bool _hasAppliedTotals; public PlayerStatApplier(ManualLogSource logger) { _logger = logger; } public void Apply(PlayerControllerB player, ProgressionTotals totals, string reason) { EnsureBaseline(player); if (_baseline.HasValue) { PlayerBaseline value = _baseline.Value; int num = Math.Max(1, value.Health + totals.HealthBonus); float num2 = value.MovementSpeed * Math.Max(0.1f, totals.MovementMultiplier); float num3 = value.SprintTime * Math.Max(0.1f, totals.SprintTimeMultiplier); float num4 = value.GrabDistance * Math.Max(0.1f, totals.GrabDistanceMultiplier); player.movementSpeed = num2; player.sprintTime = num3; player.grabDistance = num4; if (!player.isPlayerDead && player.health < num) { player.health = num; } if (!_hasAppliedTotals || reason != "tick") { _logger.LogInfo((object)$"[HDM:Progression] Applied stats: player={player.playerClientId}, healthTarget={num}, move={num2:0.00}, sprintTime={num3:0.00}, grab={num4:0.00}, reason='{reason}'."); _hasAppliedTotals = true; } } } public void Restore(PlayerControllerB? player, string reason) { if (player == null || !_baseline.HasValue) { return; } PlayerBaseline value = _baseline.Value; if (value.PlayerClientId == player.playerClientId) { player.movementSpeed = value.MovementSpeed; player.sprintTime = value.SprintTime; player.grabDistance = value.GrabDistance; if (!player.isPlayerDead && player.health > value.Health) { player.health = value.Health; } _hasAppliedTotals = false; _logger.LogInfo((object)$"[HDM:Progression] Restored baseline stats: player={player.playerClientId}, reason='{reason}'."); } } public void ForgetPlayer() { _baseline = null; _hasAppliedTotals = false; } private void EnsureBaseline(PlayerControllerB player) { if (!_baseline.HasValue || _baseline.Value.PlayerClientId != player.playerClientId) { _baseline = new PlayerBaseline(player.playerClientId, Math.Max(1, player.health), Math.Max(0.1f, player.movementSpeed), Math.Max(0.1f, player.sprintTime), Math.Max(0.1f, player.grabDistance)); _hasAppliedTotals = false; _logger.LogInfo((object)$"[HDM:Progression] Captured baseline stats: player={player.playerClientId}, health={player.health}, move={player.movementSpeed:0.00}, sprintTime={player.sprintTime:0.00}, grab={player.grabDistance:0.00}."); } } } internal enum ProgressionUpgradeId { None, ReinforcedSuit, EmergencyPadding, RunnerConditioning, BiggerLungs, SteadyHands, DeepPockets, AdrenalineStep, SteadyNerves, IronWill } internal enum ProgressionEffectKind { HealthBonus, MovementMultiplier, SprintTimeMultiplier, GrabDistanceMultiplier, Placeholder } internal sealed class UpgradeDefinition { public string Id { get; } public ProgressionUpgradeId NetworkId { get; } public string Branch { get; } public string Title { get; } public string Description { get; } public int Cost { get; } public ProgressionEffectKind EffectKind { get; } public float EffectValue { get; } public bool Available { get; } public UpgradeDefinition(string id, ProgressionUpgradeId networkId, string branch, string title, string description, int cost, ProgressionEffectKind effectKind, float effectValue, bool available) { Id = id; NetworkId = networkId; Branch = branch; Title = title; Description = description; Cost = cost; EffectKind = effectKind; EffectValue = effectValue; Available = available; } } internal enum ProgressionNetworkMessageKind { PurchaseRequest = 1, ResetRequest = 2, RequestState = 3, StateSnapshot = 10, PurchaseRejected = 11 } internal enum ProgressionRejectReason { None, UnknownUpgrade, Unavailable, AlreadyOwned, NotEnoughPoints, NotHost, NetworkUnavailable } internal readonly struct ProgressionNetworkSnapshot { public ulong TargetClientId { get; } public int AvailablePoints { get; } public int OwnedMask { get; } public ProgressionNetworkSnapshot(ulong targetClientId, int availablePoints, int ownedMask) { TargetClientId = targetClientId; AvailablePoints = availablePoints; OwnedMask = ownedMask; } } internal readonly struct ProgressionNetworkReject { public ulong TargetClientId { get; } public ProgressionUpgradeId UpgradeId { get; } public ProgressionRejectReason Reason { get; } public ProgressionNetworkReject(ulong targetClientId, ProgressionUpgradeId upgradeId, ProgressionRejectReason reason) { TargetClientId = targetClientId; UpgradeId = upgradeId; Reason = reason; } } internal readonly struct ProgressionTotals { public int HealthBonus { get; } public float MovementMultiplier { get; } public float SprintTimeMultiplier { get; } public float GrabDistanceMultiplier { get; } public ProgressionTotals(int healthBonus, float movementMultiplier, float sprintTimeMultiplier, float grabDistanceMultiplier) { HealthBonus = healthBonus; MovementMultiplier = movementMultiplier; SprintTimeMultiplier = sprintTimeMultiplier; GrabDistanceMultiplier = grabDistanceMultiplier; } } internal readonly struct ProgressionSnapshot { public int AvailablePoints { get; } public int StartingPoints { get; } public bool IsRequestPending { get; } public string LastRejectedReason { get; } public ProgressionSnapshot(int availablePoints, int startingPoints, bool isRequestPending, string lastRejectedReason) { AvailablePoints = availablePoints; StartingPoints = startingPoints; IsRequestPending = isRequestPending; LastRejectedReason = lastRejectedReason; } } internal sealed class ProgressionPlayerState { private readonly HashSet _ownedUpgradeIds = new HashSet(); public ulong ClientId { get; } public int AvailablePoints { get; private set; } public IEnumerable OwnedUpgradeIds => _ownedUpgradeIds; public ProgressionPlayerState(ulong clientId, int availablePoints) { ClientId = clientId; AvailablePoints = availablePoints; } public bool IsOwned(ProgressionUpgradeId upgradeId) { return _ownedUpgradeIds.Contains(upgradeId); } public bool TryPurchase(ProgressionUpgradeId upgradeId, int cost) { if (_ownedUpgradeIds.Contains(upgradeId) || AvailablePoints < cost) { return false; } AvailablePoints -= cost; _ownedUpgradeIds.Add(upgradeId); return true; } public void Reset(int availablePoints) { AvailablePoints = availablePoints; _ownedUpgradeIds.Clear(); } public int ToOwnedMask() { int num = 0; foreach (ProgressionUpgradeId ownedUpgradeId in _ownedUpgradeIds) { num |= 1 << (int)ownedUpgradeId; } return num; } public void ReplaceFromSnapshot(int availablePoints, int ownedMask) { AvailablePoints = availablePoints; _ownedUpgradeIds.Clear(); for (int i = 1; i <= 9; i++) { if ((ownedMask & (1 << i)) != 0) { _ownedUpgradeIds.Add((ProgressionUpgradeId)i); } } } } internal sealed class ProgressionNetworkService { private const string MessageName = "HDM_Progression_v1"; private const int Version = 1; private const int PayloadBytes = 48; private readonly ManualLogSource _logger; private Action? _onHostRequestReceived; private Action? _onSnapshotReceived; private Action? _onRejectReceived; private CustomMessagingManager? _registeredMessagingManager; public string LastMessage { get; private set; } public bool IsListening { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsListening; } } public bool IsHost { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsHost; } } public bool IsServer { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsServer; } } public ulong LocalClientId { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return 0uL; } return singleton.LocalClientId; } } public ProgressionNetworkService(ManualLogSource logger) { _logger = logger; LastMessage = "none"; } public void Initialize(Action onHostRequestReceived, Action onSnapshotReceived, Action onRejectReceived) { _onHostRequestReceived = onHostRequestReceived; _onSnapshotReceived = onSnapshotReceived; _onRejectReceived = onRejectReceived; EnsureRegistered(); } public void Tick() { EnsureRegistered(); } public void Shutdown() { if (_registeredMessagingManager != null) { _registeredMessagingManager.UnregisterNamedMessageHandler("HDM_Progression_v1"); _registeredMessagingManager = null; } _onHostRequestReceived = null; _onSnapshotReceived = null; _onRejectReceived = null; } public bool TrySendPurchaseRequest(ProgressionUpgradeId upgradeId) { return TrySendRequest(ProgressionNetworkMessageKind.PurchaseRequest, upgradeId); } public bool TrySendResetRequest() { return TrySendRequest(ProgressionNetworkMessageKind.ResetRequest, ProgressionUpgradeId.None); } public bool TrySendStateRequest() { return TrySendRequest(ProgressionNetworkMessageKind.RequestState, ProgressionUpgradeId.None); } public bool TrySendSnapshot(ulong targetClientId, ProgressionPlayerState state) { NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null || !singleton.IsListening) { LastMessage = "snapshot blocked: network unavailable"; return false; } if (targetClientId == singleton.LocalClientId) { return false; } EnsureRegistered(); return TrySend(singleton, targetClientId, ProgressionNetworkMessageKind.StateSnapshot, ProgressionUpgradeId.None, state.ClientId, state.AvailablePoints, state.ToOwnedMask(), ProgressionRejectReason.None); } public bool TrySendReject(ulong targetClientId, ProgressionUpgradeId upgradeId, ProgressionRejectReason reason) { NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null || !singleton.IsListening) { LastMessage = "reject blocked: network unavailable"; return false; } if (targetClientId == singleton.LocalClientId) { return false; } EnsureRegistered(); return TrySend(singleton, targetClientId, ProgressionNetworkMessageKind.PurchaseRejected, upgradeId, targetClientId, 0, 0, reason); } public string DescribeRole() { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return "network=null"; } return $"listening={singleton.IsListening}, host={singleton.IsHost}, server={singleton.IsServer}, client={singleton.IsClient}, localClient={singleton.LocalClientId}"; } private bool TrySendRequest(ProgressionNetworkMessageKind kind, ProgressionUpgradeId upgradeId) { NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null || !singleton.IsListening) { LastMessage = $"{kind} blocked: network unavailable"; return false; } EnsureRegistered(); return TrySend(singleton, 0uL, kind, upgradeId, singleton.LocalClientId, 0, 0, ProgressionRejectReason.None); } private unsafe bool TrySend(NetworkManager networkManager, ulong clientId, ProgressionNetworkMessageKind kind, ProgressionUpgradeId upgradeId, ulong targetClientId, int availablePoints, int ownedMask, ProgressionRejectReason rejectReason) { //IL_000b: 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) try { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(48, (Allocator)2, -1); try { WritePayload(val, kind, upgradeId, targetClientId, availablePoints, ownedMask, rejectReason); networkManager.CustomMessagingManager.SendNamedMessage("HDM_Progression_v1", clientId, val, (NetworkDelivery)3); LastMessage = $"sent {kind}: to={clientId}, target={targetClientId}, upgrade={upgradeId}, points={availablePoints}, mask={ownedMask}, reason={rejectReason}"; _logger.LogInfo((object)("[HDM:ProgressionNet] " + LastMessage + ".")); return true; } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception ex) { LastMessage = $"send failed {kind}: {ex.GetType().Name}: {ex.Message}"; _logger.LogWarning((object)("[HDM:ProgressionNet] " + LastMessage)); return false; } } private void EnsureRegistered() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val != null && val != _registeredMessagingManager) { if (_registeredMessagingManager != null) { _registeredMessagingManager.UnregisterNamedMessageHandler("HDM_Progression_v1"); } val.RegisterNamedMessageHandler("HDM_Progression_v1", new HandleNamedMessageDelegate(OnNamedMessage)); _registeredMessagingManager = val; _logger.LogInfo((object)"[HDM:ProgressionNet] Registered progression named message handler."); } } private void OnNamedMessage(ulong senderClientId, FastBufferReader reader) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { ReadPayload(reader, out var kind, out var upgradeId, out var targetClientId, out var availablePoints, out var ownedMask, out var rejectReason); LastMessage = $"received {kind}: sender={senderClientId}, target={targetClientId}, upgrade={upgradeId}, points={availablePoints}, mask={ownedMask}, reason={rejectReason}"; _logger.LogInfo((object)("[HDM:ProgressionNet] " + LastMessage + ".")); switch (kind) { case ProgressionNetworkMessageKind.PurchaseRequest: case ProgressionNetworkMessageKind.ResetRequest: case ProgressionNetworkMessageKind.RequestState: _onHostRequestReceived?.Invoke(senderClientId, kind, upgradeId); break; case ProgressionNetworkMessageKind.StateSnapshot: _onSnapshotReceived?.Invoke(new ProgressionNetworkSnapshot(targetClientId, availablePoints, ownedMask)); break; case ProgressionNetworkMessageKind.PurchaseRejected: _onRejectReceived?.Invoke(new ProgressionNetworkReject(targetClientId, upgradeId, rejectReason)); break; } } catch (Exception ex) { LastMessage = "receive failed: " + ex.GetType().Name + ": " + ex.Message; _logger.LogWarning((object)("[HDM:ProgressionNet] " + LastMessage)); } } private static void WritePayload(FastBufferWriter writer, ProgressionNetworkMessageKind kind, ProgressionUpgradeId upgradeId, ulong targetClientId, int availablePoints, int ownedMask, ProgressionRejectReason rejectReason) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0030: 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_0042: 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_005a: 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_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) int num = 1; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref num, default(ForPrimitives)); num = (int)kind; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref num, default(ForPrimitives)); num = (int)upgradeId; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref targetClientId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref availablePoints, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ownedMask, default(ForPrimitives)); num = (int)rejectReason; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref num, default(ForPrimitives)); } private static void ReadPayload(FastBufferReader reader, out ProgressionNetworkMessageKind kind, out ProgressionUpgradeId upgradeId, out ulong targetClientId, out int availablePoints, out int ownedMask, out ProgressionRejectReason rejectReason) { //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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0091: 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) int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); if (num != 1) { throw new InvalidOperationException($"Unsupported progression payload version {num}."); } int num2 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); int num3 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref targetClientId, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref availablePoints, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref ownedMask, default(ForPrimitives)); int num4 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num4, default(ForPrimitives)); kind = (ProgressionNetworkMessageKind)num2; upgradeId = (ProgressionUpgradeId)num3; rejectReason = (ProgressionRejectReason)num4; } } internal sealed class ProgressionRuntime : MonoBehaviour { private ProgressionService? _service; public void Initialize(ProgressionService service) { _service = service; } private void Update() { if (_service != null) { _service.HandleUiKeyInput("runtime"); } } } internal sealed class ProgressionService { private readonly ManualLogSource _logger; private readonly ConfigService _config; private readonly GameplayInputService _gameplayInput; private readonly ProgressionNetworkService _network; private readonly ModifierRegistry _modifierRegistry; private readonly PlayerStatApplier _statApplier; private readonly Dictionary _states = new Dictionary(); private readonly Dictionary _hostAliveByClientId = new Dictionary(); private ProgressionRuntime? _runtime; private ProgressionUiController? _ui; private GameObject? _runtimeHost; private bool? _wasLocalPlayerAlive; private ulong? _observedPlayerId; private ulong? _requestedStateClientId; private bool _localRequestPending; private string _lastRejectedReason = string.Empty; private int _lastOpenKeyFrame = -1; private int _lastCloseKeyFrame = -1; public IReadOnlyList Upgrades => (from modifier in _modifierRegistry.GetAvailable(EffectTargetKind.Player) select modifier.ToUpgradeDefinition()).ToArray(); internal KeyCode OpenKey => _config.ProgressionOpenKey; public event Action? StateChanged; public ProgressionService(ManualLogSource logger, ConfigService config, GameplayInputService gameplayInput, ProgressionNetworkService network, ModifierRegistry modifierRegistry) { _logger = logger; _config = config; _gameplayInput = gameplayInput; _network = network; _modifierRegistry = modifierRegistry; _statApplier = new PlayerStatApplier(logger); } public void Initialize() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown if (!_config.ProgressionEnabled) { _logger.LogInfo((object)"[HDM:Progression] Progression prototype disabled by config."); return; } _network.Initialize(OnHostRequestReceived, OnSnapshotReceived, OnRejectReceived); _runtimeHost = new GameObject("HDM_ProgressionRuntime"); Object.DontDestroyOnLoad((Object)(object)_runtimeHost); _runtime = _runtimeHost.AddComponent(); _runtime.Initialize(this); _logger.LogInfo((object)"[HDM:Progression] Runtime initialized with host-authoritative networking."); } public void Shutdown() { CloseUi("shutdown"); _ui?.Destroy(); _ui = null; if (_runtimeHost != null) { Object.Destroy((Object)(object)_runtimeHost); _runtimeHost = null; _runtime = null; } _network.Shutdown(); _statApplier.ForgetPlayer(); _states.Clear(); _hostAliveByClientId.Clear(); } public void Tick(StartOfRound round, float deltaTime) { if (!_config.ProgressionEnabled) { return; } _network.Tick(); HandleUiKeyInput("lifecycle"); if (IsHostAuthority()) { TickHostPlayerStates(round); } PlayerControllerB val = ResolveLocalPlayer(round); if (val == null || !val.isPlayerControlled) { _wasLocalPlayerAlive = null; _observedPlayerId = null; _statApplier.ForgetPlayer(); return; } ulong localClientId = GetLocalClientId(val); EnsureLocalStateRequested(localClientId); if (_observedPlayerId != val.playerClientId) { _observedPlayerId = val.playerClientId; _wasLocalPlayerAlive = !val.isPlayerDead; _statApplier.ForgetPlayer(); _logger.LogInfo((object)$"[HDM:Progression] Observing local player {val.playerClientId}; clientId={localClientId}."); } bool flag = !val.isPlayerDead; if (_wasLocalPlayerAlive == true && !flag) { if (_config.ProgressionResetRunProgressOnDeath) { if (IsHostAuthority()) { ResetRunForClient(localClientId, "local death", notifyClient: true); } else { RequestResetRun("local death"); } } CloseUi("death"); } _wasLocalPlayerAlive = flag; if (flag) { ApplyLocalStateToPlayer(val, "tick"); } } public void ToggleUi() { if (!_config.ProgressionEnabled) { return; } ProgressionUiController ui = _ui; if (ui != null && ui.IsOpen) { CloseUi("toggle"); return; } PlayerControllerB player = ResolveLocalPlayer(Object.FindObjectOfType()); if (!CanOpenUi(player, out string reason)) { _logger.LogInfo((object)("[HDM:Progression] Progression UI blocked: " + reason + ".")); return; } if (_ui == null) { _ui = new ProgressionUiController(_logger, this, _gameplayInput); } _ui.Open(player); _logger.LogInfo((object)"[HDM:Progression] Progression UI opened."); } public void OnOpenKeyPressed() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) _logger.LogInfo((object)$"[HDM:Progression] Open key pressed: key={_config.ProgressionOpenKey}."); ToggleUi(); } public void HandleUiKeyInput(string source) { ProgressionUiController ui = _ui; if (ui == null || !ui.IsOpen || !HandleCloseKeyInput(source)) { HandleOpenKeyInput(source); } } public void HandleOpenKeyInput(string source) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (Time.frameCount != _lastOpenKeyFrame && WasOpenKeyPressed()) { _lastOpenKeyFrame = Time.frameCount; _logger.LogInfo((object)$"[HDM:Progression] Open key input detected: key={_config.ProgressionOpenKey}, source={source}."); ToggleUi(); } } public void CloseUi(string reason) { if (_ui != null && _ui.IsOpen) { _ui.Close(reason); _logger.LogInfo((object)("[HDM:Progression] Progression UI closed: reason='" + reason + "'.")); } } public bool TryPurchaseUpgrade(string upgradeId) { return RequestPurchaseForLocalPlayer(upgradeId); } public bool RequestPurchaseForLocalPlayer(string upgradeId) { UpgradeDefinition upgradeDefinition = FindUpgrade(upgradeId); if (upgradeDefinition == null) { _lastRejectedReason = "unknown upgrade " + upgradeId; _logger.LogWarning((object)("[HDM:Progression] Purchase request failed: unknown upgrade '" + upgradeId + "'.")); NotifyStateChanged(); return false; } return RequestPurchaseForLocalPlayer(upgradeDefinition.NetworkId); } public bool RequestPurchaseForLocalPlayer(ProgressionUpgradeId upgradeId) { if (_localRequestPending) { _logger.LogInfo((object)$"[HDM:Progression] Purchase request ignored while pending: upgrade={upgradeId}."); return false; } _lastRejectedReason = string.Empty; if (IsHostAuthority()) { ulong localClientId = GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType())); return ApplyPurchase(localClientId, upgradeId); } if (!_network.TrySendPurchaseRequest(upgradeId)) { _lastRejectedReason = ProgressionRejectReason.NetworkUnavailable.ToString(); _logger.LogInfo((object)$"[HDM:Progression] Purchase request blocked: upgrade={upgradeId}, reason=network unavailable."); NotifyStateChanged(); return false; } _localRequestPending = true; _logger.LogInfo((object)$"[HDM:Progression] Sent purchase request: upgrade={upgradeId}, role={_network.DescribeRole()}."); NotifyStateChanged(); return true; } public bool ApplyPurchase(ulong clientId, ProgressionUpgradeId upgradeId) { if (!IsHostAuthority()) { Reject(clientId, upgradeId, ProgressionRejectReason.NotHost); return false; } UpgradeDefinition upgradeDefinition = FindUpgrade(upgradeId); if (upgradeDefinition == null) { Reject(clientId, upgradeId, ProgressionRejectReason.UnknownUpgrade); return false; } if (!upgradeDefinition.Available) { Reject(clientId, upgradeId, ProgressionRejectReason.Unavailable); return false; } ProgressionPlayerState progressionPlayerState = EnsureState(clientId); if (progressionPlayerState.IsOwned(upgradeId)) { Reject(clientId, upgradeId, ProgressionRejectReason.AlreadyOwned); return false; } if (!progressionPlayerState.TryPurchase(upgradeId, upgradeDefinition.Cost)) { Reject(clientId, upgradeId, ProgressionRejectReason.NotEnoughPoints); return false; } _logger.LogInfo((object)$"[HDM:Progression] Host accepted purchase: client={clientId}, upgrade={upgradeId}, points={progressionPlayerState.AvailablePoints}."); SyncStateToClient(clientId, "purchase"); return true; } public void ResetRunProgress(string reason) { if (IsHostAuthority()) { ResetRunForClient(GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType())), reason, notifyClient: true); } else { RequestResetRun(reason); } } public void LogStatus(string reason) { ulong localClientId = GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType())); ProgressionPlayerState stateOrDefault = GetStateOrDefault(localClientId); string[] value = stateOrDefault.OwnedUpgradeIds.Select((ProgressionUpgradeId upgradeId) => upgradeId.ToString()).ToArray(); PlayerControllerB val = ResolveLocalPlayer(Object.FindObjectOfType()); string text = ((val == null) ? "none" : $"id={val.playerClientId}, controlled={val.isPlayerControlled}, dead={val.isPlayerDead}, health={val.health}, move={val.movementSpeed:0.00}, sprintTime={val.sprintTime:0.00}, grab={val.grabDistance:0.00}"); _logger.LogInfo((object)string.Format("[HDM:Progression] Status: reason='{0}', role={1}, localClient={2}, points={3}/{4}, owned=[{5}], pending={6}, rejected='{7}', player={8}.", reason, _network.DescribeRole(), localClientId, stateOrDefault.AvailablePoints, _config.ProgressionDevStartingPoints, string.Join(",", value), _localRequestPending, _lastRejectedReason, text)); } public void LogSyncStatus(string reason) { string[] value = (from state in _states.Values orderby state.ClientId select $"{state.ClientId}:points={state.AvailablePoints},mask={state.ToOwnedMask()}").ToArray(); _logger.LogInfo((object)string.Format("[HDM:Progression] SyncStatus: reason='{0}', role={1}, states=[{2}], pending={3}, lastNetwork='{4}'.", reason, _network.DescribeRole(), string.Join("; ", value), _localRequestPending, _network.LastMessage)); } public ProgressionSnapshot CreateSnapshot() { return new ProgressionSnapshot(GetStateOrDefault(GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType()))).AvailablePoints, _config.ProgressionDevStartingPoints, _localRequestPending, _lastRejectedReason); } public bool IsOwned(string upgradeId) { UpgradeDefinition upgradeDefinition = FindUpgrade(upgradeId); if (upgradeDefinition != null) { return IsOwned(upgradeDefinition.NetworkId); } return false; } public bool IsOwned(ProgressionUpgradeId upgradeId) { return GetStateOrDefault(GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType()))).IsOwned(upgradeId); } public int GetRank(string upgradeId) { return IsOwned(upgradeId) ? 1 : 0; } private void OnHostRequestReceived(ulong senderClientId, ProgressionNetworkMessageKind kind, ProgressionUpgradeId upgradeId) { if (!IsHostAuthority()) { _logger.LogInfo((object)$"[HDM:Progression] Ignored host request on non-host: sender={senderClientId}, kind={kind}."); return; } _logger.LogInfo((object)$"[HDM:Progression] Host received request: sender={senderClientId}, kind={kind}, upgrade={upgradeId}."); switch (kind) { case ProgressionNetworkMessageKind.PurchaseRequest: ApplyPurchase(senderClientId, upgradeId); break; case ProgressionNetworkMessageKind.ResetRequest: ResetRunForClient(senderClientId, "network reset request", notifyClient: true); break; case ProgressionNetworkMessageKind.RequestState: SyncStateToClient(senderClientId, "network state request"); break; } } private void OnSnapshotReceived(ProgressionNetworkSnapshot snapshot) { ulong localClientId = GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType())); if (snapshot.TargetClientId != localClientId) { _logger.LogInfo((object)$"[HDM:Progression] Ignored snapshot for another client: target={snapshot.TargetClientId}, local={localClientId}."); return; } EnsureState(snapshot.TargetClientId).ReplaceFromSnapshot(snapshot.AvailablePoints, snapshot.OwnedMask); _localRequestPending = false; _lastRejectedReason = string.Empty; _logger.LogInfo((object)$"[HDM:Progression] Applied host snapshot: client={snapshot.TargetClientId}, points={snapshot.AvailablePoints}, mask={snapshot.OwnedMask}."); ApplyLocalStateToCurrentPlayer("snapshot"); NotifyStateChanged(); } private void OnRejectReceived(ProgressionNetworkReject reject) { ulong localClientId = GetLocalClientId(ResolveLocalPlayer(Object.FindObjectOfType())); if (reject.TargetClientId == localClientId) { _localRequestPending = false; _lastRejectedReason = reject.Reason.ToString(); _logger.LogInfo((object)$"[HDM:Progression] Host rejected request: upgrade={reject.UpgradeId}, reason={reject.Reason}."); NotifyStateChanged(); } } private void TickHostPlayerStates(StartOfRound round) { if (round.allPlayerScripts == null) { return; } PlayerControllerB[] allPlayerScripts = round.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val != null && val.isPlayerControlled) { ulong playerClientId = val.playerClientId; EnsureState(playerClientId); bool flag = !val.isPlayerDead; if (_hostAliveByClientId.TryGetValue(playerClientId, out var value) && value && !flag && _config.ProgressionResetRunProgressOnDeath) { ResetRunForClient(playerClientId, "host observed death", notifyClient: true); } _hostAliveByClientId[playerClientId] = flag; } } } private void EnsureLocalStateRequested(ulong localClientId) { if (IsHostAuthority() || !_network.IsListening) { EnsureState(localClientId); } else if (_requestedStateClientId != localClientId && !_localRequestPending && _network.TrySendStateRequest()) { _requestedStateClientId = localClientId; _localRequestPending = true; _logger.LogInfo((object)$"[HDM:Progression] Requested host progression state: client={localClientId}."); NotifyStateChanged(); } } private void RequestResetRun(string reason) { if (!_localRequestPending) { _lastRejectedReason = string.Empty; if (!_network.TrySendResetRequest()) { _lastRejectedReason = ProgressionRejectReason.NetworkUnavailable.ToString(); _logger.LogInfo((object)("[HDM:Progression] Reset request blocked: reason='" + reason + "', network unavailable.")); NotifyStateChanged(); } else { _localRequestPending = true; _logger.LogInfo((object)("[HDM:Progression] Sent reset request: reason='" + reason + "'.")); NotifyStateChanged(); } } } private void ResetRunForClient(ulong clientId, string reason, bool notifyClient) { EnsureState(clientId).Reset(_config.ProgressionDevStartingPoints); _logger.LogInfo((object)$"[HDM:Progression] Host reset run progression: client={clientId}, reason='{reason}'."); if (notifyClient) { SyncStateToClient(clientId, reason); } } private void SyncStateToClient(ulong clientId, string reason) { ProgressionPlayerState state = EnsureState(clientId); if (clientId == _network.LocalClientId || !_network.IsListening) { _localRequestPending = false; _lastRejectedReason = string.Empty; ApplyLocalStateToCurrentPlayer("host local " + reason); NotifyStateChanged(); } else { _network.TrySendSnapshot(clientId, state); } } private void Reject(ulong clientId, ProgressionUpgradeId upgradeId, ProgressionRejectReason reason) { _logger.LogInfo((object)$"[HDM:Progression] Host rejected purchase: client={clientId}, upgrade={upgradeId}, reason={reason}."); if (clientId == _network.LocalClientId || !_network.IsListening) { _localRequestPending = false; _lastRejectedReason = reason.ToString(); NotifyStateChanged(); } else { _network.TrySendReject(clientId, upgradeId, reason); } } private void ApplyLocalStateToCurrentPlayer(string reason) { PlayerControllerB val = ResolveLocalPlayer(Object.FindObjectOfType()); if (val != null) { ApplyLocalStateToPlayer(val, reason); } } private void ApplyLocalStateToPlayer(PlayerControllerB player, string reason) { ProgressionPlayerState stateOrDefault = GetStateOrDefault(GetLocalClientId(player)); if (!stateOrDefault.OwnedUpgradeIds.Any()) { _statApplier.Restore(player, reason); } else { _statApplier.Apply(player, CalculateTotals(stateOrDefault), reason); } } private ProgressionPlayerState EnsureState(ulong clientId) { if (_states.TryGetValue(clientId, out ProgressionPlayerState value)) { return value; } value = new ProgressionPlayerState(clientId, _config.ProgressionDevStartingPoints); _states[clientId] = value; _logger.LogInfo((object)$"[HDM:Progression] Created session progression state: client={clientId}, points={value.AvailablePoints}."); return value; } private ProgressionPlayerState GetStateOrDefault(ulong clientId) { if (!_states.TryGetValue(clientId, out ProgressionPlayerState value)) { return new ProgressionPlayerState(clientId, _config.ProgressionDevStartingPoints); } return value; } private bool IsHostAuthority() { if (_network.IsListening && !_network.IsServer) { return _network.IsHost; } return true; } private ulong GetLocalClientId(PlayerControllerB? player) { if (_network.IsListening) { return _network.LocalClientId; } return player?.playerClientId ?? 0; } private bool HandleCloseKeyInput(string source) { if (Time.frameCount == _lastCloseKeyFrame || !WasCloseKeyPressed(out string keyName)) { return false; } _lastCloseKeyFrame = Time.frameCount; _logger.LogInfo((object)("[HDM:Progression] Close key input detected: key=" + keyName + ", source=" + source + ".")); CloseUi("key " + keyName); return true; } private bool WasOpenKeyPressed() { if (!WasOpenKeyPressedByInputSystem()) { return WasOpenKeyPressedByLegacyInput(); } return true; } private bool WasCloseKeyPressed(out string keyName) { if (WasCloseKeyPressedByInputSystem(out keyName)) { return true; } if (WasCloseKeyPressedByLegacyInput(out keyName)) { return true; } keyName = string.Empty; return false; } private bool WasOpenKeyPressedByInputSystem() { //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_001a: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //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_008b: Unknown result type (might be due to invalid IL or missing references) Keyboard current = Keyboard.current; if (current == null) { return false; } KeyCode progressionOpenKey = _config.ProgressionOpenKey; if ((int)progressionOpenKey <= 111) { if ((int)progressionOpenKey == 96) { return ((ButtonControl)current.backquoteKey).wasPressedThisFrame; } if ((int)progressionOpenKey == 111) { return ((ButtonControl)current.oKey).wasPressedThisFrame; } } else { if ((int)progressionOpenKey == 112) { return ((ButtonControl)current.pKey).wasPressedThisFrame; } if ((int)progressionOpenKey == 287) { return ((ButtonControl)current.f6Key).wasPressedThisFrame; } } if (Enum.TryParse(((object)_config.ProgressionOpenKey/*cast due to .constrained prefix*/).ToString(), ignoreCase: true, out Key result)) { return ((ButtonControl)current[result]).wasPressedThisFrame; } return false; } private bool WasOpenKeyPressedByLegacyInput() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) try { return Input.GetKeyDown(_config.ProgressionOpenKey); } catch { return false; } } private static bool WasCloseKeyPressedByInputSystem(out string keyName) { Keyboard current = Keyboard.current; if (current == null) { keyName = string.Empty; return false; } if (((ButtonControl)current.escapeKey).wasPressedThisFrame) { keyName = "Escape"; return true; } if (((ButtonControl)current.tabKey).wasPressedThisFrame) { keyName = "Tab"; return true; } keyName = string.Empty; return false; } private static bool WasCloseKeyPressedByLegacyInput(out string keyName) { try { if (Input.GetKeyDown((KeyCode)27)) { keyName = "Escape"; return true; } if (Input.GetKeyDown((KeyCode)9)) { keyName = "Tab"; return true; } } catch { } keyName = string.Empty; return false; } private ProgressionTotals CalculateTotals(ProgressionPlayerState state) { int num = 0; float num2 = 1f; float num3 = 1f; float num4 = 1f; foreach (ModifierDefinition item in _modifierRegistry.GetAvailable(EffectTargetKind.Player)) { if (state.IsOwned(item.NetworkId)) { switch (item.EffectKind) { case ProgressionEffectKind.HealthBonus: num += Mathf.RoundToInt(item.EffectValue); break; case ProgressionEffectKind.MovementMultiplier: num2 *= item.EffectValue; break; case ProgressionEffectKind.SprintTimeMultiplier: num3 *= item.EffectValue; break; case ProgressionEffectKind.GrabDistanceMultiplier: num4 *= item.EffectValue; break; } } } return new ProgressionTotals(num, num2, num3, num4); } private bool CanOpenUi(PlayerControllerB? player, out string reason) { if (player == null || !player.isPlayerControlled) { reason = "no controlled local player"; return false; } if (player.isPlayerDead) { reason = "player is dead"; return false; } if (player.inTerminalMenu) { reason = "terminal menu is open"; return false; } if (player.inSpecialMenu) { reason = "special menu is open"; return false; } if (player.quickMenuManager != null && player.quickMenuManager.isMenuOpen) { reason = "quick menu is open"; return false; } reason = string.Empty; return true; } private UpgradeDefinition? FindUpgrade(string upgradeId) { return _modifierRegistry.FindAvailableById(upgradeId)?.ToUpgradeDefinition(); } private UpgradeDefinition? FindUpgrade(ProgressionUpgradeId upgradeId) { return _modifierRegistry.FindAvailableByNetworkId(upgradeId)?.ToUpgradeDefinition(); } private static PlayerControllerB? ResolveLocalPlayer(StartOfRound? round) { object obj = round?.localPlayerController; if (obj == null) { GameNetworkManager instance = GameNetworkManager.Instance; if (instance == null) { return null; } obj = instance.localPlayerController; } return (PlayerControllerB?)obj; } private void NotifyStateChanged() { this.StateChanged?.Invoke(); } } internal sealed class ProgressionUiController { private sealed class UpgradeButtonBinding { public UpgradeDefinition Upgrade { get; } public Button Button { get; } public Image Background { get; } public Text Status { get; } public UpgradeButtonBinding(UpgradeDefinition upgrade, Button button, Image background, Text status) { Upgrade = upgrade; Button = button; Background = background; Status = status; } } private readonly ManualLogSource _logger; private readonly ProgressionService _service; private readonly GameplayInputService _gameplayInput; private readonly List _buttons = new List(); private GameObject? _root; private Text? _pointsText; private PlayerControllerB? _owningPlayer; private bool _subscribed; public bool IsOpen { get { if (_root != null) { return _root.activeSelf; } return false; } } public ProgressionUiController(ManualLogSource logger, ProgressionService service, GameplayInputService gameplayInput) { _logger = logger; _service = service; _gameplayInput = gameplayInput; } public void Open(PlayerControllerB player) { EnsureUi(); _owningPlayer = player; if (!_subscribed) { _service.StateChanged += Refresh; _subscribed = true; } _root.SetActive(true); _gameplayInput.LockUi(player, "progression"); Refresh(); } public void Close(string reason) { if (_root != null) { _root.SetActive(false); } _gameplayInput.UnlockUi("progression"); _owningPlayer = null; } public void Destroy() { if (_subscribed) { _service.StateChanged -= Refresh; _subscribed = false; } if (_root != null) { Object.Destroy((Object)(object)_root); _root = null; } _buttons.Clear(); _pointsText = null; _owningPlayer = null; } private void EnsureUi() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0062: 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_00de: 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_010f: 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_0139: 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_0160: 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_019c: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) if (_root == null) { EnsureEventSystem(); _root = new GameObject("HDM_ProgressionCanvas"); Object.DontDestroyOnLoad((Object)(object)_root); Canvas obj = _root.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 6500; CanvasScaler obj2 = _root.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1280f, 720f); obj2.matchWidthOrHeight = 0.5f; _root.AddComponent(); Stretch(CreatePanel(_root.transform, "Dim", new Color(0f, 0f, 0f, 0.78f)).GetComponent()); GameObject val = CreatePanel(_root.transform, "Tree", new Color(0.07f, 0.08f, 0.09f, 0.96f)); RectTransform component = val.GetComponent(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.sizeDelta = new Vector2(980f, 560f); component.anchoredPosition = Vector2.zero; Place(((Graphic)CreateText(val.transform, "Title", "HDM RUN TRAINING", 28, (TextAnchor)3, Color.white)).rectTransform, 28f, -24f, 480f, 42f, new Vector2(0f, 1f), new Vector2(0f, 1f)); _pointsText = CreateText(val.transform, "Points", string.Empty, 18, (TextAnchor)5, new Color(0.8f, 0.95f, 1f, 1f)); Place(((Graphic)_pointsText).rectTransform, -210f, -26f, 170f, 34f, new Vector2(1f, 1f), new Vector2(1f, 1f)); CreateActionButton(val.transform, "Close", "X", new Vector2(-44f, -28f), new Vector2(34f, 34f), delegate { _service.CloseUi("button"); }); CreateActionButton(val.transform, "Reset", "Reset Run", new Vector2(-132f, -514f), new Vector2(134f, 38f), delegate { _service.ResetRunProgress("ui reset"); }); CreateBranch(val.transform, "Grit", 28f); CreateBranch(val.transform, "Legs", 340f); CreateBranch(val.transform, "Utility", 652f); _root.SetActive(false); _logger.LogInfo((object)"[HDM:Progression] Progression UI created."); } } private void CreateBranch(Transform parent, string branch, float x) { //IL_0040: 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_0078: 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) Place(((Graphic)CreateText(parent, branch + "_Header", branch.ToUpperInvariant(), 20, (TextAnchor)4, new Color(1f, 0.86f, 0.54f, 1f))).rectTransform, x, -92f, 280f, 34f, new Vector2(0f, 1f), new Vector2(0f, 1f)); UpgradeDefinition[] array = _service.Upgrades.Where((UpgradeDefinition upgrade) => upgrade.Branch.Equals(branch, StringComparison.OrdinalIgnoreCase)).ToArray(); for (int num = 0; num < array.Length; num++) { CreateUpgradeButton(parent, array[num], new Vector2(x, -140f - (float)num * 128f)); } } private void CreateUpgradeButton(Transform parent, UpgradeDefinition upgrade, Vector2 position) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00b8: Expected O, but got Unknown //IL_00d1: 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_010d: 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_0171: 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_01b1: 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_01ef: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreatePanel(parent, "Upgrade_" + upgrade.Id, new Color(0.15f, 0.17f, 0.18f, 1f)); Place(val.GetComponent(), position.x, position.y, 280f, 104f, new Vector2(0f, 1f), new Vector2(0f, 1f)); Button val2 = val.AddComponent