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 VeiledRecipes v1.1.5
VeiledRecipes.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; 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.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("VeiledRecipes")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("VeiledRecipes")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.1.5")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.5.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; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace VeiledRecipes { [BepInPlugin("sighsorry.VeiledRecipes", "VeiledRecipes", "1.1.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class VeiledRecipesPlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } internal const string ModName = "VeiledRecipes"; internal const string ModVersion = "1.1.5"; internal const string Author = "sighsorry"; public const string ModGUID = "sighsorry.VeiledRecipes"; private static string ConfigFileName = "sighsorry.VeiledRecipes.cfg"; private static string ConfigFileFullPath; private readonly Harmony _harmony = new Harmony("sighsorry.VeiledRecipes"); public static readonly ManualLogSource PluginLogger; private static readonly ConfigSync ConfigSync; private FileSystemWatcher? _watcher; private readonly object _reloadLock = new object(); private DateTime _lastConfigReloadTime; private string? _lastConfigFileText; private static readonly TimeSpan ConfigReloadDebounce; private static ConfigEntry<Toggle> _serverConfigLocked; internal static ConfigEntry<Toggle> ShowUnknownCraftingRecipes; internal static ConfigEntry<Toggle> ShowUnknownBuildPieces; internal static ConfigEntry<Toggle> RequireStationLevelForUnknownCraftingRecipes; internal static ConfigEntry<Toggle> RequireStationKnowledgeForUnknownBuildPieces; internal static ConfigEntry<Toggle> RequireStationInteractionForRecipeUnlock; internal static ConfigEntry<Toggle> EnableStationProximityDiscovery; internal static ConfigEntry<string> RecipePreviewPrefabBlacklist; internal static ConfigEntry<string> PiecePreviewPrefabBlacklist; internal static ConfigEntry<string> RequirementPreviewPrefabBlacklist; internal static ConfigEntry<string> UnknownNameText; internal static ConfigEntry<string> UnknownDescriptionText; internal static ConfigEntry<string> UnknownRequirementText; internal static ConfigEntry<bool> GroupUnknownRecipePreviewsBelowKnownRecipes; internal static ConfigEntry<bool> ShowRecipeUnlockNotifications; internal static ConfigEntry<bool> ShowPieceUnlockNotifications; internal static ConfigEntry<bool> ShowSkillLevelUpNotificationAndEffect; public void Awake() { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { _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); ShowUnknownCraftingRecipes = config("2 - Veiled Recipes", "Show Unknown Crafting Recipes", Toggle.On, "Shows crafting recipes at the relevant crafting station before the recipe is fully unlocked."); ShowUnknownBuildPieces = config("2 - Veiled Recipes", "Show Unknown Build Pieces", Toggle.On, "Shows build pieces in build-piece tables before the piece is fully unlocked."); RequireStationLevelForUnknownCraftingRecipes = config("2 - Veiled Recipes", "Require Station Level For Unknown Crafting Recipes", Toggle.On, "If on, unknown crafting recipe previews are shown only when the current crafting station meets the recipe's required station level."); RequireStationKnowledgeForUnknownBuildPieces = config("2 - Veiled Recipes", "Require Station Knowledge For Unknown Build Pieces", Toggle.On, "If on, unknown build-piece previews that require a crafting station are shown only after the player knows that station."); RequireStationInteractionForRecipeUnlock = config("2 - Veiled Recipes", "Require Station Interaction For Recipe Unlock", Toggle.On, "If on, recipes that require a crafting station unlock only after the player has interacted with the required station level. If off, Valheim's normal station discovery behavior is used for recipe station knowledge."); EnableStationProximityDiscovery = config("2 - Veiled Recipes", "Enable Station Proximity Discovery", Toggle.On, "If on, Valheim's normal crafting station discovery radius is used. If off, walking near a crafting station does not discover it; interacting with the station is required."); RecipePreviewPrefabBlacklist = config("2 - Veiled Recipes", "Recipe Preview Prefab Blacklist", "", "Comma-separated item prefab names whose unknown crafting recipe previews should never be shown. This does not hide recipes after they are actually unlocked. Example: ArmorIronLegs, SwordIron"); PiecePreviewPrefabBlacklist = config("2 - Veiled Recipes", "Piece Preview Prefab Blacklist", "", "Comma-separated piece prefab names whose unknown build piece previews should never be shown. This does not hide pieces after they are actually unlocked. Example: piece_workbench_ext1, piece_chest"); RequirementPreviewPrefabBlacklist = config("2 - Veiled Recipes", "Requirement Preview Prefab Blacklist", "SwordCheat, SledgeCheat", "Comma-separated ingredient/resource prefab names that prevent unknown crafting recipe and build-piece previews from being shown when required by that recipe or piece. This does not hide anything after it is actually unlocked."); UnknownNameText = config("3 - Display", "Unknown Name Text", "???", "Text shown for unknown recipe and piece names."); UnknownDescriptionText = config("3 - Display", "Unknown Description Text", "Not enough info", "Text shown for unknown recipe and piece descriptions."); UnknownRequirementText = config("3 - Display", "Unknown Requirement Text", "?", "Text shown for unknown requirement names, amounts, and station levels."); GroupUnknownRecipePreviewsBelowKnownRecipes = config("3 - Display", "Group Unknown Recipe Previews Below Known Recipes", value: true, "If enabled, unknown crafting recipe previews are grouped below actually unlocked recipes in crafting station recipe lists.", synchronizedSetting: false); ShowRecipeUnlockNotifications = config("4 - Client Notifications", "Show Recipe Unlock Notifications", value: true, "Shows Valheim's unlock popup when a crafting recipe is learned.", synchronizedSetting: false); ShowPieceUnlockNotifications = config("4 - Client Notifications", "Show Piece Unlock Notifications", value: false, "Shows Valheim's unlock popup when a build piece or dish is learned.", synchronizedSetting: false); ShowSkillLevelUpNotificationAndEffect = config("4 - Client Notifications", "Show Skill Level Up Notification/Effect", value: true, "Shows the skill level-up message and VFX/SFX. When disabled, all $msg_skillup alarms and Player.OnSkillLevelup effects are hidden.", synchronizedSetting: false); VeiledRecipeInfinityHammerCompat.RegisterKnownPieceOverrides(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); VeiledRecipeAaaCraftingCompat.Initialize(); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; SetupWatcher(); ((BaseUnityPlugin)this).Config.Save(); _lastConfigFileText = ReadFileTextIfExists(ConfigFileFullPath); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void OnDestroy() { ((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged; try { SaveWithRespectToConfigSet(); } finally { _watcher?.Dispose(); } } private static void OnSettingChanged(object sender, SettingChangedEventArgs args) { VeiledRecipeBuildUiRefreshPatch.Invalidate(); } 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 - _lastConfigReloadTime < ConfigReloadDebounce) { return; } _lastConfigReloadTime = now; lock (_reloadLock) { if (!File.Exists(ConfigFileFullPath)) { PluginLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { string b = File.ReadAllText(ConfigFileFullPath); if (!string.Equals(_lastConfigFileText, b, StringComparison.Ordinal)) { PluginLogger.LogDebug((object)"Reloading configuration..."); SaveWithRespectToConfigSet(reload: true); _lastConfigFileText = ReadFileTextIfExists(ConfigFileFullPath); PluginLogger.LogInfo((object)"Configuration reload complete."); } } catch (Exception ex) { PluginLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } } } private static string? ReadFileTextIfExists(string path) { if (!File.Exists(path)) { return null; } return File.ReadAllText(path); } private void SaveWithRespectToConfigSet(bool reload = false) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } ((BaseUnityPlugin)this).Config.Save(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), (AcceptableValueBase)null, Array.Empty<object>()); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } static VeiledRecipesPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; PluginLogger = Logger.CreateLogSource("VeiledRecipes"); ConfigSync = new ConfigSync("sighsorry.VeiledRecipes") { DisplayName = "VeiledRecipes", CurrentVersion = "1.1.5", MinimumRequiredVersion = "1.1.5" }; ConfigReloadDebounce = TimeSpan.FromSeconds(1.0); _serverConfigLocked = null; ShowUnknownCraftingRecipes = null; ShowUnknownBuildPieces = null; RequireStationLevelForUnknownCraftingRecipes = null; RequireStationKnowledgeForUnknownBuildPieces = null; RequireStationInteractionForRecipeUnlock = null; EnableStationProximityDiscovery = null; RecipePreviewPrefabBlacklist = null; PiecePreviewPrefabBlacklist = null; RequirementPreviewPrefabBlacklist = null; UnknownNameText = null; UnknownDescriptionText = null; UnknownRequirementText = null; GroupUnknownRecipePreviewsBelowKnownRecipes = null; ShowRecipeUnlockNotifications = null; ShowPieceUnlockNotifications = null; ShowSkillLevelUpNotificationAndEffect = null; } } internal static class VeiledRecipeConstants { internal const string StationInteractionPrefix = "VeiledRecipes.InteractedStation."; internal const string UnknownNameFallback = "???"; internal const string UnknownDescriptionFallback = "Not enough info"; internal const string UnknownRequirementFallback = "?"; internal const string NewRecipeMessage = "$msg_newrecipe"; internal const string NewPieceMessage = "$msg_newpiece"; internal const string NewDishMessage = "$msg_newdish"; internal const string SkillUpMessagePrefix = "$msg_skillup "; internal const string MissingRequirementMessage = "$msg_missingrequirement"; internal const string MenuNoneMessage = "$menu_none"; internal const string CloneSuffix = "(Clone)"; internal const string RecipeIconChild = "icon"; internal const string RecipeNameChild = "name"; internal const string DurabilityChild = "Durability"; internal const string QualityLevelChild = "QualityLevel"; internal const string RequirementIconChild = "res_icon"; internal const string RequirementNameChild = "res_name"; internal const string RequirementAmountChild = "res_amount"; internal static readonly char[] PrefabBlacklistSeparators = new char[5] { ',', ';', '|', '\n', '\r' }; } internal static class VeiledRecipeAaaCraftingCompat { internal const string PluginGuid = "Azumatt.AzuAntiArthriticCrafting"; private const string Namespace = "AzuAntiArthriticCrafting."; private static bool _loaded; private static PropertyInfo? _trackedRecipe; private static FieldInfo? _trackedPanel; private static readonly HashSet<GameObject> HiddenTrackedPanels = new HashSet<GameObject>(); private static GameObject? _tooltipRoot; private static TMP_Text? _tooltipTopic; private static TMP_Text? _tooltipText; private static bool _tooltipMasked; internal static void Initialize() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (_loaded || !Chainloader.PluginInfos.TryGetValue("Azumatt.AzuAntiArthriticCrafting", out var value) || (Object)(object)value.Instance == (Object)null) { return; } Harmony val = new Harmony("sighsorry.VeiledRecipes.AAA"); try { Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("AzuAntiArthriticCrafting.Handlers.RecipeHoverTooltip", throwOnError: true); Type type2 = assembly.GetType("AzuAntiArthriticCrafting.RecipeTracking.RecipeTrackerUI", throwOnError: true); Type type3 = assembly.GetType("AzuAntiArthriticCrafting.RecipeTracking.RecipeUI", throwOnError: true); _trackedRecipe = type3.GetProperty("Recipe") ?? throw new MissingMemberException(type3.FullName, "Recipe"); _trackedPanel = type3.GetField("recipeStub") ?? throw new MissingFieldException(type3.FullName, "recipeStub"); if (_trackedRecipe.PropertyType != typeof(Recipe) || _trackedPanel.FieldType != typeof(GameObject)) { throw new InvalidOperationException("Unsupported recipe tracker fields."); } Patch(val, type, "UpdateTextElements", Type.EmptyTypes, "TooltipPostfix"); Patch(val, type, "LateUpdate", Type.EmptyTypes, "TooltipLateUpdatePostfix"); Patch(val, type2, "AddSelectedRecipe", new Type[1] { typeof(Recipe) }, "AddTrackedRecipePrefix", prefix: true); Patch(val, type2, "ToggleUI", Type.EmptyTypes, "TrackerPostfix"); _loaded = true; VeiledRecipesPlugin.PluginLogger.LogInfo((object)"AAA Crafting compatibility enabled."); InitializePagination(assembly); } catch (Exception ex) { val.UnpatchSelf(); VeiledRecipesPlugin.PluginLogger.LogWarning((object)("AAA Crafting compatibility could not be enabled: " + ex.Message)); } } private static void Patch(Harmony harmony, Type type, string method, Type[] parameters, string handler, bool prefix = false) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(type, method, parameters, (Type[])null) ?? throw new MissingMethodException(type.FullName, method); HarmonyMethod val = new HarmonyMethod(typeof(VeiledRecipeAaaCraftingCompat), handler, (Type[])null); val.after = new string[1] { "Azumatt.AzuAntiArthriticCrafting" }; val.priority = 0; HarmonyMethod val2 = val; harmony.Patch((MethodBase)methodInfo, prefix ? val2 : null, prefix ? null : val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void InitializePagination(Assembly assembly) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown Harmony val = new Harmony("sighsorry.VeiledRecipes.AAA.Paging"); try { Type type = assembly.GetType("AzuAntiArthriticCrafting.Patches.PaginatorPatches+InventoryGuiUpdateRecipeListPatch", throwOnError: true); Type[] array = new Type[2] { typeof(InventoryGui), typeof(List<Recipe>).MakeByRefType() }; MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "Prefix", array, (Type[])null) ?? throw new MissingMethodException(type.FullName, "Prefix"); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(type, "Postfix", array, (Type[])null) ?? throw new MissingMethodException(type.FullName, "Postfix"); HarmonyMethod val2 = new HarmonyMethod(typeof(VeiledRecipeAaaCraftingCompat), "GroupBeforePagination", (Type[])null); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null); VeiledRecipesPlugin.PluginLogger.LogInfo((object)"AAA Crafting grouping before pagination enabled."); } catch (Exception ex) { val.UnpatchSelf(); VeiledRecipesPlugin.PluginLogger.LogWarning((object)("AAA Crafting full-list grouping could not be enabled; keeping page-local grouping: " + ex.Message)); } } private static IEnumerable<CodeInstruction> GroupBeforePagination(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { bool flag = __originalMethod.Name == "Prefix"; Type type = (flag ? typeof(Recipe) : typeof(RecipeDataPair)); MethodInfo operand = AccessTools.Method(typeof(VeiledRecipeAaaCraftingCompat), flag ? "SkipCraftRecipes" : "SkipRecipePairs", (Type[])null, (Type[])null); List<CodeInstruction> list = instructions.ToList(); int num = 0; foreach (CodeInstruction item in list) { if (!(item.opcode != OpCodes.Call) && item.operand is MethodInfo methodInfo && !(methodInfo.DeclaringType != typeof(Enumerable)) && !(methodInfo.Name != "Skip") && methodInfo.IsGenericMethod && !(methodInfo.GetGenericArguments()[0] != type) && methodInfo.GetParameters().Length == 2 && !(methodInfo.GetParameters()[1].ParameterType != typeof(int))) { item.operand = operand; num++; } } int num2 = ((!flag) ? 1 : 2); if (num != num2) { throw new InvalidOperationException($"Unsupported AAA {__originalMethod.Name} pagination: expected {num2} Skip calls, found {num}."); } return list; } private static IEnumerable<Recipe> SkipCraftRecipes(IEnumerable<Recipe> recipes, int count) { return SkipGrouped(recipes, count, (Player player, Recipe recipe) => VeiledRecipeState.IsUnknownRecipePreview(player, recipe)); } private static IEnumerable<RecipeDataPair> SkipRecipePairs(IEnumerable<RecipeDataPair> pairs, int count) { return SkipGrouped(pairs, count, (Player player, RecipeDataPair pair) => VeiledRecipeState.GetRecipeVisibilityState(player, ((RecipeDataPair)(ref pair)).Recipe, ((RecipeDataPair)(ref pair)).ItemData) == VeiledRecipeVisibilityState.UnknownPreview); } private static IEnumerable<T> SkipGrouped<T>(IEnumerable<T> source, int count, Func<Player, T, bool> isUnknown) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !VeiledRecipeState.GroupUnknownRecipePreviewsBelowKnownRecipes) { return source.Skip(count); } List<T> list = new List<T>(); List<T> list2 = new List<T>(); foreach (T item in source) { (isUnknown(localPlayer, item) ? list2 : list).Add(item); } list.AddRange(list2); return list.Skip(count); } internal static void MaskRecipeList(InventoryGui gui, Player player) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (!_loaded) { return; } foreach (RecipeDataPair availableRecipe in gui.m_availableRecipes) { RecipeDataPair current = availableRecipe; if ((Object)(object)((RecipeDataPair)(ref current)).InterfaceElement != (Object)null && VeiledRecipeState.ShouldMaskRecipe(player, ((RecipeDataPair)(ref current)).Recipe, ((RecipeDataPair)(ref current)).ItemData)) { InventoryGuiAddRecipeToListPatch.MaskRecipeListElement(((RecipeDataPair)(ref current)).InterfaceElement, ((RecipeDataPair)(ref current)).Recipe); } } } private static bool ShouldMaskTooltip(Component tooltip) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)tooltip == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null) { return false; } foreach (RecipeDataPair availableRecipe in instance.m_availableRecipes) { RecipeDataPair current = availableRecipe; if ((Object)(object)((RecipeDataPair)(ref current)).InterfaceElement == (Object)(object)tooltip.gameObject) { return VeiledRecipeState.ShouldMaskRecipe(localPlayer, ((RecipeDataPair)(ref current)).Recipe, ((RecipeDataPair)(ref current)).ItemData); } } return false; } private static void TooltipPostfix(Component __instance, GameObject ___m_tooltip, string ___m_topic, string ___m_text) { UpdateTooltip(__instance, ___m_tooltip, ___m_topic, ___m_text); } private static void TooltipLateUpdatePostfix(Component __instance, Component ___m_current, GameObject ___m_tooltip, string ___m_topic, string ___m_text) { if ((Object)(object)__instance == (Object)(object)___m_current) { UpdateTooltip(__instance, ___m_tooltip, ___m_topic, ___m_text); } } private static void UpdateTooltip(Component owner, GameObject root, string? topic, string? text) { if ((Object)(object)root == (Object)null) { return; } if ((Object)(object)_tooltipRoot != (Object)(object)root) { _tooltipRoot = root; Transform obj = Utils.FindChild(root.transform, "Topic", (IterativeSearchType)0); _tooltipTopic = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null); Transform obj2 = Utils.FindChild(root.transform, "Text", (IterativeSearchType)0); _tooltipText = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null); _tooltipMasked = false; } bool flag = ShouldMaskTooltip(owner); if (flag || _tooltipMasked) { if ((Object)(object)_tooltipTopic != (Object)null) { _tooltipTopic.text = (flag ? VeiledRecipeState.UnknownNameText : Localization.instance.Localize(topic ?? "")); } if ((Object)(object)_tooltipText != (Object)null) { _tooltipText.text = (flag ? VeiledRecipeState.UnknownDescriptionText : Localization.instance.Localize(text ?? "")); } _tooltipMasked = flag; } } private static bool AddTrackedRecipePrefix(Recipe recipe) { Player localPlayer = Player.m_localPlayer; InventoryGui instance = InventoryGui.instance; ItemData targetItem = (((Object)(object)instance != (Object)null && (Object)(object)((RecipeDataPair)(ref instance.m_selectedRecipe)).Recipe == (Object)(object)recipe) ? ((RecipeDataPair)(ref instance.m_selectedRecipe)).ItemData : null); if ((Object)(object)localPlayer == (Object)null || !VeiledRecipeState.ShouldMaskRecipe(localPlayer, recipe, targetItem)) { return true; } ((Character)localPlayer).Message((MessageType)2, VeiledRecipeState.UnknownDescriptionText, 0, (Sprite)null, false); return false; } private static void TrackerPostfix(IEnumerable ___RecipeUIs) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || _trackedRecipe == null || _trackedPanel == null) { return; } HiddenTrackedPanels.RemoveWhere((GameObject panel) => (Object)(object)panel == (Object)null); foreach (object ___RecipeUI in ___RecipeUIs) { Component val = (Component)((___RecipeUI is Component) ? ___RecipeUI : null); if (val == null || (Object)(object)val == (Object)null) { continue; } object? value = _trackedRecipe.GetValue(___RecipeUI); Recipe val2 = (Recipe)((value is Recipe) ? value : null); if (val2 == null) { continue; } object? value2 = _trackedPanel.GetValue(___RecipeUI); GameObject val3 = (GameObject)((value2 is GameObject) ? value2 : null); if (val3 == null || (Object)(object)val3 == (Object)null) { continue; } if (VeiledRecipeState.RequiresRecipeKnowledge(localPlayer, val2)) { if (val3.activeSelf) { HiddenTrackedPanels.Add(val3); val3.SetActive(false); } } else if (HiddenTrackedPanels.Remove(val3)) { val3.SetActive(true); } } } } internal static class VeiledRecipeInfinityHammerCompat { private const string PluginGuid = "infinity_hammer"; private const string HammerSelectTypeName = "InfinityHammer.HammerSelect"; private const string SelectionTypeName = "InfinityHammer.Selection"; private const string BaseSelectionTypeName = "InfinityHammer.BaseSelection"; private static bool _initialized; private static bool _loaded; private static MethodInfo? _getSelectionMethod; private static MethodInfo? _getSelectedPieceMethod; private static PropertyInfo? _isToolProperty; private static object? _activeCommandSelection; internal static void RegisterKnownPieceOverrides() { VeiledRecipeState.RegisterKnownPieceOverride(IsKnownActiveSelectionPiece); } private static bool IsKnownActiveSelectionPiece(Piece piece) { if ((Object)(object)piece == (Object)null) { return false; } EnsureInitialized(); if (!_loaded || _getSelectionMethod == null || _getSelectedPieceMethod == null || _isToolProperty == null) { return false; } try { object obj = _getSelectionMethod.Invoke(null, null); if (obj == null) { _activeCommandSelection = null; return false; } object? obj2 = _getSelectedPieceMethod.Invoke(obj, null); Piece val = (Piece)((obj2 is Piece) ? obj2 : null); if ((Object)(object)val == (Object)null || val != piece) { return false; } if (IsToolSelection(obj) || obj == _activeCommandSelection) { return true; } if (!IsHammerSelectCommandOnStack()) { return false; } _activeCommandSelection = obj; return true; } catch (Exception ex) { VeiledRecipesPlugin.PluginLogger.LogDebug((object)("Infinity Hammer active selection check failed: " + ex.Message)); return false; } } private static bool IsToolSelection(object? selection) { if (selection != null) { object obj = _isToolProperty?.GetValue(selection); if (obj is bool) { return (bool)obj; } return false; } return false; } private static bool IsHammerSelectCommandOnStack() { StackFrame[] frames = new StackTrace().GetFrames(); for (int i = 0; i < frames.Length; i++) { string? obj = frames[i].GetMethod()?.DeclaringType?.FullName; if (obj != null && obj.StartsWith("InfinityHammer.HammerSelect", StringComparison.Ordinal)) { return true; } } return false; } private static void EnsureInitialized() { if (!_initialized) { _initialized = true; if (Chainloader.PluginInfos.TryGetValue("infinity_hammer", out var value)) { Assembly obj = ((object)value.Instance)?.GetType().Assembly; Type type = obj?.GetType("InfinityHammer.Selection", throwOnError: false); Type? obj2 = obj?.GetType("InfinityHammer.BaseSelection", throwOnError: false); _getSelectionMethod = type?.GetMethod("Get", BindingFlags.Static | BindingFlags.Public); _getSelectedPieceMethod = obj2?.GetMethod("GetSelectedPiece", BindingFlags.Instance | BindingFlags.Public); _isToolProperty = obj2?.GetProperty("IsTool", BindingFlags.Instance | BindingFlags.Public); _loaded = _getSelectionMethod != null && _getSelectedPieceMethod != null && _isToolProperty != null; } } } } internal static class VeiledRecipeState { private static readonly HashSet<string> RegisteredBuildPiecePrefabNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static ObjectDB? _registeredPieceObjectDb; private static int _registeredPieceItemCount = -1; private static readonly List<Func<Piece, bool>> KnownPieceOverrides = new List<Func<Piece, bool>>(); private static readonly HashSet<string> KnownPiecePrefabOverrides = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> KnownPieceTypeOverrides = new HashSet<string>(StringComparer.Ordinal); private static string _recipePreviewPrefabBlacklistRaw = ""; private static string _piecePreviewPrefabBlacklistRaw = ""; private static string _requirementPreviewPrefabBlacklistRaw = ""; private static HashSet<string> _recipePreviewPrefabBlacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static HashSet<string> _piecePreviewPrefabBlacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static HashSet<string> _requirementPreviewPrefabBlacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static bool ShowUnknownCraftingRecipes => IsOn(VeiledRecipesPlugin.ShowUnknownCraftingRecipes); internal static bool ShowUnknownBuildPieces => IsOn(VeiledRecipesPlugin.ShowUnknownBuildPieces); internal static bool RequireStationLevelForUnknownCraftingRecipes => IsOn(VeiledRecipesPlugin.RequireStationLevelForUnknownCraftingRecipes); internal static bool RequireStationKnowledgeForUnknownBuildPieces => IsOn(VeiledRecipesPlugin.RequireStationKnowledgeForUnknownBuildPieces); internal static bool RequireStationInteractionForRecipeUnlock => IsOn(VeiledRecipesPlugin.RequireStationInteractionForRecipeUnlock); internal static bool EnableStationProximityDiscovery => IsOn(VeiledRecipesPlugin.EnableStationProximityDiscovery); internal static string UnknownNameText => SafeText(VeiledRecipesPlugin.UnknownNameText, "???"); internal static string UnknownDescriptionText => SafeText(VeiledRecipesPlugin.UnknownDescriptionText, "Not enough info"); internal static string UnknownRequirementText => SafeText(VeiledRecipesPlugin.UnknownRequirementText, "?"); internal static bool GroupUnknownRecipePreviewsBelowKnownRecipes => VeiledRecipesPlugin.GroupUnknownRecipePreviewsBelowKnownRecipes?.Value ?? true; internal static bool ShowRecipeUnlockNotifications => VeiledRecipesPlugin.ShowRecipeUnlockNotifications?.Value ?? true; internal static bool ShowPieceUnlockNotifications => VeiledRecipesPlugin.ShowPieceUnlockNotifications?.Value ?? false; internal static bool ShowSkillLevelUpNotificationAndEffect => VeiledRecipesPlugin.ShowSkillLevelUpNotificationAndEffect?.Value ?? true; internal static bool IsRecipeActuallyKnown(Player player, Recipe recipe) { if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null) { return false; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)28)) { return true; } if (player.m_noPlacementCost || player.NoCostCheat()) { return true; } return player.IsRecipeKnown(recipe.m_item.m_itemData.m_shared.m_name); } internal static bool IsPieceActuallyKnown(Player player, Piece piece) { if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null) { return false; } if (piece.m_repairPiece || piece.m_removePiece) { return true; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)26)) { return true; } if (player.m_noPlacementCost || player.NoCostCheat()) { return true; } if (!player.IsRecipeKnown(piece.m_name)) { return HasKnownPieceOverride(piece); } return true; } internal static bool RequiresRecipeKnowledge(Player player, Recipe recipe) { if ((Object)(object)player != (Object)null && (Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && !IsRecipeActuallyKnown(player, recipe)) { return HasDiscoverableCraftingRecipe(player, recipe); } return false; } internal static bool ShouldMaskRecipe(Player player, Recipe recipe, ItemData? targetItem = null) { if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || IsRecipeActuallyKnown(player, recipe)) { return false; } if (HasDiscoverableCraftingRecipe(player, recipe)) { return true; } if (targetItem == null) { return !IsBackedByOwnedItem(player, recipe); } return false; } internal static bool ShouldMaskPiece(Player player, Piece piece) { if ((Object)(object)player != (Object)null && (Object)(object)piece != (Object)null && !IsPieceActuallyKnown(player, piece)) { return HasRegisteredBuildPiece(piece); } return false; } internal static void RegisterBuildPieceTable(PieceTable table) { if ((Object)(object)table == (Object)null) { return; } ResetRegisteredBuildPiecesIfObjectDbChanged(); foreach (GameObject piece in table.m_pieces) { if (!((Object)(object)piece == (Object)null)) { string prefabName = Utils.GetPrefabName(piece); if (!string.IsNullOrEmpty(prefabName)) { RegisteredBuildPiecePrefabNames.Add(prefabName); } } } } private static bool HasDiscoverableCraftingRecipe(Player player, Recipe recipe) { if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)recipe.m_item == (Object)null) { return false; } string name = recipe.m_item.m_itemData.m_shared.m_name; foreach (Recipe recipe2 in ObjectDB.instance.m_recipes) { if ((Object)(object)recipe2 != (Object)null && (Object)(object)recipe2.m_item != (Object)null && recipe2.m_item.m_itemData.m_shared.m_name == name && IsRecipeEnabledForPlayer(player, recipe2)) { return true; } } return false; } private static bool IsBackedByOwnedItem(Player player, Recipe recipe) { ItemData itemData = recipe.m_item.m_itemData; if (itemData != null) { return ((Humanoid)player).GetInventory().ContainsItem(itemData); } return false; } private static bool HasRegisteredBuildPiece(Piece piece) { RefreshRegisteredBuildPieces(); string prefabName = Utils.GetPrefabName(((Component)piece).gameObject); if (!string.IsNullOrEmpty(prefabName)) { return RegisteredBuildPiecePrefabNames.Contains(prefabName); } return false; } private static void RefreshRegisteredBuildPieces() { ObjectDB instance = ObjectDB.instance; ResetRegisteredBuildPiecesIfObjectDbChanged(); if ((Object)(object)instance == (Object)null || _registeredPieceItemCount == instance.m_items.Count) { return; } foreach (GameObject item in instance.m_items) { ItemDrop val = (((Object)(object)item == (Object)null) ? null : item.GetComponent<ItemDrop>()); if ((Object)(object)val?.m_itemData.m_shared.m_buildPieces != (Object)null) { RegisterBuildPieceTable(val.m_itemData.m_shared.m_buildPieces); } } _registeredPieceItemCount = instance.m_items.Count; } private static void ResetRegisteredBuildPiecesIfObjectDbChanged() { ObjectDB instance = ObjectDB.instance; if (_registeredPieceObjectDb != instance) { _registeredPieceObjectDb = instance; _registeredPieceItemCount = -1; RegisteredBuildPiecePrefabNames.Clear(); } } internal static bool IsMaterialKnown(Player player, Requirement requirement) { if ((Object)(object)player == (Object)null || requirement == null || (Object)(object)requirement.m_resItem == (Object)null) { return false; } return player.IsKnownMaterial(requirement.m_resItem.m_itemData.m_shared.m_name); } private static bool DlcInstalled(string dlc) { if (!string.IsNullOrEmpty(dlc) && !((Object)(object)DLCMan.instance == (Object)null)) { return DLCMan.instance.IsDLCInstalled(dlc); } return true; } internal static void RegisterKnownPieceOverride(Func<Piece, bool> predicate) { if (predicate != null && !KnownPieceOverrides.Contains(predicate)) { KnownPieceOverrides.Add(predicate); VeiledRecipeBuildUiRefreshPatch.Invalidate(); } } internal static void UnregisterKnownPieceOverride(Func<Piece, bool> predicate) { if (predicate != null && KnownPieceOverrides.Remove(predicate)) { VeiledRecipeBuildUiRefreshPatch.Invalidate(); } } internal static void RegisterKnownPiecePrefabOverride(string prefabName) { if (!string.IsNullOrWhiteSpace(prefabName) && KnownPiecePrefabOverrides.Add(prefabName.Trim())) { VeiledRecipeBuildUiRefreshPatch.Invalidate(); } } internal static void UnregisterKnownPiecePrefabOverride(string prefabName) { if (!string.IsNullOrWhiteSpace(prefabName) && KnownPiecePrefabOverrides.Remove(prefabName.Trim())) { VeiledRecipeBuildUiRefreshPatch.Invalidate(); } } internal static void RegisterKnownPieceTypeOverride(string typeName) { if (!string.IsNullOrWhiteSpace(typeName) && KnownPieceTypeOverrides.Add(typeName.Trim())) { VeiledRecipeBuildUiRefreshPatch.Invalidate(); } } internal static void UnregisterKnownPieceTypeOverride(string typeName) { if (!string.IsNullOrWhiteSpace(typeName) && KnownPieceTypeOverrides.Remove(typeName.Trim())) { VeiledRecipeBuildUiRefreshPatch.Invalidate(); } } private static bool HasKnownPieceOverride(Piece piece) { if ((Object)(object)piece == (Object)null) { return false; } string prefabName = Utils.GetPrefabName(((Component)piece).gameObject); if (!string.IsNullOrEmpty(prefabName) && KnownPiecePrefabOverrides.Contains(prefabName)) { return true; } string fullName = ((object)piece).GetType().FullName; if (!string.IsNullOrEmpty(fullName) && KnownPieceTypeOverrides.Contains(fullName)) { return true; } foreach (Func<Piece, bool> knownPieceOverride in KnownPieceOverrides) { try { if (knownPieceOverride(piece)) { return true; } } catch (Exception ex) { VeiledRecipesPlugin.PluginLogger.LogDebug((object)("Known piece override failed for '" + prefabName + "': " + ex.Message)); } } return false; } private static bool IsOn(ConfigEntry<VeiledRecipesPlugin.Toggle> entry) { if (entry != null) { return entry.Value == VeiledRecipesPlugin.Toggle.On; } return false; } private static string SafeText(ConfigEntry<string> entry, string fallback) { if (entry == null || string.IsNullOrEmpty(entry.Value)) { return fallback; } return entry.Value; } private static bool IsRecipePreviewBlacklisted(Recipe recipe) { HashSet<string> recipePreviewPrefabBlacklist = GetRecipePreviewPrefabBlacklist(); if (recipePreviewPrefabBlacklist.Count > 0) { string[] obj = new string[4] { ((Object)recipe).name, null, null, null }; ItemDrop item = recipe.m_item; obj[1] = ((item != null) ? ((Object)item).name : null); ItemDrop item2 = recipe.m_item; object obj2; if (item2 == null) { obj2 = null; } else { GameObject gameObject = ((Component)item2).gameObject; obj2 = ((gameObject != null) ? ((Object)gameObject).name : null); } obj[2] = (string)obj2; ItemDrop item3 = recipe.m_item; object obj3; if (item3 == null) { obj3 = null; } else { GameObject dropPrefab = item3.m_itemData.m_dropPrefab; obj3 = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); } obj[3] = (string)obj3; return ContainsPrefabName(recipePreviewPrefabBlacklist, obj); } return false; } private static bool IsPiecePreviewBlacklisted(Piece piece) { HashSet<string> piecePreviewPrefabBlacklist = GetPiecePreviewPrefabBlacklist(); if (piecePreviewPrefabBlacklist.Count > 0) { string[] obj = new string[2] { ((Object)piece).name, null }; GameObject gameObject = ((Component)piece).gameObject; obj[1] = ((gameObject != null) ? ((Object)gameObject).name : null); return ContainsPrefabName(piecePreviewPrefabBlacklist, obj); } return false; } private static HashSet<string> GetRecipePreviewPrefabBlacklist() { return GetPrefabBlacklist(VeiledRecipesPlugin.RecipePreviewPrefabBlacklist, ref _recipePreviewPrefabBlacklistRaw, ref _recipePreviewPrefabBlacklist); } private static HashSet<string> GetPiecePreviewPrefabBlacklist() { return GetPrefabBlacklist(VeiledRecipesPlugin.PiecePreviewPrefabBlacklist, ref _piecePreviewPrefabBlacklistRaw, ref _piecePreviewPrefabBlacklist); } private static bool HasPreviewBlacklistedRequirement(Requirement[] requirements) { HashSet<string> requirementPreviewPrefabBlacklist = GetRequirementPreviewPrefabBlacklist(); if (requirementPreviewPrefabBlacklist.Count == 0 || requirements == null) { return false; } foreach (Requirement val in requirements) { if (!((Object)(object)val?.m_resItem == (Object)null) && val.GetAmount(1) > 0) { string[] obj = new string[3] { ((Object)val.m_resItem).name, null, null }; GameObject gameObject = ((Component)val.m_resItem).gameObject; obj[1] = ((gameObject != null) ? ((Object)gameObject).name : null); GameObject dropPrefab = val.m_resItem.m_itemData.m_dropPrefab; obj[2] = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); if (ContainsPrefabName(requirementPreviewPrefabBlacklist, obj)) { return true; } } } return false; } private static HashSet<string> GetRequirementPreviewPrefabBlacklist() { return GetPrefabBlacklist(VeiledRecipesPlugin.RequirementPreviewPrefabBlacklist, ref _requirementPreviewPrefabBlacklistRaw, ref _requirementPreviewPrefabBlacklist); } private static HashSet<string> GetPrefabBlacklist(ConfigEntry<string> entry, ref string cachedRaw, ref HashSet<string> cached) { string text = entry?.Value ?? ""; if (string.Equals(text, cachedRaw, StringComparison.Ordinal)) { return cached; } cachedRaw = text; cached = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = text.Split(VeiledRecipeConstants.PrefabBlacklistSeparators, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text2 = NormalizePrefabName(array[i]); if (!string.IsNullOrEmpty(text2)) { cached.Add(text2); } } return cached; } private static bool ContainsPrefabName(HashSet<string> blacklist, params string?[] names) { for (int i = 0; i < names.Length; i++) { string text = NormalizePrefabName(names[i]); if (!string.IsNullOrEmpty(text) && blacklist.Contains(text)) { return true; } } return false; } private static string NormalizePrefabName(string? name) { string text = name?.Trim() ?? ""; if (text.Length == 0) { return ""; } if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - "(Clone)".Length).Trim(); } return text; } internal static VeiledRecipeVisibilityState GetRecipeVisibilityState(Player player, Recipe recipe, ItemData? targetItem = null) { if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null) { return VeiledRecipeVisibilityState.Hidden; } if (!ShouldMaskRecipe(player, recipe, targetItem)) { return VeiledRecipeVisibilityState.Known; } if (!ShowUnknownCraftingRecipes || !IsRecipeEnabledForPlayer(player, recipe)) { return VeiledRecipeVisibilityState.Hidden; } if (IsRecipePreviewBlacklisted(recipe)) { return VeiledRecipeVisibilityState.Hidden; } if (HasPreviewBlacklistedRequirement(recipe.m_resources)) { return VeiledRecipeVisibilityState.Hidden; } if (!DlcInstalled(recipe.m_item.m_itemData.m_shared.m_dlc)) { return VeiledRecipeVisibilityState.Hidden; } if (!PassesCraftFilter(recipe)) { return VeiledRecipeVisibilityState.Hidden; } bool flag = RequireStationLevelForUnknownCraftingRecipes && (Object)(object)recipe.GetRequiredStation(1) != (Object)null; if (!player.RequiredCraftingStation(recipe, 1, flag)) { return VeiledRecipeVisibilityState.Hidden; } return VeiledRecipeVisibilityState.UnknownPreview; } internal static VeiledRecipeVisibilityState GetPieceVisibilityState(Player player, Piece piece) { if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null) { return VeiledRecipeVisibilityState.Hidden; } if (!ShouldMaskPiece(player, piece)) { return VeiledRecipeVisibilityState.Known; } if (!ShowUnknownBuildPieces || !IsPieceEnabledForPlayer(player, piece)) { return VeiledRecipeVisibilityState.Hidden; } if (IsPiecePreviewBlacklisted(piece)) { return VeiledRecipeVisibilityState.Hidden; } if (HasPreviewBlacklistedRequirement(piece.m_resources)) { return VeiledRecipeVisibilityState.Hidden; } if (RequireStationKnowledgeForUnknownBuildPieces && !KnowsPieceStationRequirement(player, piece)) { return VeiledRecipeVisibilityState.Hidden; } if (!DlcInstalled(piece.m_dlc)) { return VeiledRecipeVisibilityState.Hidden; } return VeiledRecipeVisibilityState.UnknownPreview; } internal static bool IsUnknownRecipePreview(Player player, Recipe recipe) { return GetRecipeVisibilityState(player, recipe) == VeiledRecipeVisibilityState.UnknownPreview; } internal static bool IsUnknownPiecePreview(Player player, Piece piece) { return GetPieceVisibilityState(player, piece) == VeiledRecipeVisibilityState.UnknownPreview; } internal static bool CanDiscoverRecipe(Player player, Recipe recipe) { if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null) { return false; } if ((Object)(object)recipe.m_craftingStation != (Object)null && !HasKnownRecipeStationLevel(player, recipe.m_craftingStation.m_name, recipe.m_minStationLevel)) { return false; } if (!DlcInstalled(recipe.m_item.m_itemData.m_shared.m_dlc)) { return false; } return HasDiscoveredRecipeMaterials(player, recipe); } private static bool HasDiscoveredRecipeMaterials(Player player, Recipe recipe) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool flag = false; Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0 && (!((Object)(object)currentCraftingStation == (Object)null) || !val.m_upgraderResource)) { bool flag2 = IsMaterialKnown(player, val); if (recipe.m_requireOnlyOneIngredient) { flag = flag || flag2; } else if (!flag2) { return false; } } } return !recipe.m_requireOnlyOneIngredient || flag; } internal static bool IsRecipeRequirementActiveAtCurrentStation(Player player, Requirement requirement) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool flag = (Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader; return requirement.m_upgraderResource == flag; } private static bool IsRecipeEnabledForPlayer(Player player, Recipe recipe) { bool flag = (Object)(object)player.CurrentSeason != (Object)null && player.CurrentSeason.Recipes.Contains(recipe); return recipe.m_enabled || flag; } private static bool IsPieceEnabledForPlayer(Player player, Piece piece) { bool flag = (Object)(object)player.CurrentSeason != (Object)null && player.CurrentSeason.Pieces.Contains(((Component)piece).gameObject); return piece.m_enabled || flag; } private static bool PassesCraftFilter(Recipe recipe) { if (Player.s_FilterCraft.Count == 0) { return true; } string text = ((Object)recipe.m_item).name.ToLowerInvariant(); string text2 = recipe.m_item.m_itemData.m_shared.m_name.ToLowerInvariant(); string text3 = Localization.instance.Localize(recipe.m_item.m_itemData.m_shared.m_name).ToLowerInvariant(); foreach (string item in Player.s_FilterCraft) { if (!string.IsNullOrWhiteSpace(item)) { string value = item.ToLowerInvariant(); if (text.Contains(value) || text2.Contains(value) || text3.Contains(value)) { return true; } } } return false; } internal static void RecordStationInteraction(Player player, CraftingStation station) { if ((Object)(object)player == (Object)null || (Object)(object)station == (Object)null) { return; } if (!EnableStationProximityDiscovery) { player.AddKnownStation(station); } int num = Math.Max(1, station.GetLevel(true)); string key = StationInteractionKey(station.m_name); if (player.m_customData.TryGetValue(key, out var value) && int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= num) { return; } player.m_customData[key] = num.ToString(CultureInfo.InvariantCulture); try { player.UpdateKnownRecipesList(); } catch (Exception ex) { VeiledRecipesPlugin.PluginLogger.LogDebug((object)("Could not refresh known recipes after station interaction: " + ex.Message)); } } internal static bool KnowsRecipeStationRequirement(Player player, Recipe recipe, int quality) { if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null) { return false; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader) { return HasKnownRecipeStationLevel(player, currentCraftingStation.m_name, 1); } CraftingStation requiredStation = recipe.GetRequiredStation(quality); if (!((Object)(object)requiredStation == (Object)null)) { return HasKnownRecipeStationLevel(player, requiredStation.m_name, recipe.GetRequiredStationLevel(quality)); } return true; } internal static bool KnowsPieceStationRequirement(Player player, Piece piece) { if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || (Object)(object)piece.m_craftingStation == (Object)null) { return true; } return GetKnownPieceStationLevel(player, piece.m_craftingStation.m_name) > 0; } private static int GetKnownRecipeStationLevel(Player player, string stationName) { if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(stationName)) { return 0; } if (RequireStationInteractionForRecipeUnlock) { return GetInteractedStationLevel(player, stationName); } return GetKnownPieceStationLevel(player, stationName); } private static int GetKnownPieceStationLevel(Player player, string stationName) { if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(stationName)) { return 0; } if (!player.m_knownStations.TryGetValue(stationName, out var value)) { return 0; } return value; } private static bool HasKnownRecipeStationLevel(Player player, string stationName, int requiredLevel) { return GetKnownRecipeStationLevel(player, stationName) >= Math.Max(1, requiredLevel); } private static int GetInteractedStationLevel(Player player, string stationName) { if (player.m_customData.TryGetValue(StationInteractionKey(stationName), out var value) && int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return 0; } private static string StationInteractionKey(string stationName) { return "VeiledRecipes.InteractedStation." + stationName; } } [HarmonyPatch(typeof(MessageHud), "QueueUnlockMsg")] internal static class MessageHudQueueUnlockMsgPatch { private static bool Prefix(MessageHud __instance, string topic, string description) { if (ShouldShowUnlockNotification(topic)) { return true; } __instance.AddLog(topic + ": " + description); return false; } private static bool ShouldShowUnlockNotification(string topic) { switch ((topic ?? "").Trim()) { case "$msg_newrecipe": return VeiledRecipeState.ShowRecipeUnlockNotifications; case "$msg_newpiece": case "$msg_newdish": return VeiledRecipeState.ShowPieceUnlockNotifications; default: return true; } } } [HarmonyPatch(typeof(Player), "OnSkillLevelup")] internal static class PlayerSkillLevelUpEffectsPatch { private static bool Prefix() { return VeiledRecipeState.ShowSkillLevelUpNotificationAndEffect; } } [HarmonyPatch(typeof(Player), "Message")] internal static class PlayerSkillNotificationAlarmPatch { private static bool Prefix(string msg) { if (!VeiledRecipeState.ShowSkillLevelUpNotificationAndEffect) { return !(msg ?? "").Trim().StartsWith("$msg_skillup ", StringComparison.OrdinalIgnoreCase); } return true; } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class PlayerPieceRequirementsPatch { private static bool Prefix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((Object)(object)piece == (Object)null) { return true; } if ((int)mode != 1 && VeiledRecipeState.ShouldMaskPiece(__instance, piece)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(PieceTable), "UpdateAvailable")] internal static class PieceTableUpdateAvailablePatch { private static void Prefix(PieceTable __instance, List<List<Piece>> ___m_availablePiecesByCategory) { VeiledRecipeState.RegisterBuildPieceTable(__instance); EnsureAvailablePieceBuckets(__instance, ___m_availablePiecesByCategory); } private static void Postfix(PieceTable __instance, Player player, List<List<Piece>> ___m_availablePiecesByCategory) { if (!VeiledRecipeState.ShowUnknownBuildPieces || (Object)(object)player == (Object)null) { return; } HashSet<string> availablePiecePrefabNames = GetAvailablePiecePrefabNames(__instance); foreach (GameObject piece in __instance.m_pieces) { Piece val = (((Object)(object)piece == (Object)null) ? null : piece.GetComponent<Piece>()); string text = (((Object)(object)val == (Object)null) ? "" : Utils.GetPrefabName(((Component)val).gameObject)); if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(text) && !availablePiecePrefabNames.Contains(text) && VeiledRecipeState.GetPieceVisibilityState(player, val) == VeiledRecipeVisibilityState.UnknownPreview) { AddAvailablePiece(__instance, val, ___m_availablePiecesByCategory); availablePiecePrefabNames.Add(text); } } } private static void EnsureAvailablePieceBuckets(PieceTable table, List<List<Piece>> categories) { int requiredCategoryBucketCount = GetRequiredCategoryBucketCount(table); while (categories.Count < requiredCategoryBucketCount) { categories.Add(new List<Piece>()); } } private static int GetRequiredCategoryBucketCount(PieceTable table) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected I4, but got Unknown int num = 9; foreach (GameObject piece in table.m_pieces) { Piece val = (((Object)(object)piece == (Object)null) ? null : piece.GetComponent<Piece>()); if (!((Object)(object)val == (Object)null) && (int)val.m_category != 100) { int num2 = (int)val.m_category; if (num2 >= 0) { num = Math.Max(num, num2 + 1); } } } return num; } private static HashSet<string> GetAvailablePiecePrefabNames(PieceTable table) { HashSet<string> hashSet = new HashSet<string>(); foreach (Piece availablePiece in table.m_availablePieces) { if ((Object)(object)availablePiece != (Object)null) { hashSet.Add(Utils.GetPrefabName(((Component)availablePiece).gameObject)); } } return hashSet; } private static void AddAvailablePiece(PieceTable table, Piece piece, List<List<Piece>> categories) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected I4, but got Unknown //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 int num = (int)piece.m_category; if (((int)piece.m_category != 100 && (num < 0 || num >= categories.Count)) || !table.m_availablePieces.Add(piece)) { return; } if ((int)piece.m_category == 100) { foreach (List<Piece> category in categories) { category.Add(piece); } return; } categories[num].Add(piece); } } [HarmonyPatch(typeof(Hud), "UpdatePieceList")] internal static class HudUpdatePieceListPatch { private static void Postfix(Hud __instance, Player player) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } List<Piece> buildPieces = player.GetBuildPieces(); if (buildPieces == null) { return; } for (int i = 0; i < __instance.m_pieceIcons.Count && i < buildPieces.Count; i++) { Piece val = buildPieces[i]; if (!((Object)(object)val == (Object)null) && VeiledRecipeState.ShouldMaskPiece(player, val)) { PieceIconData obj = __instance.m_pieceIcons[i]; ((Behaviour)obj.m_icon).enabled = true; obj.m_icon.sprite = val.m_icon; ((Graphic)obj.m_icon).color = Color.black; obj.m_tooltip.m_text = VeiledRecipeState.UnknownNameText; obj.m_upgrade.SetActive(false); } } } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] internal static class HudSetupPieceInfoPatch { [HarmonyPriority(0)] private static void Postfix(Hud __instance, Piece piece) { TryMaskPieceInfo(__instance, Player.m_localPlayer, piece); } internal static bool TryMaskPieceInfo(Hud hud, Player player, Piece piece) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hud == (Object)null || (Object)(object)piece == (Object)null || (Object)(object)player == (Object)null) { return false; } if (!VeiledRecipeState.ShouldMaskPiece(player, piece)) { ((Graphic)hud.m_buildIcon).color = Color.white; return false; } MaskPieceInfo(hud, player, piece); return true; } private static void MaskPieceInfo(Hud hud, Player player, Piece piece) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 hud.m_buildSelection.text = VeiledRecipeState.UnknownNameText; hud.m_pieceDescription.text = VeiledRecipeState.UnknownDescriptionText; ((Behaviour)hud.m_buildIcon).enabled = true; hud.m_buildIcon.sprite = piece.m_icon; ((Graphic)hud.m_buildIcon).color = Color.black; ((Behaviour)hud.m_snappingIcon).enabled = false; int i = 0; Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (i >= hud.m_requirementItems.Length) { break; } if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0) { hud.m_requirementItems[i].SetActive(true); VeiledRecipeRequirementUi.SetupRequirement(hud.m_requirementItems[i].transform, val, player, (int)piece.FreeBuildKey() == 25, 0); i++; } } if ((Object)(object)piece.m_craftingStation != (Object)null && i < hud.m_requirementItems.Length) { hud.m_requirementItems[i].SetActive(true); VeiledRecipeRequirementUi.SetupPieceStationRequirement(hud.m_requirementItems[i].transform, player, piece); i++; } for (; i < hud.m_requirementItems.Length; i++) { hud.m_requirementItems[i].SetActive(false); } } } [HarmonyPatch(typeof(Hud), "UpdateBuild")] internal static class HudUpdateBuildMaskPieceInfoPatch { [HarmonyPriority(0)] private static void Postfix(Hud __instance, Player player) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)player == (Object)null) && ((Character)player).InPlaceMode()) { Piece val = __instance.m_hoveredPiece; if (!Object.op_Implicit((Object)(object)val)) { val = player.GetSelectedPiece(); } if (Object.op_Implicit((Object)(object)val)) { HudSetupPieceInfoPatch.TryMaskPieceInfo(__instance, player, val); } } } } [HarmonyPatch(typeof(Player), "SetupPlacementGhost")] internal static class PlayerSetupPlacementGhostPatch { private static void Postfix(Player __instance) { Piece selectedPiece = __instance.GetSelectedPiece(); if (!((Object)(object)selectedPiece == (Object)null) && VeiledRecipeState.ShouldMaskPiece(__instance, selectedPiece)) { if ((Object)(object)__instance.m_placementGhost != (Object)null) { Object.Destroy((Object)(object)__instance.m_placementGhost); __instance.m_placementGhost = null; } if ((Object)(object)__instance.m_placementMarkerInstance != (Object)null) { __instance.m_placementMarkerInstance.SetActive(false); } } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class PlayerTryPlacePiecePatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if ((Object)(object)piece != (Object)null && VeiledRecipeState.ShouldMaskPiece(__instance, piece)) { ((Character)__instance).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); __result = false; return false; } return true; } } [HarmonyPatch(typeof(BuildUiPieceButton), "Setup")] internal static class BuildUiPieceSetupPatch { private static void Prefix(BuildUiPieceButton __instance) { Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(__instance.RefreshSearchTerm)); } } [HarmonyPatch(typeof(BuildUiPieceButton), "UpdateRequirements")] internal static class BuildUiPieceRequirementsPatch { [HarmonyPriority(0)] private static void Postfix(BuildUiPieceButton __instance, Image ___m_icon, Image ___m_upgradeArrow) { ApplyAppearance(__instance, Player.m_localPlayer, ___m_icon, ___m_upgradeArrow); } private static void ApplyAppearance(BuildUiPieceButton button, Player? player, Image icon, Image upgradeArrow) { Piece piece = button.Piece; bool num = (Object)(object)player != (Object)null && (Object)(object)piece != (Object)null && VeiledRecipeState.ShouldMaskPiece(player, piece); VeiledBuildPieceIconGuard veiledBuildPieceIconGuard = ((Component)button).GetComponent<VeiledBuildPieceIconGuard>(); if (!num) { veiledBuildPieceIconGuard?.Configure(icon, veiled: false); return; } if ((Object)(object)veiledBuildPieceIconGuard == (Object)null) { veiledBuildPieceIconGuard = ((Component)button).gameObject.AddComponent<VeiledBuildPieceIconGuard>(); } veiledBuildPieceIconGuard.Configure(icon, veiled: true); ((Component)upgradeArrow).gameObject.SetActive(false); } } internal sealed class VeiledBuildPieceIconGuard : MonoBehaviour { private Image? _veil; internal Image? Veil => _veil; internal void Configure(Image icon, bool veiled) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_veil == (Object)null) { Image val = (_veil = new GameObject("VeiledRecipes Piece Veil", new Type[1] { typeof(RectTransform) }).AddComponent<Image>()); ((Component)val).transform.SetParent(((Component)icon).transform, false); RectTransform rectTransform = ((Graphic)val).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; ((Transform)rectTransform).localScale = Vector3.one; } Image veil = _veil; veil.sprite = icon.sprite; veil.preserveAspect = icon.preserveAspect; ((Graphic)veil).raycastTarget = ((Graphic)icon).raycastTarget; ((Graphic)veil).color = Color.black; ((Behaviour)icon).enabled = !veiled; ((Component)veil).gameObject.SetActive(veiled); if (veiled) { ((Component)veil).transform.SetAsLastSibling(); } } } [HarmonyPatch(typeof(BuildUiPieceButton), "RefreshSearchTerm")] internal static class BuildUiPieceSearchPatch { private static bool Prefix(BuildUiPieceButton __instance) { Player localPlayer = Player.m_localPlayer; Piece piece = __instance.Piece; if ((Object)(object)localPlayer == (Object)null || (Object)(object)piece == (Object)null || !VeiledRecipeState.ShouldMaskPiece(localPlayer, piece)) { return true; } List<string> localizedSearchTerms = __instance.LocalizedSearchTerms; localizedSearchTerms.Clear(); localizedSearchTerms.Add(Normalize(VeiledRecipeState.UnknownNameText)); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val?.m_resItem != (Object)null && VeiledRecipeState.IsMaterialKnown(localPlayer, val)) { localizedSearchTerms.Add(Normalize(Localization.instance.Localize(val.m_resItem.m_itemData.m_shared.m_name))); } } return false; } private static string Normalize(string text) { return text.ToLowerInvariant().Replace(" ", ""); } } [HarmonyPatch(typeof(ByMaterialPieceList), "GetTagDisplayName")] internal static class BuildUiMaterialTagPatch { private static void Postfix(ByMaterialPieceList __instance, int index, ref string __result) { Player localPlayer = Player.m_localPlayer; Requirement tagById = __instance.GetTagById(__instance.GetTagIdByIndex(index)); if ((Object)(object)localPlayer != (Object)null && tagById != null && !VeiledRecipeState.IsMaterialKnown(localPlayer, tagById)) { __result = VeiledRecipeState.UnknownRequirementText; } } } [HarmonyPatch(typeof(BuildUi), "Update")] internal static class VeiledRecipeBuildUiRefreshPatch { private sealed class Snapshot { public Player? Player; public PieceTable? Table; public int Revision; public bool FreePlacement; public bool NoCostCheat; public float NextCheck; public readonly HashSet<string> Recipes = new HashSet<string>(); public readonly HashSet<string> Materials = new HashSet<string>(); public readonly Dictionary<string, int> Stations = new Dictionary<string, int>(); public bool SameStations(Dictionary<string, int> stations) { if (Stations.Count != stations.Count) { return false; } foreach (KeyValuePair<string, int> station in stations) { if (!Stations.TryGetValue(station.Key, out var value) || station.Value != value) { return false; } } return true; } } private static int _revision; private static readonly ConditionalWeakTable<BuildUi, Snapshot> Snapshots = new ConditionalWeakTable<BuildUi, Snapshot>(); private static readonly FieldRef<Player, HashSet<string>> KnownRecipes = AccessTools.FieldRefAccess<Player, HashSet<string>>("m_knownRecipes"); private static readonly FieldRef<Player, HashSet<string>> KnownMaterials = AccessTools.FieldRefAccess<Player, HashSet<string>>("m_knownMaterial"); private static readonly FieldRef<Player, Dictionary<string, int>> KnownStations = AccessTools.FieldRefAccess<Player, Dictionary<string, int>>("m_knownStations"); private static readonly FieldRef<Player, bool> NoPlacementCost = AccessTools.FieldRefAccess<Player, bool>("m_noPlacementCost"); private static readonly Action<BuildUi, bool> RefreshTags = AccessTools.MethodDelegate<Action<BuildUi, bool>>(AccessTools.Method(typeof(BuildUi), "UpdateTagButtons", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<Player> RefreshGhost = AccessTools.MethodDelegate<Action<Player>>(AccessTools.Method(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null), (object)null, true); internal static void Invalidate() { Interlocked.Increment(ref _revision); } private static void Postfix(BuildUi __instance, PieceTable ___m_currentBuildTool) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)___m_currentBuildTool == (Object)null || !((Component)__instance).gameObject.activeInHierarchy || !((Character)localPlayer).InPlaceMode()) { return; } Snapshot orCreateValue = Snapshots.GetOrCreateValue(__instance); if (Time.unscaledTime < orCreateValue.NextCheck) { return; } orCreateValue.NextCheck = Time.unscaledTime + 0.25f; HashSet<string> hashSet = KnownRecipes.Invoke(localPlayer); HashSet<string> hashSet2 = KnownMaterials.Invoke(localPlayer); Dictionary<string, int> dictionary = KnownStations.Invoke(localPlayer); bool flag = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)26); bool flag2 = NoPlacementCost.Invoke(localPlayer) || flag; bool flag3 = localPlayer.NoCostCheat(); int num = Volatile.Read(in _revision); if (!((Object)(object)orCreateValue.Player != (Object)(object)localPlayer) && !((Object)(object)orCreateValue.Table != (Object)(object)___m_currentBuildTool) && orCreateValue.Revision == num && orCreateValue.FreePlacement == flag2 && orCreateValue.NoCostCheat == flag3 && orCreateValue.Recipes.SetEquals(hashSet) && orCreateValue.Materials.SetEquals(hashSet2) && orCreateValue.SameStations(dictionary)) { return; } orCreateValue.Player = localPlayer; orCreateValue.Table = ___m_currentBuildTool; orCreateValue.Revision = num; orCreateValue.FreePlacement = flag2; orCreateValue.NoCostCheat = flag3; orCreateValue.Recipes.Clear(); orCreateValue.Recipes.UnionWith(hashSet); orCreateValue.Materials.Clear(); orCreateValue.Materials.UnionWith(hashSet2); orCreateValue.Stations.Clear(); foreach (KeyValuePair<string, int> item in dictionary) { orCreateValue.Stations.Add(item.Key, item.Value); } ___m_currentBuildTool.UpdateAvailable(hashSet, localPlayer, false, flag2); RefreshTags(__instance, arg2: true); RefreshGhost(localPlayer); } internal static void Forget(BuildUi ui) { Snapshots.Remove(ui); } } [HarmonyPatch(typeof(BuildUi), "OnDestroy")] internal static class BuildUiDestroyPatch { private static void Prefix(BuildUi __instance, List<BuildUiPieceButton> ___m_pieceButtons, Stack<BuildUiPieceButton> ___m_pieceButtonPool, Stack<BuildUiPieceButton> ___m_previousPieceButtonsTemp, BuildUiPieceButton ___m_specialPieceButton) { VeiledRecipeBuildUiRefreshPatch.Forget(__instance); foreach (BuildUiPieceButton ___m_pieceButton in ___m_pieceButtons) { Unsubscribe(___m_pieceButton); } foreach (BuildUiPieceButton item in ___m_pieceButtonPool) { Unsubscribe(item); } foreach (BuildUiPieceButton item2 in ___m_previousPieceButtonsTemp) { Unsubscribe(item2); } Unsubscribe(___m_specialPieceButton); } internal static void Unsubscribe(BuildUiPieceButton button) { if ((Object)(object)button != (Object)null) { Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(button.RefreshSearchTerm)); } } } [HarmonyPatch(typeof(BuildUi), "UpdatePieceButtons")] internal static class BuildUiSpecialPieceCleanupPatch { private static void Prefix(BuildUiPieceButton ___m_specialPieceButton) { BuildUiDestroyPatch.Unsubscribe(___m_specialPieceButton); } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class PlayerRecipeRequirementsPatch { private static bool Prefix(Player __instance, Recipe recipe, bool discover, ref bool __result) { if ((Object)(object)recipe == (Object)null) { return true; } if (discover && VeiledRecipeState.RequireStationInteractionForRecipeUnlock) { __result = VeiledRecipeState.CanDiscoverRecipe(__instance, recipe); return false; } if (!discover && VeiledRecipeState.RequiresRecipeKnowledge(__instance, recipe)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(Player), "GetAvailableRecipes")] internal static class PlayerGetAvailableRecipesPatch { private static void Postfix(Player __instance, ref List<Recipe> available) { if (!VeiledRecipeState.ShowUnknownCraftingRecipes || (Object)(object)ObjectDB.instance == (Object)null) { return; } HashSet<Recipe> hashSet = new HashSet<Recipe>(available); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (!hashSet.Contains(recipe) && VeiledRecipeState.GetRecipeVisibilityState(__instance, recipe) == VeiledRecipeVisibilityState.UnknownPreview) { available.Add(recipe); hashSet.Add(recipe); } } } } [HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")] internal static class InventoryGuiAddRecipeToListPatch { private static void Prefix(Player player, Recipe recipe, ItemData item, ref bool canCraft, out bool __state) { __state = VeiledRecipeState.ShouldMaskRecipe(player, recipe, item); if (__state) { canCraft = false; } } private static void Postfix(InventoryGui __instance, Recipe recipe, ItemData item, bool __state) { if (__state) { GameObject val = FindRecipeElement(__instance, recipe, item); if ((Object)(object)val != (Object)null) { MaskRecipeListElement(val, recipe); } } } private static GameObject? FindRecipeElement(InventoryGui gui, Recipe recipe, ItemData item) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) for (int num = gui.m_availableRecipes.Count - 1; num >= 0; num--) { RecipeDataPair val = gui.m_availableRecipes[num]; if ((Object)(object)((RecipeDataPair)(ref val)).Recipe == (Object)(object)recipe && ((RecipeDataPair)(ref val)).ItemData == item) { return ((RecipeDataPair)(ref val)).InterfaceElement; } } return null; } internal static void MaskRecipeListElement(GameObject element, Recipe recipe) { //IL_007c: 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) Image val = VeiledRecipeRequirementUi.FindComponent<Image>(element.transform, "icon"); if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = true; if ((Object)(object)recipe?.m_item != (Object)null) { val.sprite = recipe.m_item.m_itemData.GetIcon(); } ((Graphic)val).color = Color.black; } TMP_Text val2 = VeiledRecipeRequirementUi.FindComponent<TMP_Text>(element.transform, "name"); if ((Object)(object)val2 != (Object)null) { val2.text = VeiledRecipeState.UnknownNameText; ((Graphic)val2).color = Color.white; } GuiBar val3 = VeiledRecipeRequirementUi.FindComponent<GuiBar>(element.transform, "Durability"); if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(false); } TMP_Text val4 = VeiledRecipeRequirementUi.FindComponent<TMP_Text>(element.transform, "QualityLevel"); if ((Object)(object)val4 != (Object)null) { ((Component)val4).gameObject.SetActive(false); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList", new Type[] { typeof(List<Recipe>) })] internal static class InventoryGuiUpdateRecipeListPatch { [HarmonyAfter(new string[] { "Azumatt.AzuAntiArthriticCrafting" })] private static void Postfix(InventoryGui __instance) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } VeiledRecipeAaaCraftingCompat.MaskRecipeList(__instance, localPlayer); if (!VeiledRecipeState.GroupUnknownRecipePreviewsBelowKnownRecipes || __instance.m_availableRecipes.Count <= 1) { return; } List<RecipeDataPair> list = new List<RecipeDataPair>(); List<RecipeDataPair> list2 = new List<RecipeDataPair>(); foreach (RecipeDataPair availableRecipe in __instance.m_availableRecipes) { RecipeDataPair current = availableRecipe; if (VeiledRecipeState.GetRecipeVisibilityState(localPlayer, ((RecipeDataPair)(ref current)).Recipe, ((RecipeDataPair)(ref current)).ItemData) == VeiledRecipeVisibilityState.UnknownPreview) { list2.Add(current); } else { list.Add(current); } } if (list.Count == 0 || list2.Count == 0) { return; } __instance.m_availableRecipes.Clear(); __instance.m_availableRecipes.AddRange(list); __instance.m_availableRecipes.AddRange(list2); LayoutGroup component = ((Component)__instance.m_recipeListRoot).GetComponent<LayoutGroup>(); bool flag = (Object)(object)component != (Object)null && ((Behaviour)component).isActiveAndEnabled; for (int i = 0; i < __instance.m_availableRecipes.Count; i++) { RecipeDataPair val = __instance.m_availableRecipes[i]; GameObject interfaceElement = ((RecipeDataPair)(ref val)).InterfaceElement; if ((Object)(object)interfaceElement == (Object)null) { continue; } if (flag) { interfaceElement.transform.SetSiblingIndex(i); continue; } Transform transform = interfaceElement.transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val2 != null) { val2.anchoredPosition = new Vector2(0f, (float)i * (0f - __instance.m_recipeListSpace)); } } if (flag) { LayoutRebuilder.MarkLayoutForRebuild(__instance.m_recipeListRoot); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] internal static class InventoryGuiUpdateRecipePatch { [HarmonyAfter(new string[] { "Azumatt.AzuAntiArthriticCrafting" })] private static void Postfix(InventoryGui __instance, Player player) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) Recipe recipe = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).Recipe; if (!((Object)(object)recipe == (Object)null)) { if (!VeiledRecipeState.ShouldMaskRecipe(player, recipe, ((RecipeDataPair)(ref __instance.m_selectedRecipe)).ItemData)) { ((Graphic)__instance.m_recipeIcon).color = Color.white; } else { MaskSelectedRecipe(__instance, player, recipe); } } } private static void MaskSelectedRecipe(InventoryGui gui, Player player, Recipe recipe) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) ItemData itemData = ((RecipeDataPair)(ref gui.m_selectedRecipe)).ItemData; int num = ((itemData == null) ? 1 : (itemData.m_quality + 1)); int craftMultiplier = ((itemData != null || (!ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyLStick"))) ? 1 : gui.m_multiCraftAmount); CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool flag = (Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader; bool allowedQuality = (Object)(object)recipe.m_item != (Object)null && (flag || num <= recipe.m_item.m_itemData.m_shared.m_maxQuality); ((Behaviour)gui.m_recipeIcon).enabled = true; if ((Object)(object)recipe.m_item != (Object)null) { gui.m_recipeIcon.sprite = recipe.m_item.m_itemData.GetIcon(); } ((Graphic)gui.m_recipeIcon).color = Color.black; ((Behaviour)gui.m_recipeName).enabled = true; gui.m_recipeName.text = VeiledRecipeState.UnknownNameText; ((Behaviour)gui.m_recipeDecription).enabled = true; gui.m_recipeDecription.text = VeiledRecipeState.UnknownDescriptionText; ((Component)gui.m_variantButton).gameObject.SetActive(false); ((Component)gui.m_itemCraftType).gameObject.SetActive(false); ((Component)gui.m_qualityPanel).gameObject.SetActive(false); ((Selectable)gui.m_craftButton).interactable = false; ((Component)gui.m_craftButton).GetComponent<UITooltip>().m_text = VeiledRecipeState.UnknownDescriptionText; SetupRecipeRequirements(gui, player, recipe, num, allowedQuality, craftMultiplier); SetupRecipeStationLevel(gui, player, recipe, num, allowedQuality); } private static void SetupRecipeStationLevel(InventoryGui gui, Player player, Recipe recipe, int quality, bool allowedQuality) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)recipe.GetRequiredStation(quality) == (Object)null || !allowedQuality) { ((Component)gui.m_minStationLevelIcon).gameObject.SetActive(false); return; } ((Component)gui.m_minStationLevelIcon).gameObject.SetActive(true); CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); int num = (((Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader) ? 1 : recipe.GetRequiredStationLevel(quality)); gui.m_minStationLevelText.text = (VeiledRecipeState.KnowsRecipeStationRequirement(player, recipe, quality) ? num.ToString() : VeiledRecipeState.UnknownRequirementText); ((Graphic)gui.m_minStationLevelText).color = gui.m_minStationLevelBasecolor; } private static void SetupRecipeRequirements(InventoryGui gui, Player player, Recipe recipe, int quality, bool allowedQuality, int craftMultiplier) { int i = 0; Requirement[] resources = recipe.m_resources; if (allowedQuality && resources != null && gui.m_recipeRequirementList.Length != 0) { int num = 0; Requirement[] array = resources; foreach (Requirement val in array) { if ((Object)(object)val?.m_resItem != (Object)null && VeiledRecipeState.IsRecipeRequirementActiveAtCurrentStation(player, val) && val.GetAmount(quality) > 0) { num++; } } int num2 = VeiledRecipeRequirementUi.GetCyclingStart(num, gui.m_recipeRequirementList.Length); array = resources; foreach (Requirement val2 in array) { if (i >= gui.m_recipeRequirementList.Length) { break; } if (!((Object)(object)val2?.m_resItem == (Object)null) && VeiledRecipeState.IsRecipeRequirementActiveAtCurrentStation(player, val2) && val2.GetAmount(quality) > 0) { if (num2 > 0) { num2--; continue; } VeiledRecipeRequirementUi.SetupRequirement(gui.m_recipeRequirementList[i].transform, val2, player, craft: true, quality, craftMultiplier); i++; } } } for (; i < gui.m_recipeRequirementList.Length; i++) { InventoryGui.HideRequirement(gui.m_recipeRequirementList[i].transform); } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] internal static class InventoryGuiOnCraftPressedPatch { private static bool Prefix(InventoryGui __instance) { Recipe recipe = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).Recipe; Player localPlayer = Player.m_localPlayer; if ((Object)(object)recipe != (Object)null && (Object)(object)localPlayer != (Object)null && VeiledRecipeState.ShouldMaskRecipe(localPlayer, recipe, ((RecipeDataPair)(ref __instance.m_selectedRecipe)).ItemData)) { ((Character)localPlayer).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); return false; } return true; } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class InventoryGuiDoCraftingPatch { private static bool Prefix(InventoryGui __instance, Player player) { Recipe craftRecipe = __instance.m_craftRecipe; if ((Object)(object)craftRecipe != (Object)null && VeiledRecipeState.ShouldMaskRecipe(player, craftRecipe, __instance.m_craftUpgradeItem)) { __instance.m_craftTimer = -1f; ((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); return false; } return true; } } [HarmonyPatch(typeof(CraftingStation), "Interact")] internal static class CraftingStationInteractPatch { private static void Prefix(CraftingStation __instance, Humanoid user, bool repeat) { if (!repeat && !((Object)(object)user != (Object)(object)Player.m_localPlayer)) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && __instance.InUseDistance(user) && __instance.CheckUsable(val, false)) { VeiledRecipeState.RecordStationInteraction(val, __instance); } } } } [HarmonyPatch(typeof(CraftingStation), "UpdateKnownStationsInRange")] internal static class CraftingStationUpdateKnownStationsInRangePatch { private static bool Prefix() { return VeiledRecipeState.EnableStationProximityDiscovery; } } public enum VeiledRecipeVisibilityState { Hidden, Known, UnknownPreview } internal static class VeiledRecipeRequirementUi { internal static void SetupRequirement(Transform root, Requirement? requirement, Player player, bool craft, int quality, int multiplier = 1) { if (requirement == null || (Object)(object)requirement.m_resItem == (Object)null || requirement.GetAmount(quality) <= 0) { InventoryGui.HideRequirement(root); } else if (VeiledRecipeState.IsMaterialKnown(player, requirement)) { InventoryGui.SetupRequirement(root, requirement, player, craft, quality, multiplier); } else { SetupMaskedRequirement(root, requirement); } } internal static void SetupMaskedRequirement(Transform root, Requirement requirement) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) Image val = VeiledRecipeRequirementUi.FindComponent<Image>(root, "res_icon"); TMP_Text val2 = VeiledRecipeRequirementUi.FindComponent<TMP_Text>(root, "res_name"); TMP_Text val3 = VeiledRecipeRequirementUi.FindComponent<TMP_Text>(root, "res_amount"); UITooltip component = ((Component)root).GetComponent<UITooltip>(); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); ((Behaviour)val).enabled = true; val.sprite = requirement.m_resItem.m_itemData.GetIcon(); ((Graphic)val).color = Color.black; } if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(true); val2.text = VeiledRecipeState.UnknownNameText; ((Graphic)val2).color = Color.white; } if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(true); val3.text = VeiledRecipeState.UnknownRequirementText; ((Graphic)val3).color = Color.white; } if ((Object)(object)component != (Object)null) { component.m_text = VeiledRecipeState.UnknownNameText; } } internal static void SetupPieceStationRequirement(Transform root, Player player, Piece piece) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece.m_craftingStation == (Object)null) { InventoryGui.HideRequirement(root); return; } Image val = VeiledRecipeRequirementUi.FindComponent<Image>(root, "res_icon"); TMP_Text val2 = VeiledRecipeRequirementUi.FindComponent<TMP_Text>(root, "res_name"); TMP_Text val3 = VeiledRecipeRequirementUi.FindComponent<TMP_Text>(root, "res_amount"); UITooltip component = ((Component)root).GetComponent<UITooltip>(); bool flag = VeiledRecipeState.KnowsPieceStationRequirement(player, piece); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); ((Behaviour)val).enabled = true; val.sprite = piece.m_craftingStation.m_icon; ((Graphic)val).color = (flag ? Color.white : Color.black); } if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(true); val2.text = (flag ? Localization.instance.Localize(piece.m_craftingStation.m_name) : VeiledRecipeState.UnknownNameText); ((Graphic)val2).color = Color.white; } if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(true); if (flag) { CraftingStation val4 = CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position); if ((Object)(object)val4 != (Object)null) { val4.ShowAreaMarker(); val3.text = ""; } else { val3.text = Localization.instance.Localize("$menu_none"); } } else { val3.text = VeiledRecipeState.UnknownRequirementText; } ((Graphic)val3).color = Color.white; } if ((Object)(object)component != (Object)null) { component.m_text = (flag ? piece.m_craftingStation.m_name : VeiledRecipeState.UnknownNameText); } } internal static int GetCyclingStart(int requirementCount, int slotCount) { if (slotCount <= 0 || requirementCount <= slotCount) { return 0; } int num = Mathf.CeilToInt((float)requirementCount / (float)slotCount); return (int)Time.fixedTime % num * slotCount; } internal static T? FindComponent<T>(Transform root, string childName) where T : Component { Transform val = root.Find(childName); if (!((Object)(object)val == (Object)null)) { return ((Component)val).GetComponent<T>(); } return default(T); } } public static class VeiledRecipesCompat { public const string PluginGuid = "sighsorry.VeiledRecipes"; public const string PluginName = "VeiledRecipes"; public const string PluginVersion = "1.1.5"; public const string Author = "sighsorry"; public static string UnknownNameText => VeiledRecipeState.UnknownNameText; public static string UnknownDescriptionText => VeiledRecipeState.UnknownDescriptionText; public static string UnknownRequirementText => VeiledRecipeState.UnknownRequirementText; public static bool GroupUnknownRecipePreviewsBelowKnownRecipes => VeiledRecipeState.GroupUnknownRecipePreviewsBelowKnownRecipes; [Obsolete("Admin bypass is no longer supported; this member remains for binary compatibility.")] public static bool IsAdminBypassActive => false; public static VeiledRecipeVisibilityState GetRecipeVisibilityState(Recipe recipe) { return GetRecipeVisibilityState(Player.m_localPlayer, recipe); } public static VeiledRecipeVisibilityState GetRecipeVisibilityState(Player player, Recipe recipe) { if (!((Object)(object)player != (Object)null) || !((Object)(object)recipe != (Object)null)) { return VeiledRecipeVisibilityState.Hidden; } return VeiledRecipeState.GetRecipeVisibilityState(player, recipe); } public static bool IsUnknownRecipePreview(Recipe recipe) { return IsUnknownRecipePreview(Player.m_localPlayer, recipe); } public static bool IsUnknownRecipePreview(Player player, Recipe recipe) { if ((Object)(object)player != (Object)null && (Object)(object)recipe != (Object)null) { return VeiledRecipeState.IsUnknownRecipePreview(player, recipe); } return false; } public static VeiledRecipeVisibilityState GetPieceVisibilityState(Piece piece) { return GetPieceVisibilityState(Player.m_localPlayer, piece); } public static VeiledRecipeVisibilityState GetPieceVisibilityState(Player player, Piece piece) { if (!((Object)(object)player != (Object)null) || !((Object)(object)piece != (Object)null)) { return VeiledRecipeVisibilityState.Hidden; } return VeiledRecipeState.GetPieceVisibilityState(player, piece); } public static bool IsUnknownPiecePreview(Piece piece) { return IsUnknownPiecePreview(Player.m_localPlayer, piece); } public static bool IsUnknownPiecePreview(Player player, Piece piece) { if ((Object)(object)player != (Object)null && (Object)(object)piece != (Object)null) { return VeiledRecipeState.IsUnknownPiecePreview(player, piece); } return false; } public static bool ShouldMaskRecipe(Recipe recipe) { return ShouldMaskRecipe(Player.m_localPlayer, recipe); } public static bool ShouldMaskRecipe(Player player, Recipe recipe) { if ((Object)(object)player != (Object)null && (Object)(object)recipe != (Object)null) { return VeiledRecipeState.ShouldMaskRecipe(player, recipe); } return false; } public static bool ShouldMaskRecipePair(RecipeDataPair pair) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return ShouldMaskRecipePair(Player.m_localPlayer, pair); } public static bool ShouldMaskRecipePair(Player player, RecipeDataPair pair) { if ((Object)(object)player != (Object)null && (Object)(object)((RecipeDataPair)(ref pair)).Recipe != (Object)null) { return VeiledRecipeState.ShouldMaskRecipe(player, ((RecipeDataPair)(ref pair)).Recipe, ((RecipeDataPair)(ref pair)).ItemData); } return false; } public static bool IsRecipeActuallyKnown(Player player, Recipe recipe) { if ((Object)(object)player != (Object)null && (Object)(object)recipe != (Object)null) { return VeiledRecipeState.IsRecipeActuallyKnown(player, recipe); } return false; } public static bool ShouldMaskPiece(Piece piece) { return ShouldMaskPiece(Player.m_localPlayer, piece); } public static bool ShouldMaskPiece(Player player, Piece piece) { if ((Object)(object)player != (Object)null && (Object)(object)piece != (Object)null) { return VeiledRecipeState.ShouldMaskPiece(player, piece); } return false; } public static void RegisterKnownPieceOverride(Func<Piece, bool> predicate) { VeiledRecipeState.RegisterKnownPieceOverride(predicate); } public static void UnregisterKnownPieceOverride(Func<Piece, bool> predicate) { VeiledRecipeState.UnregisterKnownPieceOverride(predicate); } public static void RegisterKnownPiecePrefabOverride(string prefabName) { VeiledRecipeState.RegisterKnownPiecePrefabOverride(prefabName); } public static void UnregisterKnownPiecePrefabOverride(string prefabName) { VeiledRecipeState.UnregisterKnownPiecePrefabOverride(prefabName); } public static void RegisterKnownPieceTypeOverride(string typeName) { VeiledRecipeState.RegisterKnownPieceTypeOverride(typeName); } public static void UnregisterKnownPieceTypeOverride(string typeName) { VeiledRecipeState.UnregisterKnownPieceTypeOverride(typeName); } public static bool IsPieceActuallyKnown(Player player, Piece piece) { if ((Object)(object)player != (Object)null && (Object)(object)piece != (Object)null) { return VeiledRecipeState.IsPieceActuallyKnown(player, piece); } return false; } public static bool IsMaterialKnown(Requirement requirement) { return IsMaterialKnown(Player.m_localPlayer, requirement); } public static bool IsMaterialKnown(Player player, Requirement requirement) { if ((Object)(object)player != (Object)null && requirement != null) { return VeiledRecipeState.IsMaterialKnown(player, requirement); } return false; } public static bool KnowsRecipeStationRequirement(Recipe recipe, int quality) { return KnowsRecipeStationRequirement(Player.m_localPlayer, recipe, quality); } public static bool KnowsRecipeStationRequirement(Player player, Recipe recipe, int quality) { if ((Object)(object)player != (Object)null && (Object)(object)recipe != (Object)null) { return VeiledRecipeState.KnowsRecipeStationRequirement(player, recipe, quality); } return false; } public static bool KnowsPieceStationRequirement(Piece piece) { return KnowsPieceStationRequirement(Player.m_localPlayer, piece); } public static bool KnowsPieceStationRequirement(Player player, Piece piece) { if ((Object)(object)player != (Object)null && (Object)(object)piece != (Object)null) { return VeiledRecipeState.KnowsPieceStationRequirement(player, piece); } return false; } } } namespace ServerSync { [PublicAPI] internal abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract Conf