Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of GhostBuild v1.0.2
GhostBuild.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GhostBuild.Cloning; using GhostBuild.Extensions; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using SoftReferenceableAssets; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; using Valheim.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("GhostBuild")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Azumatt")] [assembly: AssemblyProduct("GhostBuild")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.0.2")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { public ExtensionMarkerAttribute(string name) { } } } namespace GhostBuild { public class GhostBuildPiece : MonoBehaviour, Hoverable, Interactable { public Piece m_piece; public Piece OriginalPiece; private ZNetView m_nView; internal WearNTear m_wearNTear; public float m_holdRepeatInterval = 0.2f; private float m_lastLookedTime = -9999f; private float m_lastUseTime = -9999f; private bool m_confirmed; internal void MarkConfirmed() { m_confirmed = true; } public void OnDestroy() { RefundIfNotConfirmed(); } internal void RefundIfNotConfirmed() { if (!m_confirmed && Object.op_Implicit((Object)(object)m_nView) && m_nView.IsValid() && m_nView.IsOwner()) { m_confirmed = true; RefundStoredResources(); } } private void RefundStoredResources() { //IL_00c3: 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) if (!Object.op_Implicit((Object)(object)OriginalPiece) || OriginalPiece.m_resources == null) { return; } Requirement[] resources = OriginalPiece.m_resources; foreach (Requirement val in resources) { if (!Object.op_Implicit((Object)(object)val.m_resItem)) { continue; } string name = val.m_resItem.m_itemData.m_shared.m_name; int storedResourceCount = GetStoredResourceCount(name); if (storedResourceCount > 0) { ItemData val2 = val.m_resItem.m_itemData.Clone(); val2.m_dropPrefab = ((Component)val.m_resItem).gameObject; val2.m_stack = storedResourceCount; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !((Humanoid)localPlayer).GetInventory().AddItem(val2)) { ItemDrop.DropItem(val2, val2.m_stack, ((Component)this).transform.position, ((Component)this).transform.rotation); } } } } public void Awake() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown m_wearNTear = ((Component)this).GetComponent<WearNTear>(); m_nView = ((Component)this).GetComponent<ZNetView>(); m_piece = ((Component)this).GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)m_piece)) { m_piece.m_canBeRemoved = true; m_piece.m_comfort = 0; ((StaticTarget)m_piece).m_randomTarget = false; ((StaticTarget)m_piece).m_primaryTarget = false; } if (Object.op_Implicit((Object)(object)m_wearNTear)) { m_wearNTear.m_noSupportWear = true; m_wearNTear.m_noRoofWear = false; m_wearNTear.m_supports = true; m_wearNTear.m_hitEffect = new EffectList(); m_wearNTear.m_hitNoise = 0f; m_wearNTear.m_destroyedEffect = new EffectList(); m_wearNTear.m_destroyNoise = 0f; } if (!Object.op_Implicit((Object)(object)OriginalPiece) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.GetPrefab(((Object)((Component)m_piece).gameObject).name.Replace("(Clone)", "")); } } public string GetHoverText() { if (Time.time - m_lastLookedTime > 0.0002f) { m_lastLookedTime = Time.time; if (GhostBuildPlugin.GhostModeExplicit.Value.IsOff() || (GhostBuildPlugin.GhostModeExplicit.Value.IsOn() && GhostBuildManager.IsGhostActive)) { SetupPieceInfo(m_piece); } } if (GhostBuildPlugin.GhostModeExplicit.Value.IsOff() || (GhostBuildPlugin.GhostModeExplicit.Value.IsOn() && GhostBuildManager.IsGhostActive)) { GhostBuildManager.ghostPieceInformation.SetActive((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Player.m_localPlayer.m_placementGhost == (Object)null && !Hud.IsPieceSelectionVisible()); } bool num = Player.m_localPlayer.HaveRequirements(OriginalPiece, (RequirementMode)0); bool flag = HasAllResources(); string text = ((!(num || flag)) ? "[<color=yellow>$KEY_Use</color>] Add Resource\n[Hold <color=yellow>$KEY_Use</color>] Add All Resources" : "[<color=yellow>$KEY_Use</color>] $hud_build"); GhostBuildManager.m_pieceDescription.text = GetHoverName() + " \n" + Localization.instance.Localize(text); return ""; } public string GetHoverName() { return Localization.instance.Localize("$enemy_ghost " + m_piece.m_name); } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_01b2: 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_0098: Unknown result type (might be due to invalid IL or missing references) Player val = (Player)(object)((user is Player) ? user : null); if (val == null) { return false; } if (!m_nView.IsOwner() || !m_nView.HasOwner()) { m_nView.ClaimOwnership(); } bool isGhostActive = GhostBuildManager.IsGhostActive; bool suppressTagging = GhostBuildManager.SuppressTagging; GhostBuildManager.IsGhostActive = false; GhostBuildManager.SuppressTagging = true; bool flag = val.NoCostCheat(); bool flag2 = val.HaveRequirements(OriginalPiece, (RequirementMode)0); bool flag3 = HasAllResources(); if (flag || flag2 || flag3) { if (!GhostBuildManager.TryResolveRealPrefab(this, out Piece realPrefab)) { return false; } GhostBuildManager.UnregisterGhost(m_piece); if (!flag && !ZoneSystem.instance.GetGlobalKey(m_piece.FreeBuildKey())) { ConsumeRemainingResources(val); } val.PlacePiece(realPrefab, ((Component)m_piece).transform.position, ((Component)m_piece).transform.rotation, false, false); MarkConfirmed(); ZNetScene.instance.Destroy(((Component)this).gameObject); GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; ZLog.Log((object)("Placed " + ((Object)realPrefab).name)); Gogan.LogEvent("Game", "PlacedPiece", ((Object)realPrefab).name, 0L); Game.instance.IncrementPlayerStat((PlayerStatType)2, 1f, false); return true; } if (hold) { if (Time.time - m_lastUseTime < m_holdRepeatInterval) { return false; } m_lastUseTime = Time.time; bool num = TryAddAllResources(val); if (num && HasAllResources()) { ((Character)user).Message((MessageType)2, "$msg_canplace", 0, (Sprite)null, false); } GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return num; } if (Object.op_Implicit((Object)(object)OriginalPiece.m_craftingStation) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(OriginalPiece.m_craftingStation.m_name, ((Component)user).transform.position)) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27)) { ((Character)user).Message((MessageType)2, "$msg_missingstation", 0, (Sprite)null, false); GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return false; } if (!flag2 && OriginalPiece.m_resources != null && OriginalPiece.m_resources.Length != 0) { bool flag4 = false; Requirement[] resources = OriginalPiece.m_resources; foreach (Requirement requirement in resources) { if (TryAddResource(val, requirement)) { flag4 = true; break; } } if (flag4) { if (HasAllResources()) { ((Character)user).Message((MessageType)2, "$msg_canplace", 0, (Sprite)null, false); } GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return true; } ((Character)user).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return false; } GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return false; } private void SetupPieceInfo(Piece piece) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0084: 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: Invalid comparison between Unknown and I4 //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Invalid comparison between Unknown and I4 //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: 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_033e: Unknown result type (might be due to invalid IL or missing references) Camera mainCamera = Utils.GetMainCamera(); if (!Object.op_Implicit((Object)(object)mainCamera)) { return; } GhostBuildManager.ghostPieceInformation.transform.position = Utils.WorldToScreenPointScaled(mainCamera, ((Component)piece).transform.position); Player localPlayer = Player.m_localPlayer; Hud instance = Hud.instance; if (Object.op_Implicit((Object)(object)localPlayer.m_placementGhost)) { return; } if (Object.op_Implicit((Object)(object)instance.m_pieceHealthRoot)) { ((Component)instance.m_pieceHealthRoot).transform.position = GhostBuildManager.ghostPieceInformation.transform.position + new Vector3(-100f, 100f, 0f); ((Component)instance.m_pieceHealthRoot).gameObject.SetActive(false); } GhostBuildManager.m_buildSelection.text = Localization.instance.Localize(OriginalPiece.m_name); GhostBuildManager.m_pieceDescription.text = Localization.instance.Localize(OriginalPiece.m_description); ((Behaviour)GhostBuildManager.m_buildIcon).enabled = true; GhostBuildManager.m_buildIcon.sprite = OriginalPiece.m_icon; Sprite snappingIconForPiece = instance.GetSnappingIconForPiece(OriginalPiece); GhostBuildManager.m_snappingIcon.sprite = snappingIconForPiece; ((Behaviour)GhostBuildManager.m_snappingIcon).enabled = (Object)(object)snappingIconForPiece != (Object)null && ((int)OriginalPiece.m_category == 2 || OriginalPiece.m_groundPiece || OriginalPiece.m_waterPiece); for (int i = 0; i < GhostBuildManager.m_requirementItems.Length; i++) { if (i < OriginalPiece.m_resources.Length) { Requirement req = OriginalPiece.m_resources[i]; GhostBuildManager.m_requirementItems[i].SetActive(true); SetupRequirementWithStored(GhostBuildManager.m_requirementItems[i].transform, req, localPlayer, (int)OriginalPiece.FreeBuildKey() == 25, 0); } else { GhostBuildManager.m_requirementItems[i].SetActive(false); } } if (Object.op_Implicit((Object)(object)OriginalPiece.m_craftingStation)) { CraftingStation val = CraftingStation.HaveBuildStationInRange(OriginalPiece.m_craftingStation.m_name, ((Component)localPlayer).transform.position); GameObject obj = GhostBuildManager.m_requirementItems[OriginalPiece.m_resources.Length]; obj.SetActive(true); Image component = ((Component)obj.transform.Find("res_icon")).GetComponent<Image>(); TMP_Text component2 = ((Component)obj.transform.Find("res_name")).GetComponent<TMP_Text>(); TMP_Text component3 = ((Component)obj.transform.Find("res_amount")).GetComponent<TMP_Text>(); UITooltip component4 = obj.GetComponent<UITooltip>(); component.sprite = OriginalPiece.m_craftingStation.m_icon; component2.text = Localization.instance.Localize(OriginalPiece.m_craftingStation.m_name); string name = OriginalPiece.m_craftingStation.m_name; component4.m_text = name; if (Object.op_Implicit((Object)(object)val)) { val.ShowAreaMarker(); ((Graphic)component).color = Color.white; component3.text = ""; ((Graphic)component3).color = Color.white; } else { ((Graphic)component).color = Color.gray; component3.text = Localization.instance.Localize("$menu_none"); ((Graphic)component3).color = (((double)Mathf.Sin(Time.time * 10f) <= 0.0 || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)) ? Color.white : Color.red); } } } private bool SetupRequirementWithStored(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier = 1) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) Image component = ((Component)((Component)elementRoot).transform.Find("res_icon")).GetComponent<Image>(); TMP_Text component2 = ((Component)((Component)elementRoot).transform.Find("res_name")).GetComponent<TMP_Text>(); TMP_Text component3 = ((Component)((Component)elementRoot).transform.Find("res_amount")).GetComponent<TMP_Text>(); UITooltip component4 = ((Component)elementRoot).GetComponent<UITooltip>(); if (!Object.op_Implicit((Object)(object)req.m_resItem)) { return true; } ((Component)component).gameObject.SetActive(true); ((Component)component2).gameObject.SetActive(true); ((Component)component3).gameObject.SetActive(true); if (!Object.op_Implicit((Object)(object)req.m_resItem.m_itemData.GetIcon())) { GhostBuildPlugin.GhostBuildLogger.LogError((object)("Item " + req.m_resItem.m_itemData.m_shared.m_name + " has no icon")); } component.sprite = req.m_resItem.m_itemData.GetIcon(); ((Graphic)component).color = Color.white; component4.m_text = Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name); component2.text = Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name); int num = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); int storedResourceCount = GetStoredResourceCount(req.m_resItem.m_itemData.m_shared.m_name); int num2 = req.GetAmount(quality) * craftMultiplier; if (num2 <= 0) { InventoryGui.HideRequirement(elementRoot); return false; } if (storedResourceCount > 0) { component3.text = $"{storedResourceCount}/{num2}"; ((Graphic)component3).color = (Color)((storedResourceCount >= num2) ? Color.white : (((double)Mathf.Sin(Time.time * 10f) > 0.0) ? new Color(1f, 0.7f, 0f) : Color.white)); } else { component3.text = num2.ToString(); if (num < num2 && ((!craft && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)24)) || (craft && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)))) { ((Graphic)component3).color = (((double)Mathf.Sin(Time.time * 10f) > 0.0) ? Color.red : Color.white); } else { ((Graphic)component3).color = Color.white; } } return true; } public static bool SetupRequirement(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier = 1) { //IL_00d8: 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_01c3: 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) Image component = ((Component)((Component)elementRoot).transform.Find("res_icon")).GetComponent<Image>(); TMP_Text component2 = ((Component)((Component)elementRoot).transform.Find("res_name")).GetComponent<TMP_Text>(); TMP_Text component3 = ((Component)((Component)elementRoot).transform.Find("res_amount")).GetComponent<TMP_Text>(); UITooltip component4 = ((Component)elementRoot).GetComponent<UITooltip>(); if (!Object.op_Implicit((Object)(object)req.m_resItem)) { return true; } ((Component)component).gameObject.SetActive(true); ((Component)component2).gameObject.SetActive(true); ((Component)component3).gameObject.SetActive(true); if (!Object.op_Implicit((Object)(object)req.m_resItem.m_itemData.GetIcon())) { GhostBuildPlugin.GhostBuildLogger.LogError((object)("Item " + req.m_resItem.m_itemData.m_shared.m_name + " has no icon")); } component.sprite = req.m_resItem.m_itemData.GetIcon(); ((Graphic)component).color = Color.white; component4.m_text = Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name); component2.text = Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name); int num = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); int num2 = req.GetAmount(quality) * craftMultiplier; if (num2 <= 0) { InventoryGui.HideRequirement(elementRoot); return false; } component3.text = num2.ToString(); if (num < num2 && ((!craft && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)24)) || (craft && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)))) { ((Graphic)component3).color = (((double)Mathf.Sin(Time.time * 10f) > 0.0) ? Color.red : Color.white); } else { ((Graphic)component3).color = Color.white; } return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } private int GetStoredResourceCount(string itemName) { if (!Object.op_Implicit((Object)(object)m_nView) || !m_nView.IsValid()) { return 0; } return m_nView.GetZDO().GetInt("GhostBuild_Resource_" + itemName, 0); } private void SetStoredResourceCount(string itemName, int count) { if (Object.op_Implicit((Object)(object)m_nView) && m_nView.IsValid()) { if (!m_nView.IsOwner()) { m_nView.ClaimOwnership(); } m_nView.GetZDO().Set("GhostBuild_Resource_" + itemName, count); } } internal void ConsumeRemainingResources(Player player) { if (!Object.op_Implicit((Object)(object)OriginalPiece) || OriginalPiece.m_resources == null) { return; } Requirement[] resources = OriginalPiece.m_resources; foreach (Requirement val in resources) { if (Object.op_Implicit((Object)(object)val.m_resItem)) { string name = val.m_resItem.m_itemData.m_shared.m_name; int amount = val.GetAmount(0); int storedResourceCount = GetStoredResourceCount(name); int num = amount - storedResourceCount; if (num > 0) { ((Humanoid)player).GetInventory().RemoveItem(name, num, -1, true); } } } } public bool HasAllResources() { if (!Object.op_Implicit((Object)(object)OriginalPiece) || OriginalPiece.m_resources == null) { return false; } Requirement[] resources = OriginalPiece.m_resources; foreach (Requirement val in resources) { if (Object.op_Implicit((Object)(object)val.m_resItem)) { string name = val.m_resItem.m_itemData.m_shared.m_name; int amount = val.GetAmount(0); if (GetStoredResourceCount(name) < amount) { return false; } } } return true; } private bool TryAddResource(Player player, Requirement requirement, bool takeAll = false) { if (!Object.op_Implicit((Object)(object)requirement.m_resItem)) { return false; } string name = requirement.m_resItem.m_itemData.m_shared.m_name; int amount = requirement.GetAmount(0); int storedResourceCount = GetStoredResourceCount(name); if (storedResourceCount >= amount) { return false; } int num = ((!takeAll) ? 1 : (amount - storedResourceCount)); int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true); if (num2 <= 0) { return false; } int num3 = Mathf.Min(new int[3] { num, num2, amount - storedResourceCount }); ((Humanoid)player).GetInventory().RemoveItem(name, num3, -1, true); SetStoredResourceCount(name, storedResourceCount + num3); ((Character)player).Message((MessageType)2, $"Added {num3}x {Localization.instance.Localize(name)} ({storedResourceCount + num3}/{amount})", 0, (Sprite)null, false); return true; } private bool TryAddAllResources(Player player) { if (!Object.op_Implicit((Object)(object)OriginalPiece) || OriginalPiece.m_resources == null) { return false; } bool result = false; Requirement[] resources = OriginalPiece.m_resources; foreach (Requirement requirement in resources) { if (TryAddResource(player, requirement, takeAll: true)) { result = true; } } return result; } } internal sealed class GhostPiecePrefab { public const string GhostSuffix = "_ghost"; public Piece OriginalPiece { get; } public Piece GhostPiece { get; } public GameObject PiecePrefab => ((Component)GhostPiece).gameObject; public int OriginalHash { get; } public GhostPiecePrefab(Piece original) { //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Invalid comparison between Unknown and I4 //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)original)) { throw new ArgumentNullException("original"); } OriginalPiece = original; OriginalHash = StringExtensionMethods.GetStableHashCode(((Object)original).name); string text = ((Object)((Component)original).gameObject).name + "_ghost"; GameObject val = new GhostBuild.Cloning.Cloning().CreateClonedPrefab(text, ((Component)original).gameObject); if (!Object.op_Implicit((Object)(object)val)) { GhostBuildPlugin.GhostBuildLogger.LogWarning((object)("Failed to clone '" + ((Object)((Component)original).gameObject).name + "' → '" + text + "'")); throw new InvalidOperationException("Clone failed"); } GhostPiece = val.GetComponent<Piece>(); if (!Object.op_Implicit((Object)(object)GhostPiece)) { GhostBuildPlugin.GhostBuildLogger.LogWarning((object)("Cloned prefab '" + text + "' has no Piece component")); throw new InvalidOperationException("Clone has no Piece"); } GhostPieceRegistry.RegisterGhost(((Component)original).gameObject.GetComponent<Piece>(), GhostPiece); GhostPiece.m_name = OriginalPiece.m_name; GhostPiece.m_description = OriginalPiece.m_description; GhostPiece.m_resources = Array.Empty<Requirement>(); GhostPiece.m_craftingStation = null; GhostPiece.m_placeEffect.m_effectPrefabs = Array.Empty<EffectData>(); GhostPiece.m_comfort = 0; GhostPiece.m_canBeRemoved = true; ((StaticTarget)GhostPiece).m_randomTarget = false; ((StaticTarget)GhostPiece).m_primaryTarget = false; GhostPiece.m_enabled = OriginalPiece.m_enabled; GhostPiece.m_category = (PieceCategory)(((int)OriginalPiece.m_category != 9) ? ((int)OriginalPiece.m_category) : 0); GhostPiece.m_groundOnly = OriginalPiece.m_groundOnly; GhostPiece.m_groundPiece = OriginalPiece.m_groundPiece; GhostPiece.m_inCeilingOnly = OriginalPiece.m_inCeilingOnly; GhostPiece.m_isUpgrade = OriginalPiece.m_isUpgrade; ((StaticTarget)GhostPiece).m_haveCenter = ((StaticTarget)OriginalPiece).m_haveCenter; GhostPiece.m_dlc = OriginalPiece.m_dlc; GhostPiece.m_allowAltGroundPlacement = OriginalPiece.m_allowAltGroundPlacement; GhostPiece.m_allowedInDungeons = OriginalPiece.m_allowedInDungeons; GhostPiece.m_icon = OriginalPiece.m_icon; WearNTear val2 = val.GetComponent<WearNTear>(); if (!Object.op_Implicit((Object)(object)val2)) { val2 = val.AddComponent<WearNTear>(); } val2.m_noSupportWear = true; val2.m_noRoofWear = false; val2.m_autoCreateFragments = false; val2.m_supports = true; val2.m_hitEffect = new EffectList(); val2.m_hitNoise = 0f; val2.m_destroyedEffect = new EffectList(); val2.m_destroyNoise = 0f; GhostBuildPiece ghostBuildPiece = default(GhostBuildPiece); if (!val.TryGetComponent<GhostBuildPiece>(ref ghostBuildPiece)) { ghostBuildPiece = val.AddComponent<GhostBuildPiece>(); } ghostBuildPiece.m_piece = GhostPiece; ghostBuildPiece.OriginalPiece = OriginalPiece; GhostBuildManager.DisablePiece(val); ShaderHelper.UpdateTextures(val, ShaderHelper.ShaderState.Supported); } } public static class GizmoMeshCache { private static readonly Dictionary<float, Mesh> ArcMeshCache = new Dictionary<float, Mesh>(); public static void DrawArc(Vector3 position, float radius, Color color, Vector3 axis, Quaternion rotation, float scale) { //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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0039: 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_003c: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!ArcMeshCache.TryGetValue(radius, out Mesh value)) { value = CreateCircleMesh(radius); ArcMeshCache[radius] = value; } Material val = new Material(Shader.Find("Sprites/Default")) { color = color }; Matrix4x4 val2 = Matrix4x4.TRS(position, rotation, Vector3.one * scale); Graphics.DrawMesh(value, val2, val, 0); } private static Mesh CreateCircleMesh(float radius) { //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_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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown Vector3[] array = (Vector3[])(object)new Vector3[64]; int[] array2 = new int[128]; for (int i = 0; i < 64; i++) { float num = (float)Math.PI * 2f * (float)i / 64f; array[i] = new Vector3(radius * Mathf.Cos(num), 0f, radius * Mathf.Sin(num)); array2[2 * i] = i; array2[2 * i + 1] = (i + 1) % 64; } Mesh val = new Mesh { vertices = array }; val.SetIndices(array2, (MeshTopology)3, 0); return val; } public static Mesh GetArcMesh(float radius) { if (ArcMeshCache.TryGetValue(radius, out Mesh value)) { return value; } value = CreateCircleMesh(radius); ArcMeshCache[radius] = value; return value; } } [HarmonyPatch(typeof(Player), "SetLocalPlayer")] internal static class AttachSnapGizmoManagerPlayerSetLocalPlayerPatch { private static void Postfix(Player __instance) { SnapGizmoManager snapGizmoManager = default(SnapGizmoManager); if (!((Component)__instance).gameObject.TryGetComponent<SnapGizmoManager>(ref snapGizmoManager)) { ((Component)__instance).gameObject.AddComponent<SnapGizmoManager>(); } } } [HarmonyPatch(typeof(Player), "UpdateAvailablePiecesList")] internal static class Player_UpdateAvailablePiecesList_GhostPatch { private static void Postfix(Player __instance) { if (!GhostBuildState.ShouldUseGhostPieces(__instance)) { return; } PieceTable buildPieces = __instance.m_buildPieces; if (!Object.op_Implicit((Object)(object)buildPieces) || buildPieces.m_availablePiecesByCategory == null) { return; } for (int i = 0; i < buildPieces.m_availablePiecesByCategory.Count; i++) { List<Piece> list = buildPieces.m_availablePiecesByCategory[i]; if (list == null || list.Count == 0) { continue; } for (int j = 0; j < list.Count; j++) { Piece val = list[j]; if (Object.op_Implicit((Object)(object)val) && GhostPieceRegistry.TryGetGhost(val, out Piece ghost) && Object.op_Implicit((Object)(object)ghost)) { list[j] = ghost; } } } } } [HarmonyPatch(typeof(PieceTable), "GetPieceIndex")] internal static class PieceTableGetPieceIndexGhostPatch { private static void Prefix(PieceTable __instance, ref Piece p) { if (Object.op_Implicit((Object)(object)p) && !__instance.IsPieceAvailable(p)) { Piece real; if (GhostPieceRegistry.TryGetGhost(p, out Piece ghost) && __instance.IsPieceAvailable(ghost)) { p = ghost; } else if (GhostPieceRegistry.TryGetReal(p, out real) && __instance.IsPieceAvailable(real)) { p = real; } } } } [HarmonyPatch(typeof(BuildUi), "AddRecentPiece")] internal static class BuildUiAddRecentPieceGhostPatch { private static void Prefix(ref Piece piece) { piece = GhostPieceRegistry.ToReal(piece); } } [HarmonyPatch(typeof(BuildUi), "UpdatePieceSelection")] internal static class BuildUiUpdatePieceSelectionGhostPatch { private static void Prefix(ref Piece selectedPiece) { selectedPiece = GhostPieceRegistry.ToReal(selectedPiece); } } [HarmonyPatch(typeof(Player), "SetupPlacementGhost")] internal static class FloatingRecolorPlayerSetupPlacementGhostPatch { private static void Postfix(Player __instance) { if (GhostBuildManager.IsGhostActive) { GhostBuildManager.ApplyToCurrentGhost(); } } } [HarmonyPatch(typeof(Player), "SetPlaceMode")] public static class Patch_SetPlaceMode { private static void Postfix(Player __instance, PieceTable buildPieces) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { if (Object.op_Implicit((Object)(object)buildPieces)) { GhostBuildManager.OnEnterPlaceMode(); } else { GhostBuildManager.OnExitPlaceMode(); } } } } [HarmonyPatch(typeof(Piece), "OnPlaced")] public class AddZDO { public static bool forFree; [UsedImplicitly] private static void Postfix(Piece __instance) { if (GhostBuildManager.IsGhostActive) { forFree = true; } ZNetView val = default(ZNetView); ((Component)__instance).TryGetComponent<ZNetView>(ref val); if (Object.op_Implicit((Object)(object)val) && val.IsValid()) { val.GetZDO().Set("GhostBuildFreeBuild", forFree); val.GetZDO().Set("GhostBuild", forFree); if (forFree) { Piece val2 = default(Piece); GhostBuildManager.ApplyGhostVisual(RadialUtilityExtensions.TryGetComponentInParent<Piece>(((Component)__instance).gameObject, ref val2) ? val2 : null); Piece val3 = default(Piece); GhostBuildManager.ApplyGhostBuildPiece(RadialUtilityExtensions.TryGetComponentInParent<Piece>(((Component)__instance).gameObject, ref val3) ? val3 : null); } } } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] internal static class ResetFlagPlayerUpdatePlacementPatch { private static void Finalizer() { AddZDO.forFree = false; } } [HarmonyPatch(typeof(Player), "ConsumeResources")] internal static class BuildingIsFree { private class SkipConsumeResourcesException : Exception { } [HarmonyPriority(800)] private static void Prefix() { if (AddZDO.forFree) { throw new SkipConsumeResourcesException(); } } private static Exception? Finalizer(Exception __exception) { if (!(__exception is SkipConsumeResourcesException)) { return __exception; } return null; } } [HarmonyPatch(typeof(Piece), "DropResources")] internal static class RecoverResources { private static bool Prefix(Piece __instance) { ZNetView val = default(ZNetView); if (((Component)__instance).TryGetComponent<ZNetView>(ref val) && val.GetZDO().IsValid()) { return !val.m_zdo.GetBool("GhostBuildFreeBuild", false); } return true; } } [HarmonyPatch(typeof(ZNetScene), "Destroy")] internal static class Patch_ZNetScene_Destroy_RefundGhostResources { private static void Prefix(GameObject go) { GhostBuildPiece ghostBuildPiece = default(GhostBuildPiece); if ((Object)(object)go != (Object)null && go.TryGetComponent<GhostBuildPiece>(ref ghostBuildPiece)) { ghostBuildPiece.RefundIfNotConfirmed(); } } } [HarmonyPatch(typeof(Player), "CheckCanRemovePiece")] internal static class PlayerCheckCanRemovePiecePatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if (!piece.IsGhostPiece(out ZNetView _)) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Player), "Update")] internal static class Patch_Player_Update_ToggleGhost { private static void Postfix(Player __instance) { //IL_003d: 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_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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Invalid comparison between I4 and Unknown //IL_00a2: 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) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } ItemData rightItem = ((Humanoid)__instance).GetRightItem(); if (rightItem == null || !Object.op_Implicit((Object)(object)rightItem.m_shared.m_buildPieces) || !((Character)Player.m_localPlayer).TakeInput()) { return; } if (GhostBuildPlugin.ToggleGhostKey.Value.IsKeyDown()) { GhostBuildManager.ToggleGhost(); } if (!GhostBuildPlugin.QuickSwapRepairKey.Value.IsKeyDown() || !Object.op_Implicit((Object)(object)__instance.m_placementGhost)) { return; } GhostBuildManager.CachedPiece = __instance.GetSelectedPiece(); PieceTable buildPieces = __instance.m_buildPieces; if (Object.op_Implicit((Object)(object)buildPieces)) { PieceCategory selectedCategory = buildPieces.GetSelectedCategory(); if (buildPieces.m_selectedPiece.Length > (int)selectedCategory) { buildPieces.m_selectedPiece[selectedCategory] = new Vector2Int(0, 0); __instance.SetupPlacementGhost(); } } } } [HarmonyPatch(typeof(Player), "PlacePiece", new Type[] { typeof(Piece), typeof(Vector3), typeof(Quaternion), typeof(bool), typeof(bool) })] internal static class Patch_Player_PlacePiece_TagGhost { private const float scanRadius = 0.1f; private static void Postfix(Player __instance, Piece piece, Vector3 pos, Quaternion rot, bool doAttack) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) Collider[] array; if (GhostBuildManager.IsGhostActive && !GhostBuildManager.SuppressTagging) { array = Physics.OverlapSphere(pos, 0.1f, LayerMask.GetMask(new string[4] { "piece", "piece_nonsolid", "Default", "Default_small" })); WearNTear val = default(WearNTear); for (int i = 0; i < array.Length; i++) { Piece componentInParent = ((Component)array[i]).GetComponentInParent<Piece>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !(((Object)((Component)componentInParent).gameObject).name.Replace("(Clone)", "") == ((Object)((Component)piece).gameObject).name)) { continue; } ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { if (!component.IsOwner()) { component.ClaimOwnership(); } component.GetZDO().Set("GhostBuild", true); component.GetZDO().Set("GhostBuildFreeBuild", true); GhostBuildManager.ApplyGhostVisual(componentInParent); GhostBuildManager.ApplyGhostBuildPiece(componentInParent); if (((Component)componentInParent).TryGetComponent<WearNTear>(ref val)) { val.Highlight(); } } } } if (!piece.IsGhostPiece(out ZNetView zNetView) || !Object.op_Implicit((Object)(object)zNetView)) { return; } array = Physics.OverlapSphere(pos, 0.1f, LayerMask.GetMask(new string[4] { "piece", "piece_nonsolid", "Default", "Default_small" })); ZNetView val2 = default(ZNetView); for (int i = 0; i < array.Length; i++) { Piece componentInParent2 = ((Component)array[i]).GetComponentInParent<Piece>(); if (Object.op_Implicit((Object)(object)componentInParent2) && !(((Object)((Component)componentInParent2).gameObject).name.Replace("(Clone)", "") != ((Object)((Component)piece).gameObject).name) && ((Component)componentInParent2).TryGetComponent<ZNetView>(ref val2) && val2.IsValid()) { GhostBuildPlugin.GhostBuildLogger.LogMessage((object)"Deep cloning."); piece.DeepClonePieceZdo(zNetView.m_zdo, val2.m_zdo); } } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class PlayerHaveRequirementsPatch { private const float SettleTime = 0.35f; private static bool _pendingAnswer; private static float _pendingSince; private static int _lastSampledFrame = -1; private static bool _resolvingRealRequirements; internal static void ResetAutoGhostTracking() { _lastSampledFrame = -1; _pendingSince = 0f; } private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_0032: 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_0061: Invalid comparison between Unknown and I4 if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || _resolvingRealRequirements) { return; } ItemData rightItem = ((Humanoid)__instance).GetRightItem(); if (rightItem != null && Object.op_Implicit((Object)(object)rightItem.m_shared.m_buildPieces)) { if ((int)mode == 0 && GhostBuildPlugin.GhostModeAutoSwitch.Value.IsOn() && IsSelectedPiece(__instance, piece)) { UpdateAutoGhost(__instance, piece, __result); } if (GhostBuildManager.IsGhostActive && (int)mode != 1) { __result = true; } } } private static bool IsSelectedPiece(Player player, Piece piece) { if (!Object.op_Implicit((Object)(object)piece) || !Object.op_Implicit((Object)(object)player.m_placementGhost) || !Object.op_Implicit((Object)(object)player.m_buildPieces)) { return false; } Piece selectedPiece = player.m_buildPieces.GetSelectedPiece(); if (Object.op_Implicit((Object)(object)selectedPiece)) { if (!((Object)(object)selectedPiece == (Object)(object)piece)) { return selectedPiece.m_name == piece.m_name; } return true; } return false; } private static void UpdateAutoGhost(Player player, Piece piece, bool hasRequirements) { if (GhostBuildManager.IsGhostActive && GhostPieceRegistry.TryGetReal(piece, out Piece real) && Object.op_Implicit((Object)(object)real)) { _resolvingRealRequirements = true; try { hasRequirements = player.HaveRequirements(real, (RequirementMode)0); } finally { _resolvingRealRequirements = false; } piece = real; } int frameCount = Time.frameCount; if (frameCount == _lastSampledFrame) { return; } if (_lastSampledFrame < 0 || hasRequirements != _pendingAnswer) { _pendingAnswer = hasRequirements; _pendingSince = Time.time; } _lastSampledFrame = frameCount; if (!(Time.time - _pendingSince < 0.35f)) { if (!hasRequirements && !GhostBuildManager.IsGhostActive && !player.NoCostCheat() && player.m_knownRecipes.Contains(piece.m_name)) { GhostBuildManager.ToggleGhost(auto: true); ((Character)player).Message((MessageType)2, Localization.instance.Localize("$msg_missingrequirement — $enemy_ghost $piece_guardstone_active"), 0, (Sprite)null, false); } else if (hasRequirements && GhostBuildManager.IsGhostActive && GhostBuildManager.AutoGhostEngaged) { GhostBuildManager.ToggleGhost(); } } } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class Patch_Piece_Awake_ApplyGhost { private static void Postfix(Piece __instance) { GhostBuildManager.ApplyGhostVisual(__instance); GhostBuildManager.ApplyGhostBuildPiece(__instance); } } [HarmonyPatch(typeof(WearNTear), "UpdateWear")] internal static class Patch_WearNTear_UpdateWear_AdjustMask { private static void Prefix(WearNTear __instance, float time, ref int __state) { __state = WearNTear.s_rayMask; int num = 1 << LayerMask.NameToLayer("piece_nonsolid"); if (__instance.IsGhostPiece()) { WearNTear.s_rayMask |= num; } else { WearNTear.s_rayMask &= ~num; } } private static void Postfix(ref int __state) { WearNTear.s_rayMask = __state; } } [HarmonyPatch(typeof(WearNTear), "Damage")] internal static class PreventDamageWearNTearDamagePatch { private static bool Prefix(WearNTear __instance) { return !__instance.IsGhostPiece(); } } [HarmonyPatch(typeof(WearNTear), "ApplyDamage")] internal static class Patch_WearNTear_ApplyDamage_SkipGhost { private static bool Prefix(WearNTear __instance) { return !__instance.IsGhostPiece(); } } [HarmonyPatch(typeof(Hud), "Awake")] internal static class BumpUpHealthRootOfPieceHudAwakePatch { internal static Vector3 CachedHealthRootPosition = Vector3.zero; [HarmonyPriority(0)] private static void Postfix(Hud __instance) { //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_000d: 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_0030: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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) Vector3 val = (CachedHealthRootPosition = ((Transform)__instance.m_pieceHealthRoot).localPosition); ((Transform)__instance.m_pieceHealthRoot).localPosition = new Vector3(val.x, val.y + 20f, val.z); GhostBuildManager.ghostPieceInformation = Object.Instantiate<GameObject>(((Component)__instance.m_buildHud.transform.Find("SelectedInfo")).gameObject, __instance.m_buildHud.transform, true); ((Object)GhostBuildManager.ghostPieceInformation).name = "GhostPieceInformation"; Vector3 localPosition = __instance.m_buildHud.transform.Find("SelectedInfo").localPosition; float num = ((!Chainloader.PluginInfos.ContainsKey("Azumatt.AzuHoverStats")) ? 525f : 650f); GhostBuildManager.ghostPieceInformation.transform.localPosition = new Vector3(localPosition.x + num, localPosition.y, localPosition.z); ((Graphic)((Component)GhostBuildManager.ghostPieceInformation.transform.Find("Bkg2")).GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0f); GhostBuildManager.m_buildSelection = ((Component)GhostBuildManager.ghostPieceInformation.transform.Find("selected_piece/piece_name")).GetComponent<TMP_Text>(); GhostBuildManager.m_pieceDescription = ((Component)GhostBuildManager.ghostPieceInformation.transform.Find("selected_piece/piece_description")).GetComponent<TMP_Text>(); GhostBuildManager.m_buildIcon = ((Component)GhostBuildManager.ghostPieceInformation.transform.Find("selected_piece/piece_icon")).GetComponent<Image>(); GhostBuildManager.m_snappingIcon = ((Component)GhostBuildManager.ghostPieceInformation.transform.Find("selected_piece/snappingHint")).GetComponent<Image>(); ((Behaviour)((Component)GhostBuildManager.ghostPieceInformation.transform.Find("requirements")).GetComponent<Image>()).enabled = true; GhostBuildManager.m_requirementItems = (GameObject[])(object)new GameObject[GhostBuildManager.ghostPieceInformation.transform.Find("requirements").childCount]; for (int i = 0; i < GhostBuildManager.m_requirementItems.Length; i++) { GhostBuildManager.m_requirementItems[i] = ((Component)GhostBuildManager.ghostPieceInformation.transform.Find("requirements").GetChild(i)).gameObject; } GhostBuildManager.ghostPieceInformation.SetActive(false); } } [HarmonyPatch(typeof(Player), "UpdateHover")] internal static class PlayerUpdateHoverPatch { private static MethodInfo InPlaceMode = AccessTools.Method(typeof(Character), "InPlaceMode", (Type[])null, (Type[])null); private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> code) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown List<CodeInstruction> list = code.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], InPlaceMode)) { list[i - 1].opcode = OpCodes.Nop; list[i] = new CodeInstruction(OpCodes.Ldc_I4_0, (object)null); } } return list.AsEnumerable(); } private static void Postfix(Player __instance) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)GhostBuildManager.ghostPieceInformation == (Object)null) && (!Object.op_Implicit((Object)(object)__instance.m_hovering) || ((Character)__instance).TakeInput() || Hud.IsPieceSelectionVisible())) { GhostBuildManager.ghostPieceInformation.SetActive(false); if (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_pieceHealthRoot)) { ((Transform)Hud.instance.m_pieceHealthRoot).localPosition = BumpUpHealthRootOfPieceHudAwakePatch.CachedHealthRootPosition; } } } } [HarmonyPatch(typeof(Player), "Repair")] internal static class AllowRepairToBuildGhostPlayerRepairPatch { private static bool Prefix(Player __instance, ItemData toolItem, Piece repairPiece) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0101: 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_00ca: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Character)__instance).InPlaceMode() || !Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } Piece hoveringPiece = __instance.GetHoveringPiece(); if (Object.op_Implicit((Object)(object)hoveringPiece) && PrivateArea.CheckAccess(((Component)hoveringPiece).transform.position, 0f, true, false)) { if (!hoveringPiece.HasGhostComponent(out GhostBuildPiece ghostBuildPiece)) { return true; } bool isGhostActive = GhostBuildManager.IsGhostActive; bool suppressTagging = GhostBuildManager.SuppressTagging; GhostBuildManager.IsGhostActive = false; GhostBuildManager.SuppressTagging = true; bool flag = localPlayer.NoCostCheat(); bool flag2 = localPlayer.HaveRequirements(ghostBuildPiece.OriginalPiece, (RequirementMode)0); bool flag3 = ghostBuildPiece.HasAllResources(); if (flag || flag2 || flag3) { if (!GhostBuildManager.TryResolveRealPrefab(ghostBuildPiece, out Piece realPrefab)) { return true; } GhostBuildManager.UnregisterGhost(ghostBuildPiece.m_piece); if (!flag && !ZoneSystem.instance.GetGlobalKey(ghostBuildPiece.m_piece.FreeBuildKey())) { ghostBuildPiece.ConsumeRemainingResources(localPlayer); } ghostBuildPiece.MarkConfirmed(); ZNetScene.instance.Destroy(((Component)ghostBuildPiece).gameObject); localPlayer.PlacePiece(realPrefab, ((Component)ghostBuildPiece.m_piece).transform.position, ((Component)ghostBuildPiece.m_piece).transform.rotation, false, false); GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; ZLog.Log((object)("Placed " + ((Object)realPrefab).name)); Gogan.LogEvent("Game", "PlacedPiece", ((Object)realPrefab).name, 0L); Game.instance.IncrementPlayerStat((PlayerStatType)2, 1f, false); return false; } if (Object.op_Implicit((Object)(object)ghostBuildPiece.OriginalPiece.m_craftingStation) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(ghostBuildPiece.OriginalPiece.m_craftingStation.m_name, ((Component)localPlayer).transform.position)) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27)) { ((Character)localPlayer).Message((MessageType)2, "$msg_missingstation", 0, (Sprite)null, false); GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return true; } if (flag2) { return true; } ((Character)localPlayer).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); GhostBuildManager.SuppressTagging = suppressTagging; GhostBuildManager.IsGhostActive = isGhostActive; return true; } return true; } } [HarmonyPatch(typeof(Hud), "TogglePieceSelection")] internal static class PreventIfTogglingToGhostModeHudTogglePieceSelectionPatch { private unsafe static bool Prefix(Hud __instance) { //IL_0005: 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_0028: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 if (GhostBuildPlugin.QuickSwapRepairKey.Value.IsKeyDown()) { KeyboardShortcut value = GhostBuildPlugin.QuickSwapRepairKey.Value; object obj = (object)(KeyboardShortcut)((ConfigEntryBase)GhostBuildPlugin.QuickSwapRepairKey).DefaultValue; if (!((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).Equals(obj)) { value = GhostBuildPlugin.QuickSwapRepairKey.Value; return (int)((KeyboardShortcut)(ref value)).MainKey != 324; } return false; } return true; } } [BepInPlugin("Azumatt.GhostBuild", "GhostBuild", "1.0.2")] public class GhostBuildPlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] public string? Category; [UsedImplicitly] public Action<ConfigEntryBase>? CustomDrawer; } private class AcceptableShortcuts : AcceptableValueBase { public AcceptableShortcuts() : base(typeof(KeyboardShortcut)) { } public override object Clamp(object value) { return value; } public override bool IsValid(object value) { return true; } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes); } } internal const string ModName = "GhostBuild"; internal const string ModVersion = "1.0.2"; internal const string Author = "Azumatt"; private const string ModGUID = "Azumatt.GhostBuild"; private static string ConfigFileName = "Azumatt.GhostBuild.cfg"; private static string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("Azumatt.GhostBuild"); public static readonly ManualLogSource GhostBuildLogger; private static readonly ConfigSync ConfigSync; private FileSystemWatcher _watcher; private readonly object _reloadLock = new object(); private DateTime _lastConfigReloadTime; private const long RELOAD_DELAY = 10000000L; private readonly Dictionary<Piece, bool> _lastSupportState = new Dictionary<Piece, bool>(); private static ConfigEntry<Toggle> _serverConfigLocked; public static ConfigEntry<KeyboardShortcut> ToggleGhostKey; public static ConfigEntry<KeyboardShortcut> QuickSwapRepairKey; public static ConfigEntry<Color> UnsupportedColorConfig; public static ConfigEntry<Color> SupportedGhostColorConfig; public static ConfigEntry<float> TransparencyConfig; internal static ConfigEntry<Toggle> GhostModeExplicit; internal static ConfigEntry<Toggle> GhostModeAutoSwitch; internal static ConfigEntry<Toggle> AlwaysShowGhosts; internal static ConfigEntry<Toggle> ShowGhostToggleMessages; public static ConfigEntry<Toggle> ShowSnapGizmos; public static ConfigEntry<Toggle> ShowNearbySnapGizmos; public static ConfigEntry<float> SnapGizmoInnerRadius; public static ConfigEntry<float> SnapGizmoOuterRadius; public static ConfigEntry<float> SnapGizmoNearbyRadius; public static ConfigEntry<Color> SnapGizmoGhostColor; public static ConfigEntry<Color> SnapGizmoNearbyColor; public void Awake() { //IL_0058: 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_00bf: 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_00f3: Expected O, but got Unknown //IL_0140: 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_0174: Expected O, but got Unknown //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; int num = 0; _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); ToggleGhostKey = config<KeyboardShortcut>("1.5 - Hotkeys", "Toggle Ghost Shortcut", new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()), "The key to toggle ghost mode while holding a build hammer.", synchronizedSetting: false); QuickSwapRepairKey = config<KeyboardShortcut>("1.5 - Hotkeys", "Quick Swap to Repair", new KeyboardShortcut((KeyCode)324, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Key combination needed, while holding a build hammer, to quickly swap to the repair option in the build menu", synchronizedSetting: false); UnsupportedColorConfig = config<Color>("2 - Visuals", "Unsupported color", new Color(1f, 0.533f, 0.4313f, 0.5f), new ConfigDescription("Color of unsupported ghost pieces", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = (num -= 1) } }), synchronizedSetting: false); UnsupportedColorConfig.SettingChanged += delegate { GhostBuildManager.UpdateGhostPieces(); }; SupportedGhostColorConfig = config<Color>("2 - Visuals", "Supported color", new Color(0.078f, 0.57f, 1f, 0.5f), new ConfigDescription("Color of supported ghost pieces", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = (num -= 1) } }), synchronizedSetting: false); SupportedGhostColorConfig.SettingChanged += delegate { GhostBuildManager.UpdateGhostPieces(); }; TransparencyConfig = config("2 - Visuals", "Transparency", 0.9f, new ConfigDescription("Additional transparency for finer control.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = (num -= 1) } }), synchronizedSetting: false); TransparencyConfig.SettingChanged += delegate { GhostBuildManager.UpdateGhostPieces(); }; GhostModeExplicit = config("3 - Ghost Mode Behavior", "Require Manual Ghost Toggle", Toggle.Off, "If on, ghost pieces only appear when you manually toggle ghost mode. If off, ghost pieces appear automatically whenever you're in build mode."); GhostModeAutoSwitch = config("3 - Ghost Mode Behavior", "Auto-Ghost When Out of Resources", Toggle.On, "If on, ghost mode is automatically enabled for the current piece when you run out of resources to build it. If off, you must toggle ghost mode yourself to continue building without resources."); AlwaysShowGhosts = config("3 - Ghost Mode Behavior", "Always Show Ghosts", Toggle.Off, "If on, already-placed ghost pieces stay visible even when you aren't holding a build hammer. If off, they're only visible while a hammer is equipped.", synchronizedSetting: false); AlwaysShowGhosts.SettingChanged += delegate { GhostBuildManager.UpdateGhostPieces(); }; ShowGhostToggleMessages = config("3 - Ghost Mode Behavior", "Show Ghost Toggle Messages", Toggle.On, "If on, shows a center-screen message when ghost mode is toggled on/off. If off, the toggle happens silently.", synchronizedSetting: false); ShowSnapGizmos = config("4 - Snap Gizmos", "Show Ghost Snap Gizmos", Toggle.On, "If on, draw circular gizmos at snap points of the current placement ghost.", synchronizedSetting: false); ShowNearbySnapGizmos = config("4 - Snap Gizmos", "Show Nearby Snap Gizmos", Toggle.On, "If on, draw circular gizmos at snap points of nearby placed pieces around the ghost.", synchronizedSetting: false); SnapGizmoInnerRadius = config("4 - Snap Gizmos", "Inner Ring Radius", 0.15f, "Inner ring radius of snap gizmos (meters).", synchronizedSetting: false); SnapGizmoOuterRadius = config("4 - Snap Gizmos", "Outer Ring Radius", 0.25f, "Outer ring radius of snap gizmos (meters).", synchronizedSetting: false); SnapGizmoNearbyRadius = config("4 - Snap Gizmos", "Nearby Search Radius", 1.5f, "Radius (meters) around the placement ghost to search for snap points on other pieces.", synchronizedSetting: false); SnapGizmoGhostColor = config<Color>("4 - Snap Gizmos", "Ghost Snap Color", new Color(0f, 1f, 0.2f, 0.75f), "Color for snap gizmos on the current placement ghost.", synchronizedSetting: false); SnapGizmoNearbyColor = config<Color>("4 - Snap Gizmos", "Nearby Snap Color", new Color(0.4f, 0.8f, 1f, 0.6f), "Color for snap gizmos on nearby pieces.", synchronizedSetting: false); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } public void Update() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ItemData rightItem = ((Humanoid)localPlayer).GetRightItem(); bool flag = rightItem != null && rightItem.m_shared != null && Object.op_Implicit((Object)(object)rightItem.m_shared.m_buildPieces); bool flag2 = GhostModeExplicit.Value.IsOn() && GhostBuildManager.IsGhostActive; WearNTear val2 = default(WearNTear); for (int num = GhostBuildManager.GhostPieces.Count - 1; num >= 0; num--) { Piece val = GhostBuildManager.GhostPieces[num]; if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).gameObject)) { GhostBuildManager.GhostPieces.RemoveAt(num); } else { bool flag3 = true; if (((Component)val).TryGetComponent<WearNTear>(ref val2)) { flag3 = val2.HaveSupport(); } if (!_lastSupportState.TryGetValue(val, out var value) || value != flag3) { _lastSupportState[val] = flag3; ShaderHelper.ShaderState shaderState = ((!flag3) ? ShaderHelper.ShaderState.UnSupported : ShaderHelper.ShaderState.Supported); ShaderHelper.UpdateTextures(((Component)val).gameObject, shaderState); } bool flag4 = flag || AlwaysShowGhosts.Value.IsOn(); foreach (Renderer renderer in ShaderHelper.GetRenderers(((Component)val).gameObject)) { if (Object.op_Implicit((Object)(object)renderer)) { if (GhostModeExplicit.Value.IsOn()) { renderer.enabled = flag2 && flag4; } else { renderer.enabled = flag4; } } } } } } private void OnDestroy() { SaveWithRespectToConfigSet(); _watcher?.Dispose(); } private void SetupWatcher() { _watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); _watcher.Changed += ReadConfigValues; _watcher.Created += ReadConfigValues; _watcher.Renamed += ReadConfigValues; _watcher.IncludeSubdirectories = true; _watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _watcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { DateTime now = DateTime.Now; if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { if (!File.Exists(ConfigFileFullPath)) { GhostBuildLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { GhostBuildLogger.LogDebug((object)"Reloading configuration..."); SaveWithRespectToConfigSet(reload: true); GhostBuildLogger.LogInfo((object)"Configuration reload complete."); } catch (Exception ex) { GhostBuildLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } } _lastConfigReloadTime = now; } private void SaveWithRespectToConfigSet(bool reload = false) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } static GhostBuildPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; GhostBuildLogger = Logger.CreateLogSource("GhostBuild"); ConfigSync = new ConfigSync("Azumatt.GhostBuild") { DisplayName = "GhostBuild", CurrentVersion = "1.0.2", MinimumRequiredVersion = "1.0.2" }; _serverConfigLocked = null; GhostModeExplicit = null; GhostModeAutoSwitch = null; AlwaysShowGhosts = null; ShowGhostToggleMessages = null; } } public static class ReflectionHelper { public const BindingFlags AllBindingFlags = (BindingFlags)(-1); public static bool IsSameOrSubclass(this Type type, Type @base) { if (!type.IsSubclassOf(@base)) { return type == @base; } return true; } } public static class ShaderCache { internal static readonly HashSet<Shader> CachedShaders = new HashSet<Shader>(); internal static bool Initialized = false; } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystemStartPatch { private static void Postfix() { if (ShaderCache.Initialized) { return; } Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); foreach (Shader val in array) { if ((Object)(object)val != (Object)null) { ShaderCache.CachedShaders.Add(val); } } AssetBundle[] array2 = Resources.FindObjectsOfTypeAll<AssetBundle>(); foreach (AssetBundle val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } try { Shader[] array3 = val2.LoadAllAssets<Shader>(); if (array3 != null && array3.Length != 0) { array = array3; foreach (Shader val3 in array) { if ((Object)(object)val3 != (Object)null) { ShaderCache.CachedShaders.Add(val3); } } continue; } } catch { } string[] allAssetNames; try { allAssetNames = val2.GetAllAssetNames(); } catch { continue; } string[] array4 = allAssetNames; foreach (string text in array4) { if (!text.EndsWith(".shader", StringComparison.OrdinalIgnoreCase)) { continue; } try { Shader val4 = val2.LoadAsset<Shader>(text); if ((Object)(object)val4 != (Object)null) { ShaderCache.CachedShaders.Add(val4); } } catch { } } } GhostBuildPlugin.GhostBuildLogger.LogInfo((object)$"Primed shader cache with {ShaderCache.CachedShaders.Count} shaders."); ShaderCache.Initialized = true; } } public static class MaterialReplacer { public static Shader FindCached(string name, Shader fallback = null) { GhostBuildPlugin.GhostBuildLogger.LogWarning((object)("ShaderCache.FindCached: " + name)); Shader val = ((IEnumerable<Shader>)ShaderCache.CachedShaders).FirstOrDefault((Func<Shader, bool>)((Shader x) => ((Object)x).name == name)); if ((Object)(object)val != (Object)null) { GhostBuildPlugin.GhostBuildLogger.LogWarning((object)("ShaderCache.FindCached: found " + name)); return val; } GhostBuildPlugin.GhostBuildLogger.LogWarning((object)("ShaderCache.FindCached: not found " + name)); return fallback ?? Shader.Find(name); } } public class ShaderHelper { public enum ShaderState { Supported, UnSupported, Original } private static readonly Dictionary<Material, Material> SupportedMaterialCache = new Dictionary<Material, Material>(); private static readonly Dictionary<Material, Material> UnsupportedMaterialCache = new Dictionary<Material, Material>(); private static Shader? _planShader = null; public static Shader PlanShader => _planShader ?? (_planShader = MaterialReplacer.FindCached("Lux Lit Particles/ Bumped")); public static void ClearCache() { SupportedMaterialCache.Clear(); UnsupportedMaterialCache.Clear(); } public static Texture2D GetTexture(Color color) { //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_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_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, color); val.Apply(); return val; } public static Texture2D CreateScaledTexture(Texture2D texture, int width) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0032: Expected O, but got Unknown Texture2D val = new Texture2D(((Texture)texture).width, ((Texture)texture).height, texture.format, false); val.SetPixels(texture.GetPixels()); val.Apply(); ScaleTexture(val, width); return val; } public static void ScaleTexture(Texture2D texture, int width) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //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) Texture2D val = new Texture2D(((Texture)texture).width, ((Texture)texture).height, texture.format, false); val.SetPixels(texture.GetPixels()); val.Apply(); int num = (int)Math.Round((float)width * (float)((Texture)texture).height / (float)((Texture)texture).width); texture.Reinitialize(width, num); texture.Apply(); Color[] pixels = texture.GetPixels(0); float num2 = 1f / (float)width; float num3 = 1f / (float)num; for (int i = 0; i < pixels.Length; i++) { pixels[i] = val.GetPixelBilinear(num2 * ((float)i % (float)width), num3 * Mathf.Floor((float)i / (float)width)); } texture.SetPixels(pixels, 0); texture.Apply(); Object.Destroy((Object)(object)val); } public static List<Renderer> GetRenderers(GameObject gameObject) { List<Renderer> list = new List<Renderer>(); list.AddRange((IEnumerable<Renderer>)(object)gameObject.GetComponentsInChildren<MeshRenderer>(true)); list.AddRange((IEnumerable<Renderer>)(object)gameObject.GetComponentsInChildren<SkinnedMeshRenderer>(true)); return list; } public static void UpdateTextures(GameObject gameObject, ShaderState shaderState) { if (!Object.op_Implicit((Object)(object)gameObject)) { return; } WearNTear val = default(WearNTear); if (gameObject.TryGetComponent<WearNTear>(ref val) && val.m_oldMaterials != null) { val.ResetHighlight(); } GhostMaterialState ghostMaterialState = gameObject.GetComponent<GhostMaterialState>(); if (!Object.op_Implicit((Object)(object)ghostMaterialState)) { ghostMaterialState = gameObject.AddComponent<GhostMaterialState>(); } if (ghostMaterialState.Renderers == null || ghostMaterialState.Renderers.Length == 0 || ghostMaterialState.Renderers.Any((Renderer r) => !Object.op_Implicit((Object)(object)r))) { ghostMaterialState.Renderers = (from r in GetRenderers(gameObject) where (Object)(object)r != (Object)null select r).ToArray(); ghostMaterialState.Initialized = false; } if (ghostMaterialState.Renderers == null || ghostMaterialState.Renderers.Length == 0) { ghostMaterialState.CurrentState = shaderState; return; } if (!ghostMaterialState.Initialized || ghostMaterialState.OriginalMaterials == null || ghostMaterialState.OriginalMaterials.Length != ghostMaterialState.Renderers.Length) { int num = ghostMaterialState.Renderers.Length; ghostMaterialState.OriginalMaterials = new Material[num][]; for (int num2 = 0; num2 < num; num2++) { Renderer val2 = ghostMaterialState.Renderers[num2]; if (!Object.op_Implicit((Object)(object)val2)) { ghostMaterialState.OriginalMaterials[num2] = Array.Empty<Material>(); continue; } Material[] source = val2.sharedMaterials ?? Array.Empty<Material>(); ghostMaterialState.OriginalMaterials[num2] = source.ToArray(); } ghostMaterialState.Initialized = true; ghostMaterialState.CurrentState = ShaderState.Original; } if (shaderState == ghostMaterialState.CurrentState) { return; } for (int num3 = 0; num3 < ghostMaterialState.Renderers.Length; num3++) { Renderer val3 = ghostMaterialState.Renderers[num3]; if (!Object.op_Implicit((Object)(object)val3)) { continue; } Material[] array = (Material[])((num3 < ghostMaterialState.OriginalMaterials.Length && ghostMaterialState.OriginalMaterials[num3] != null) ? ((Array)ghostMaterialState.OriginalMaterials[num3]) : ((Array)Array.Empty<Material>())); if (array.Length == 0) { continue; } if (shaderState == ShaderState.Original) { val3.sharedMaterials = array; continue; } int num4 = array.Length; Material[] array2 = (Material[])(object)new Material[num4]; for (int num5 = 0; num5 < num4; num5++) { Material val4 = array[num5]; if (!Object.op_Implicit((Object)(object)val4)) { array2[num5] = null; } else { array2[num5] = GetGhostMaterial(val4, shaderState); } } val3.sharedMaterials = array2; val3.shadowCastingMode = (ShadowCastingMode)0; } ghostMaterialState.CurrentState = shaderState; } private static Material GetGhostMaterial(Material originalMaterial, ShaderState shaderState) { //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_004f: Expected O, but got Unknown //IL_007e: 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_0083: 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) float value = GhostBuildPlugin.TransparencyConfig.Value; value *= value; Dictionary<Material, Material> dictionary = ((shaderState == ShaderState.Supported) ? SupportedMaterialCache : UnsupportedMaterialCache); if (dictionary.TryGetValue(originalMaterial, out var value2)) { return value2; } value2 = new Material(originalMaterial) { name = $"{((Object)originalMaterial).name} ({shaderState}Ghost)" }; value2.SetOverrideTag("RenderType", "Transparent"); value2.shader = PlanShader; Color color = ((shaderState == ShaderState.Supported) ? GhostBuildPlugin.SupportedGhostColorConfig.Value : GhostBuildPlugin.UnsupportedColorConfig.Value); color.a *= value; value2.color = color; value2.EnableKeyword("_EMISSION"); value2.DisableKeyword("DIRECTIONAL"); dictionary[originalMaterial] = value2; return value2; } internal static void SetEmissionColor(GameObject gameObject, Color color) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) foreach (Renderer renderer in GetRenderers(gameObject)) { if (!((Object)(object)renderer == (Object)null)) { Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials != null && sharedMaterials.Length != 0) { SetEmissionColor(sharedMaterials, color); renderer.sharedMaterials = sharedMaterials; } } } } private static void SetEmissionColor(Material[] sharedMaterials, Color color) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) foreach (Material val in sharedMaterials) { if (Object.op_Implicit((Object)(object)val) && val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", color); } } } public static Texture2D FromHeightmap(Heightmap terrain) { //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) return FromHeightmap(terrain, Color.gray, Color.black); } public static Texture2D FromHeightmap(Heightmap terrain, Color bandColor, Color bkgColor) { //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_001e: Expected O, but got Unknown //IL_0039: 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_018b: 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) int width = terrain.m_width; int width2 = terrain.m_width; Texture2D val = new Texture2D(width, width2) { anisoLevel = 16 }; Color[] array = (Color[])(object)new Color[width * width2]; for (int i = 0; i < width2; i++) { for (int j = 0; j < width; j++) { array[i * width + j] = bkgColor; } } float num = 1f; float num2 = 0f; for (int k = 0; k < width2; k++) { for (int l = 0; l < width; l++) { float height = terrain.GetHeight(l, k); if (num > height) { num = height; } if (num2 < height) { num2 = height; } } } float num3 = 1f; List<float> list = new List<float>(); for (float num4 = num + num3; num4 < num2; num4 += num3) { list.Add(num4); } bool[,] array2 = new bool[width, width2]; for (int m = 0; m < list.Count; m++) { for (int n = 0; n < width2; n++) { for (int num5 = 0; num5 < width; num5++) { array2[num5, n] = terrain.GetHeight(num5, n) >= list[m]; } } for (int num6 = 1; num6 < width2 - 1; num6++) { for (int num7 = 1; num7 < width - 1; num7++) { if (array2[num7, num6] && (!array2[num7 - 1, num6] || !array2[num7 + 1, num6] || !array2[num7, num6 - 1] || !array2[num7, num6 + 1])) { int num8 = (width2 - num6 - 1) * width + (width - num7 - 1); array[num8] = bandColor; } } } } val.SetPixels(array); val.Apply(); return val; } } public class SnapGizmoManager : MonoBehaviour { private GameObject _lastGhost; private readonly List<Vector3> _ghostSnapLocalOffsets = new List<Vector3>(); private readonly List<Vector3> _nearbySnapWorldPositions = new List<Vector3>(); private static readonly List<Transform> SnapPointsBuffer = new List<Transform>(); private static readonly List<Piece> SnapPiecesBuffer = new List<Piece>(); private Mesh _outerMesh; private Mesh _innerMesh; private Material _ghostMat; private Material _nearbyMat; private float _cachedInnerRadius = -1f; private float _cachedOuterRadius = -1f; private Color _cachedGhostColor; private Color _cachedNearbyColor; private const float RecalcPosThresholdSqr = 0.01f; private const float RecalcAngleThreshold = 1f; private Vector3 _lastGhostPos; private Quaternion _lastGhostRot; private void Start() { _outerMesh = null; _innerMesh = null; _ghostMat = null; _nearbyMat = null; } private void Update() { //IL_0080: 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_008c: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_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_00bb: 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_00dd: 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_00e4: 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_011d: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_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_017e: 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_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: 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_0229: Unknown result type (might be due to invalid IL or missing references) if (GhostBuildPlugin.ShowSnapGizmos.Value.IsOff() && GhostBuildPlugin.ShowNearbySnapGizmos.Value.IsOff()) { ClearAll(); return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { ClearAll(); return; } if (!Object.op_Implicit((Object)(object)localPlayer.m_buildPieces)) { ClearAll(); return; } GameObject placementGhost = localPlayer.m_placementGhost; if (!Object.op_Implicit((Object)(object)placementGhost)) { ClearAll(); return; } EnsureMeshesAndMaterials(); bool num = (Object)(object)placementGhost != (Object)(object)_lastGhost; Vector3 position = placementGhost.transform.position; Quaternion rotation = placementGhost.transform.rotation; int num2; if (Object.op_Implicit((Object)(object)_lastGhost)) { Vector3 val = position - _lastGhostPos; if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f)) { num2 = ((Quaternion.Angle(rotation, _lastGhostRot) > 1f) ? 1 : 0); goto IL_00d1; } } num2 = 1; goto IL_00d1; IL_00d1: bool flag = (byte)num2 != 0; if (num) { _lastGhost = placementGhost; _lastGhostPos = position; _lastGhostRot = rotation; RebuildGhostLocalSnapOffsets(placementGhost); if (GhostBuildPlugin.ShowNearbySnapGizmos.Value.IsOn()) { RebuildNearbySnaps(position); } else { _nearbySnapWorldPositions.Clear(); } } else if (flag) { _lastGhostPos = position; _lastGhostRot = rotation; if (GhostBuildPlugin.ShowNearbySnapGizmos.Value.IsOn()) { RebuildNearbySnaps(position); } else { _nearbySnapWorldPositions.Clear(); } } if (GhostBuildPlugin.ShowSnapGizmos.Value.IsOn()) { foreach (Vector3 ghostSnapLocalOffset in _ghostSnapLocalOffsets) { Matrix4x4 val2 = Matrix4x4.TRS(placementGhost.transform.TransformPoint(ghostSnapLocalOffset), Quaternion.identity, Vector3.one); Graphics.DrawMesh(_outerMesh, val2, _ghostMat, 0); Graphics.DrawMesh(_innerMesh, val2, _ghostMat, 0); } } if (!GhostBuildPlugin.ShowNearbySnapGizmos.Value.IsOn()) { return; } foreach (Vector3 nearbySnapWorldPosition in _nearbySnapWorldPositions) { Matrix4x4 val3 = Matrix4x4.TRS(nearbySnapWorldPosition, Quaternion.identity, Vector3.one); Graphics.DrawMesh(_outerMesh, val3, _nearbyMat, 0); Graphics.DrawMesh(_innerMesh, val3, _nearbyMat, 0); } } private void ClearAll() { _lastGhost = null; _ghostSnapLocalOffsets.Clear(); _nearbySnapWorldPositions.Clear(); } private void EnsureMeshesAndMaterials() { //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_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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_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_0137: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.01f, GhostBuildPlugin.SnapGizmoInnerRadius.Value); float num2 = Mathf.Max(num + 0.001f, GhostBuildPlugin.SnapGizmoOuterRadius.Value); Color value = GhostBuildPlugin.SnapGizmoGhostColor.Value; Color value2 = GhostBuildPlugin.SnapGizmoNearbyColor.Value; if (!Object.op_Implicit((Object)(object)_innerMesh) || !Mathf.Approximately(num, _cachedInnerRadius)) { _innerMesh = GizmoMeshCache.GetArcMesh(num); _cachedInnerRadius = num; } if (!Object.op_Implicit((Object)(object)_outerMesh) || !Mathf.Approximately(num2, _cachedOuterRadius)) { _outerMesh = GizmoMeshCache.GetArcMesh(num2); _cachedOuterRadius = num2; } if (!Object.op_Implicit((Object)(object)_ghostMat)) { _ghostMat = new Material(Shader.Find("Sprites/Default")); } if (!Object.op_Implicit((Object)(object)_nearbyMat)) { _nearbyMat = new Material(Shader.Find("Sprites/Default")); } if (Object.op_Implicit((Object)(object)_ghostMat) && _ghostMat.color != value) { _ghostMat.color = value; _cachedGhostColor = value; } if (!(_nearbyMat.color == value2)) { _nearbyMat.color = value2; _cachedNearbyColor = value2; } } private void RebuildGhostLocalSnapOffsets(GameObject ghost) { //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) _ghostSnapLocalOffsets.Clear(); Piece val = default(Piece); if (!ghost.TryGetComponent<Piece>(ref val)) { return; } List<Transform> list = new List<Transform>(); val.GetSnapPoints(list); foreach (Transform item in list) { if (Object.op_Implicit((Object)(object)item)) { _ghostSnapLocalOffsets.Add(ghost.transform.InverseTransformPoint(item.position)); } } } private void RebuildNearbySnaps(Vector3 center) { //IL_0034: 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) _nearbySnapWorldPositions.Clear(); SnapPointsBuffer.Clear(); SnapPiecesBuffer.Clear(); float num = Mathf.Max(0.1f, GhostBuildPlugin.SnapGizmoNearbyRadius.Value); Piece.GetSnapPoints(center, num, SnapPointsBuffer, SnapPiecesBuffer); foreach (Transform item in SnapPointsBuffer) { if (Object.op_Implicit((Object)(object)item)) { _nearbySnapWorldPositions.Add(item.position); } } } } public static class GhostBuildManager { public static int m_planLayer = LayerMask.NameToLayer("piece_nonsolid"); public static int m_placeRayMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "vehicle" }); internal static GameObject ghostPieceInformation = null; internal static TMP_Text m_buildSelection = null; internal static TMP_Text m_pieceDescription = null; internal static Image m_buildIcon = null; internal static Image m_snappingIcon = null; internal static GameObject[] m_requirementItems = Array.Empty<GameObject>(); internal static Piece CachedPiece = null; internal static Vector2Int CachedSelectedPieceIndex = Vector2Int.zero; public static readonly List<Piece> GhostPieces = new List<Piece>(); public static readonly Dictionary<Piece, Piece> GhostPrefabs = new Dictionary<Piece, Piece>(); private static readonly List<Type> typesToDestroyInChildren = new List<Type>(16) { typeof(Joint), typeof(Rigidbody), typeof(ParticleSystemForceField), typeof(Demister), typeof(TerrainModifier), typeof(GuidePoint), typeof(Light), typeof(LightLod), typeof(LineRenderer), typeof(LightFlicker), typeof(WispSpawner), typeof(Ship), typeof(Plant), typeof(Interactable), typeof(Hoverable), typeof(EffectArea) }; private static readonly List<Type> TypesToKeepInChildren = new List<Type>(7) { typeof(ZNetView), typeof(WearNTear), typeof(Piece), typeof(Interactable), typeof(Hoverable), typeof(GhostBuildPiece), typeof(ItemDrop) }; public static bool SuppressTagging { get; internal set; } public static bool CanToggleGhost { get; private set; } public static bool IsGhostActive { get; internal set; } public static bool AutoGhostEngaged { get; private set; } public static void OnEnterPlaceMode() { CanToggleGhost = true; } public static void OnExitPlaceMode() { CanToggleGhost = false; if (IsGhostActive) { ToggleGhost(); } ShaderHelper.ClearCache(); } public static void RegisterGhost(Piece p, Piece prefab) { if ((Object)(object)p != (Object)null && !GhostPieces.Contains(p)) { GhostPieces.Add(p); GhostPrefabs[p] = prefab; } } public static void UnregisterGhost(Piece p) { GhostPrefabs.Remove(p); GhostPieces.Remove(p); } public static void ToggleGhost(bool auto = false) { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && (IsGhostActive || CanToggleGhost)) { IsGhostActive = !IsGhostActive; AutoGhostEngaged = IsGhostActive && auto; PlayerHaveRequirementsPatch.ResetAutoGhostTracking(); if (GhostBuildPlugin.ShowGhostToggleMessages.Value.IsOn()) { ((Character)localPlayer).Message((MessageType)2, IsGhostActive ? Localization.instance.Localize("$enemy_ghost $piece_guardstone_active") : Localization.instance.Localize("$enemy_ghost $piece_guardstone_inactive"), 0, (Sprite)null, false); } localPlayer.UpdateAvailablePiecesList(); localPlayer.SetupPlacementGhost(); ApplyToCurrentGhost(); } } public static void ApplyToCurrentGhost() { GameObject val = Player.m_localPlayer?.m_placementGhost; if (Object.op_Implicit((Object)(object)val)) { ShaderHelper.ShaderState shaderState = ((!IsGhostActive) ? ShaderHelper.ShaderState.Original : ShaderHelper.ShaderState.Supported); ShaderHelper.UpdateTextures(val, shaderState); WearNTear val2 = default(WearNTear); if (IsGhostActive && val.TryGetComponent<WearNTear>(ref val2)) { val2.Highlight(); } } } public static void UpdateGhostPieces() { WearNTear val = default(WearNTear); foreach (Piece ghostPiece in GhostPieces) { if (!((Object)(object)ghostPiece == (Object)null) && !((Object)(object)((Component)ghostPiece).gameObject == (Object)null)) { bool flag = true; if (((Component)ghostPiece).TryGetComponent<WearNTear>(ref val)) { flag = val.HaveSupport(); } ShaderHelper.ShaderState shaderState = ((!flag) ? ShaderHelper.ShaderState.UnSupported : ShaderHelper.ShaderState.Supported); ShaderHelper.UpdateTextures(((Component)ghostPiece).gameObject, shaderState); } } } public static void ApplyGhostVisual(Piece piece) { if (!Object.op_Implicit((Object)(object)piece)) { return; } ZNetView component = ((Component)piece).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.GetZDO().GetBool("GhostBuild", false)) { return; } GhostBuildPiece ghostBuildPiece = default(GhostBuildPiece); if (!((Component)piece).TryGetComponent<GhostBuildPiece>(ref ghostBuildPiece)) { ghostBuildPiece = ((Component)piece).gameObject.AddComponent<GhostBuildPiece>(); } ghostBuildPiece.m_piece = piece; if (!Object.op_Implicit((Object)(object)ghostBuildPiece.OriginalPiece) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { string prefabName = Utils.GetPrefabName(((Object)piece).name); GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); if (Object.op_Implicit((Object)(object)prefab)) { Piece val = prefab.GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)val) && GhostPieceRegistry.TryGetReal(val, out Piece real) && Object.op_Implicit((Object)(object)real)) { val = real; } ghostBuildPiece.OriginalPiece = val; } } DisablePiece(((Component)piece).gameObject); ShaderHelper.UpdateTextures(((Component)piece).gameObject, ShaderHelper.ShaderState.Supported); Transform[] componentsInChildren = ((Component)piece).gameObject.GetComponentsInChildren<Transform>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.layer = m_planLay