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 DynamicStorage Butchers Hall v1.1.0
plugins/DynamicStorageButchersHall/DynamicStorageButchersHall.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("DynamicStorageMeatRack")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("DynamicStorageMeatRack")] [assembly: AssemblyTitle("DynamicStorageMeatRack")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DynamicStorageMeatRack { internal sealed class ConfigurationManagerAttributes { public int? Order; public bool? IsAdminOnly; public bool? ReadOnly; public bool? Browsable; public bool? IsAdvanced; } [BepInPlugin("com.muji.DynamicStorageMeatRack", "DynamicStorage Meat Rack", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal sealed class DynamicStorageMeatRackPlugin : BaseUnityPlugin { private sealed class MeatVisualConfigEntries { internal ConfigEntry<float> Scale; internal ConfigEntry<float> LengthScale; internal ConfigEntry<float> WidthScale; internal ConfigEntry<float> ThicknessScale; internal ConfigEntry<float> RotationX; internal ConfigEntry<float> RotationY; internal ConfigEntry<float> RotationZ; internal ConfigEntry<float> HeightOffset; internal ConfigEntry<float> AnchorOffsetX; internal ConfigEntry<float> AnchorOffsetY; internal ConfigEntry<float> AnchorOffsetZ; internal ConfigEntry<float> RotationVarianceY; internal ConfigEntry<float> HeightAnchorVariance; internal ConfigEntry<float> ScaleVariance; } private sealed class HookAnchorConfigEntries { internal ConfigEntry<float> OffsetX; internal ConfigEntry<float> OffsetY; internal ConfigEntry<float> OffsetZ; } public const string PluginGuid = "com.muji.DynamicStorageMeatRack"; public const string PluginName = "DynamicStorage Meat Rack"; public const string PluginVersion = "1.1.0"; private const string FunctionalBaseName = "piece_chest_barrel"; private const string RackVisualSourceName = "piece_cookingstation_iron"; private const string MeatRackPrefabName = "DSMR_MeatRack"; private static readonly Vector3[] DefaultHookAnchorOffsets = (Vector3[])(object)new Vector3[5] { new Vector3(0.5f, -0.7f, 0.01f), new Vector3(0.37f, -0.65f, -0.01f), new Vector3(0.03f, -0.7f, 0f), new Vector3(-0.2f, -0.65f, 0f), new Vector3(-0.4f, -0.7f, 0.01f) }; private ConfigEntry<int> storageSlots; private ConfigEntry<string> additionalRawPrefabs; private ConfigEntry<string> additionalCookedPrefabs; private bool catalogReady; private ConfigEntry<MeatRackBehaviour> storageBehaviour; private ConfigEntry<float> rackScale; private ConfigEntry<bool> scaleMeatWithRack; private ConfigEntry<float> rackHeightOffset; private ConfigEntry<string> looksFullAt; private ConfigEntry<bool> advancedHookDebug; private ConfigEntry<bool> globalMeatVisualOverride; private ConfigEntry<bool> showStorageDebugTooltip; private ConfigEntry<bool> showHookAnchorOrb; private ConfigEntry<int> selectedHookAnchor; private readonly HookAnchorConfigEntries[] hookAnchorConfig = new HookAnchorConfigEntries[5]; private readonly Dictionary<string, MeatVisualConfigEntries> meatVisualConfig = new Dictionary<string, MeatVisualConfigEntries>(StringComparer.Ordinal); private readonly Dictionary<string, int> liveCalibrationRevisions = new Dictionary<string, int>(StringComparer.Ordinal); private Harmony harmony; private GameObject registeredPrefab; private Vector3 registeredBaseScale = Vector3.one; private string cachedVisualProfilePayload = string.Empty; private MeatRackEditorWindow editorWindow; private MeatRackAppearance editorTarget; private ZRoutedRpc registeredAdminRpc; private bool editorOpen; private bool previousCursorVisible; private CursorLockMode previousCursorLock; internal static DynamicStorageMeatRackPlugin Current { get; private set; } internal int StorageCapacity => NormalizeStorageCapacity((storageSlots != null) ? storageSlots.Value : 20); internal bool CanEditServerSettings { get { if (!((Object)(object)ZNet.instance == (Object)null)) { return ZNet.instance.LocalPlayerIsAdminOrHost(); } return true; } } internal string AdditionalRawPrefabs { get { if (additionalRawPrefabs == null) { return string.Empty; } return additionalRawPrefabs.Value; } } internal string AdditionalCookedPrefabs { get { if (additionalCookedPrefabs == null) { return string.Empty; } return additionalCookedPrefabs.Value; } } internal bool AdvancedCalibrationEnabled { get { if (advancedHookDebug != null) { return advancedHookDebug.Value; } return false; } } internal bool GlobalMeatVisualOverride { get { if (globalMeatVisualOverride != null) { return globalMeatVisualOverride.Value; } return false; } } internal bool ShowStorageDebugTooltip { get { if (showStorageDebugTooltip != null) { return showStorageDebugTooltip.Value; } return false; } } internal bool AppearanceEditorEnabled => AdvancedCalibrationEnabled; internal bool AdvancedHookDebugEnabled => AdvancedCalibrationEnabled; internal bool HookAnchorDebugOrbEnabled { get { if (AdvancedHookDebugEnabled && showHookAnchorOrb != null) { return showHookAnchorOrb.Value; } return false; } } internal int SelectedHookAnchorIndex => Mathf.Clamp(((selectedHookAnchor != null) ? selectedHookAnchor.Value : 3) - 1, 0, 4); internal bool TrySetServerCapacity(int slots) { if (!CanEditServerSettings || storageSlots == null || (slots != 10 && slots != 20 && slots != 40 && slots != 60)) { return false; } if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { storageSlots.Value = slots; } else if (!SendAdminSetting("capacity", slots.ToString())) { return false; } return true; } internal bool TrySetAdditionalPrefabs(bool cooked, string csv) { if (!CanEditServerSettings) { return false; } ConfigEntry<string> val = (cooked ? additionalCookedPrefabs : additionalRawPrefabs); if (val == null || csv == null || csv.Length > 4096) { return false; } if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { val.Value = csv.Trim(); } else if (!SendAdminSetting(cooked ? "cooked" : "raw", csv.Trim())) { return false; } return true; } private bool SendAdminSetting(string setting, string value) { if (registeredAdminRpc == null || registeredAdminRpc != ZRoutedRpc.instance) { return false; } ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "DSMR_AdminSetting", new object[2] { setting, value }); return true; } private void OnAdminSettingRpc(long sender, string setting, string value) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || peer.m_socket == null || !ZNet.instance.IsAdmin(peer.m_socket.GetHostName())) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Rejected unauthorised Butcher's Hall admin setting request."); } else if (setting == "capacity") { if (int.TryParse(value, out var result) && (result == 10 || result == 20 || result == 40 || result == 60)) { storageSlots.Value = result; } } else if (value != null && value.Length <= 4096 && setting == "raw") { additionalRawPrefabs.Value = value.Trim(); } else if (value != null && value.Length <= 4096 && setting == "cooked") { additionalCookedPrefabs.Value = value.Trim(); } } internal bool GlobalMeatVisualOverrideApplies(string prefabName) { if (!GlobalMeatVisualOverride) { return false; } prefabName = MeatCatalog.CalibrationPrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName)) { return meatVisualConfig.ContainsKey(prefabName); } return false; } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Current = this; BindConfig(); harmony = new Harmony("com.muji.DynamicStorageMeatRack"); PrefabManager.OnPrefabsRegistered += OnPrefabsRegistered; TryInstallHook("inventory restrictions", delegate { MeatRackInventoryPatches.Install(harmony); }); TryInstallHook("capacity protection", delegate { MeatRackCapacityPatches.Install(harmony); }); TryInstallHook("placement", delegate { MeatRackPlacementPatches.Install(harmony); }); TryInstallHook("editor hover", delegate { MeatRackAppearanceEditorPatches.Install(harmony); }); TryInstallHook("build menu", delegate { MeatRackUnlocks.Install(harmony); }); try { if (!GUIManager.IsHeadless()) { GUIManager.OnCustomGUIAvailable += OnEditorGuiAvailable; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Optional Meat Rack editor UI could not initialize: " + ex.Message)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"DynamicStorage Meat Rack 1.1.0 loaded."); } private static void TryInstallHook(string name, Action install) { try { install(); } catch (Exception ex) { Logger.LogError((object)("Meat Rack " + name + " hook failed: " + ex)); } } private void OnDestroy() { try { if (!GUIManager.IsHeadless()) { GUIManager.OnCustomGUIAvailable -= OnEditorGuiAvailable; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Optional Meat Rack editor UI cleanup failed: " + ex.Message)); } if (editorOpen) { SetEditorOpen(open: false); } PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; if (harmony != null) { try { harmony.UnpatchSelf(); } catch { } } if ((Object)(object)Current == (Object)(object)this) { Current = null; } } private void Update() { if (ZRoutedRpc.instance != null && registeredAdminRpc != ZRoutedRpc.instance) { ZRoutedRpc.instance.Register<string, string>("DSMR_AdminSetting", (Action<long, string, string>)OnAdminSettingRpc); registeredAdminRpc = ZRoutedRpc.instance; } if (GUIManager.IsHeadless() || editorWindow == null) { return; } if (!editorOpen && Input.GetKeyDown((KeyCode)112) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && Time.timeScale > 0f && !InventoryGui.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible() && !Console.IsVisible()) { MeatRackAppearance meatRackAppearance = FindHoveredRack(); ZNetView val = (Object.op_Implicit((Object)(object)meatRackAppearance) ? ((Component)meatRackAppearance).GetComponent<ZNetView>() : null); if (Object.op_Implicit((Object)(object)meatRackAppearance) && Object.op_Implicit((Object)(object)val) && val.IsValid() && val.GetZDO() != null) { editorTarget = meatRackAppearance; SetEditorOpen(open: true); return; } } if (editorOpen && Input.GetKeyDown((KeyCode)27)) { SetEditorOpen(open: false); } else if (editorOpen && !Object.op_Implicit((Object)(object)editorTarget)) { editorWindow.RefreshRack(); } } private MeatRackAppearance FindHoveredRack() { Player localPlayer = Player.m_localPlayer; GameObject val = (Object.op_Implicit((Object)(object)localPlayer) ? ((Humanoid)localPlayer).GetHoverObject() : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.GetComponentInParent<MeatRackAppearance>(); } private void OnEditorGuiAvailable() { if (editorOpen) { SetEditorOpen(open: false); } try { MeatRackEditorWindow meatRackEditorWindow = new MeatRackEditorWindow(SetEditorOpen, () => editorTarget, this); meatRackEditorWindow.Build(GUIManager.CustomGUIFront.transform); editorWindow = meatRackEditorWindow; } catch (Exception ex) { editorWindow = null; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Meat Rack Appearance Editor could not open: " + ex.Message)); } } private void SetEditorOpen(bool open) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (editorWindow == null || open == editorOpen) { return; } editorOpen = open; if (open) { previousCursorVisible = Cursor.visible; previousCursorLock = Cursor.lockState; GUIManager.BlockInput(true); Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; editorWindow.SetVisible(visible: true); if (Object.op_Implicit((Object)(object)editorTarget)) { editorTarget.FlashSelectionTwice(); } } else { GUIManager.BlockInput(false); Cursor.lockState = previousCursorLock; Cursor.visible = previousCursorVisible; editorWindow.SetVisible(visible: false); editorTarget = null; } } private void BindConfig() { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Expected O, but got Unknown storageSlots = ConfigFileExtensions.BindConfig<int>(((BaseUnityPlugin)this).Config, "Server Settings", "Meat Rack Slots", 20, "Server-controlled Meat Rack inventory capacity. Existing racks always preserve stored items first; unsafe reductions are deferred or compacted safely. Options: 10, 20, 40, or 60 slots.", true, (int?)100, (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 10, 20, 40, 60 }), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); additionalRawPrefabs = ConfigFileExtensions.BindConfig<string>(((BaseUnityPlugin)this).Config, "Server Settings", "Additional Raw Meat Prefabs", "", "Advanced: comma-separated ItemDrop prefab IDs treated as raw meat. Invalid IDs are ignored. Keep IDs listed while their items remain stored.", true, (int?)90, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); additionalCookedPrefabs = ConfigFileExtensions.BindConfig<string>(((BaseUnityPlugin)this).Config, "Server Settings", "Additional Cooked Meat Prefabs", "", "Advanced: comma-separated ItemDrop prefab IDs treated as cooked meat. Invalid IDs are ignored. Keep IDs listed while their items remain stored.", true, (int?)89, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); additionalRawPrefabs.SettingChanged += delegate { RefreshConfiguredCatalog(); }; additionalCookedPrefabs.SettingChanged += delegate { RefreshConfiguredCatalog(); }; storageBehaviour = ((BaseUnityPlugin)this).Config.Bind<MeatRackBehaviour>("Rack Settings", "Storage Behaviour", MeatRackBehaviour.Auto, new ConfigDescription("Placement template saved per Meat Rack. Raw and cooked meat are always separate storage classes: the first class inserted locks an empty rack until it is emptied. Auto: one meat type grows across the rack; two or more types switch to a top-five mixed display. Single Meat: the first meat prefab locks the rack until empty. Mixed Meat: accepts all supported meats within the rack's current raw/cooked class and shows up to the five most abundant types.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); rackScale = ((BaseUnityPlugin)this).Config.Bind<float>("Rack Settings", "Rack Scale", 1f, new ConfigDescription("Placement-template scale for newly placed Meat Racks. Existing racks keep their saved scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), new object[1] { new ConfigurationManagerAttributes { Order = 95 } })); scaleMeatWithRack = ((BaseUnityPlugin)this).Config.Bind<bool>("Rack Settings", "Scale Meat With Rack", true, new ConfigDescription("When enabled, hanging meat scales proportionally with Rack Scale. When disabled, meat keeps its calibrated world size. Saved per placed rack.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 94 } })); rackHeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Rack Settings", "Rack Visual Height Offset", 0f, new ConfigDescription("Vertical offset applied to the reconstructed Iron Cooking Station visual and its transplanted blocking colliders. The placed gameplay/container root remains fixed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 2f), new object[1] { new ConfigurationManagerAttributes { Order = 90 } })); looksFullAt = ((BaseUnityPlugin)this).Config.Bind<string>("Rack Settings", "Looks Full At (Single-Meat Display)", "50% Occupied Slots", new ConfigDescription("Controls when all five hooks are visually occupied in Single Meat mode, and in Auto mode while only one meat type is stored. Occupied-slot percentages scale with the rack's current effective capacity. Mixed display is unaffected.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[10] { "25% Occupied Slots", "50% Occupied Slots", "75% Occupied Slots", "100% Occupied Slots", "10 Meat", "20 Meat", "40 Meat", "60 Meat", "100 Meat", "Always Full" }), new object[1] { new ConfigurationManagerAttributes { Order = 85 } })); BindHookAnchorCalibrationConfig(); int num = 0; foreach (MeatDefinition definition in MeatCatalog.Definitions) { if (definition.PrefabName != "FishAnglerRaw") { BindMeatVisualConfig(definition, num); } num++; } storageSlots.SettingChanged += delegate { MeatRackCapacity.RefreshAll(); MeatRackStorage.RefreshAllVisuals(); }; rackScale.SettingChanged += delegate { RefreshPlacementTemplateScale(); }; rackHeightOffset.SettingChanged += delegate { MeatRackStorage.RefreshAllVisuals(); }; RebuildCachedVisualProfile(); } internal MeatVisualTuning GetDefaultMeatVisualTuning(string prefabName) { switch (MeatCatalog.CalibrationPrefabName(prefabName)) { case "RawMeat": return new MeatVisualTuning(1.12f, 1f, 1f, 1f, 18f, -156f, 6f, 0.33f, 0.03f, 0.03f, 0.02f, 180f, 0.05f, 0.35f); case "DeerMeat": return new MeatVisualTuning(1.2f, 1f, 1f, 1f, 0f, -62f, 0f, 0.1f, 0f, -0.03f, 0f, 180f, 0.16f, 0.4f); case "NeckTail": return new MeatVisualTuning(1f, 1f, 1f, 1f, 174f, 48f, 0f, 0.13f, 0.04f, 0.02f, 0.02f, 75f, 0.07f, 0.38f); case "BjornMeat": return new MeatVisualTuning(1.2f, 1f, 1f, 0.65f, -9f, 180f, 0f, 0.14f, -0.02f, 0f, -0.05f, 39f, 0.1f, 0.5f); case "SerpentMeat": return new MeatVisualTuning(0.75f, 1f, 1f, 0.7f, 0f, 60f, 36f, 0.23f, 0f, 0f, 0f, 24f, 0f, 0.2f); case "WolfMeat": return new MeatVisualTuning(1f, 1f, 1f, 1f, 0f, 54f, -6f, 0.33f, 0.03f, -0.05f, 0.02f, 180f, 0.06f, 0.4f); case "LoxMeat": return new MeatVisualTuning(1f, 1f, 1f, 1f, -162f, -72f, -9f, 0.33f, 0.03f, -0.02f, 0.05f, 180f, 0.09f, 0.35f); case "ChickenMeat": return new MeatVisualTuning(1.25f, 1f, 1f, 1f, 3f, -3f, 0f, 0.03f, 0f, 0.12f, -0.02f, 180f, 0.05f, 0.15f); case "HareMeat": return new MeatVisualTuning(0.8f, 1f, 1f, 1f, 6f, 12f, 0f, 0.4f, 0f, 0.05f, 0.03f, 64.5f, 0f, 0.3f); case "BugMeat": return new MeatVisualTuning(1f, 1f, 1f, 1f, 3f, 0f, 3f, 0f, -0.03f, 0.13f, 0f, 49.5f, 0.05f, 0.35f); case "AsksvinMeat": return new MeatVisualTuning(1f, 1f, 1f, 1f, 174f, 48f, 0f, 0.13f, 0.04f, 0.02f, 0.02f, 75f, 0.07f, 0.38f); case "VoltureMeat": return new MeatVisualTuning(0.75f, 1f, 1f, 1f, 0f, 33f, 0f, 0.1f, -0.03f, 0f, 0f, 180f, 0.05f, 0.3f); case "BoneMawSerpentMeat": return new MeatVisualTuning(0.75f, 1f, 1f, 0.7f, 0f, 60f, 36f, 0.23f, 0f, 0f, 0f, 24f, 0f, 0.2f); case "MooseMeat": return new MeatVisualTuning(0.57f, 0.9f, 1f, 1f, 1f, 126f, 0f, 0.2f, 0.03f, 0f, 0.12f, 39f, 0.05f, 0.5f); case "SealBlubber": return new MeatVisualTuning(1.5f, 1f, 1f, 1f, 0f, -126f, 15f, 0.13f, 0f, 0.03f, 0.08f, 141f, 0.05f, 0.33f); case "FishRaw": case "FishCooked": case "SmokedFish": return FishPreset(1.1f, 0f, 0.13f, 0f, 0f, 0f, 80f, 0f, 0.5f); case "FishAnglerRaw": return FishPreset(0.72f, -18f, 0.16f, 0.01f, 0.04f, -0.02f, 15f, 0.02f, 0.06f); case "Fish1": return FishPreset(1.2f, 15f, 0.13f, 0.02f, 0.03f, 0.02f, 100f, 0.02f, 0.4f); case "Fish2": return FishPreset(0.79f, 100f, 0.14f, 0f, 0f, 0f, 100f, 0.1f, 0.35f); case "Fish3": return FishPreset(0.7f, 81f, 0.13f, 0f, 0f, 0f, 60.5f, 0.06f, 0.4f); case "Fish4_cave": return FishPreset(1.2f, 19f, 0.09f, 0f, 0.01f, 0f, 114f, 0.08f, 0.5f); case "Fish5": return FishPreset(0.8f, 39f, 0.13f, 0f, 0f, 0f, 120f, 0.03f, 0.5f); case "Fish6": return FishPreset(1.2f, 60f, 0.13f, 0f, 0f, 0f, 120f, 0.04f, 0.3f); case "Fish7": return FishPreset(1f, 45f, 0.13f, 0f, 0f, 0f, 135.5f, 0.03f, 0.35f); case "Fish8": return FishPreset(0.9f, 50f, 0.13f, 0f, 0f, 0f, 75f, 0f, 0.4f); case "Fish9": return FishPreset(0.7f, 18f, 0.1f, 0f, 0.04f, -0.02f, 100f, 0f, 0.25f); case "Fish10": return FishPreset(0.6f, 97f, 0.17f, 0f, 0.03f, 0.02f, 84.5f, 0.07f, 0.5f); case "Fish11": return FishPreset(1f, 45f, 0.2f, 0f, 0f, 0f, 60.5f, 0.03f, 0.5f); case "Fish12": return FishPreset(1.1f, -105f, 0.13f, 0f, 0.08f, 0f, 180f, 0.08f, 0.5f); default: return new MeatVisualTuning(1f, 1f, 1f, 1f, 0f, 0f, 0f, 0f); } } private static MeatVisualTuning FishPreset(float scale, float rotationY, float height, float anchorX, float anchorY, float anchorZ, float rotationVarianceY, float heightAnchorVariance, float scaleVariance) { return new MeatVisualTuning(scale, 1f, 1f, 1f, 0f, rotationY, 0f, height, anchorX, anchorY, anchorZ, rotationVarianceY, heightAnchorVariance, scaleVariance); } private void BindMeatVisualConfig(MeatDefinition definition, int index) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Expected O, but got Unknown //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Expected O, but got Unknown //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Expected O, but got Unknown //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Expected O, but got Unknown //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Expected O, but got Unknown //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Expected O, but got Unknown //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Expected O, but got Unknown //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Expected O, but got Unknown //IL_055f: Unknown result type (might be due to invalid IL or missing references) //IL_0569: Expected O, but got Unknown string text = "Advanced Meat Visual - " + (index + 1).ToString("00") + " " + definition.DisplayName; MeatVisualConfigEntries meatVisualConfigEntries = new MeatVisualConfigEntries(); MeatVisualTuning defaultMeatVisualTuning = GetDefaultMeatVisualTuning(definition.PrefabName); meatVisualConfigEntries.Scale = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Scale", defaultMeatVisualTuning.Scale, new ConfigDescription("Base scale for this meat model when hanging on the rack.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), new object[1] { new ConfigurationManagerAttributes { Order = 100, IsAdvanced = true } })); meatVisualConfigEntries.LengthScale = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Length Scale (Long Axis)", defaultMeatVisualTuning.LengthScale, new ConfigDescription("Shape multiplier along this meat model's longest source-model axis. Use this to make a cut longer/shorter without making it uniformly chunkier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 98, IsAdvanced = true } })); meatVisualConfigEntries.WidthScale = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Width Scale", defaultMeatVisualTuning.WidthScale, new ConfigDescription("Shape multiplier along this meat model's second-largest source-model axis. This changes width independently from overall Scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 97, IsAdvanced = true } })); meatVisualConfigEntries.ThicknessScale = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Thickness / Height Scale", defaultMeatVisualTuning.ThicknessScale, new ConfigDescription("Shape multiplier along this meat model's smallest source-model axis. Use this to flatten or thicken the cut independently from length/width.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 96, IsAdvanced = true } })); meatVisualConfigEntries.RotationX = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Rotation X", defaultMeatVisualTuning.RotationX, new ConfigDescription("Base X-axis rotation applied after the automatic long-axis hanging orientation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[1] { new ConfigurationManagerAttributes { Order = 95, IsAdvanced = true } })); meatVisualConfigEntries.RotationY = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Rotation Y (Twist)", defaultMeatVisualTuning.RotationY, new ConfigDescription("Base Y-axis twist around the vertical hanging axis after automatic long-axis orientation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[1] { new ConfigurationManagerAttributes { Order = 92, IsAdvanced = true } })); meatVisualConfigEntries.RotationZ = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Rotation Z", defaultMeatVisualTuning.RotationZ, new ConfigDescription("Base Z-axis rotation applied after the automatic long-axis hanging orientation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[1] { new ConfigurationManagerAttributes { Order = 90, IsAdvanced = true } })); meatVisualConfigEntries.HeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Height Offset", defaultMeatVisualTuning.HeightOffset, new ConfigDescription("Base vertical offset for this meat model after it is aligned to the rack hook.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 2f), new object[1] { new ConfigurationManagerAttributes { Order = 85, IsAdvanced = true } })); meatVisualConfigEntries.AnchorOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Anchor Offset X", defaultMeatVisualTuning.AnchorOffsetX, new ConfigDescription("Additional per-meat local offset from the selected rack hook anchor on the X axis. Use this to fine-tune where the meat actually attaches without changing the shared hook calibration.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 84, IsAdvanced = true } })); meatVisualConfigEntries.AnchorOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Anchor Offset Y", defaultMeatVisualTuning.AnchorOffsetY, new ConfigDescription("Additional per-meat local offset from the selected rack hook anchor on the Y axis. Useful for getting awkward cuts to sit directly on the hook.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 83, IsAdvanced = true } })); meatVisualConfigEntries.AnchorOffsetZ = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Anchor Offset Z", defaultMeatVisualTuning.AnchorOffsetZ, new ConfigDescription("Additional per-meat local offset from the selected rack hook anchor on the Z axis.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 82, IsAdvanced = true } })); meatVisualConfigEntries.RotationVarianceY = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Rotation Y Variance", defaultMeatVisualTuning.RotationVarianceY, new ConfigDescription("Deterministic rack-specific +/- twist variance around the meat's Y axis. Useful for meats that can hang naturally at multiple twists.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 180f), new object[1] { new ConfigurationManagerAttributes { Order = 81, IsAdvanced = true } })); meatVisualConfigEntries.HeightAnchorVariance = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Height Anchor Variance", defaultMeatVisualTuning.HeightAnchorVariance, new ConfigDescription("Deterministic vertical variation applied inward into the hook while keeping the calibrated attachment point fixed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.3f), new object[1] { new ConfigurationManagerAttributes { Order = 80, IsAdvanced = true } })); meatVisualConfigEntries.ScaleVariance = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Scale Variance", defaultMeatVisualTuning.ScaleVariance, new ConfigDescription("Deterministic rack-specific +/- proportional scale variation for this meat. 0.10 means up to +/-10%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), new object[1] { new ConfigurationManagerAttributes { Order = 78, IsAdvanced = true } })); meatVisualConfigEntries.Scale.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.LengthScale.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.WidthScale.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.ThicknessScale.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.RotationX.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.RotationY.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.RotationZ.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.HeightOffset.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.AnchorOffsetX.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.AnchorOffsetY.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.AnchorOffsetZ.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.RotationVarianceY.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.HeightAnchorVariance.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfigEntries.ScaleVariance.SettingChanged += delegate { PreviewMeatCalibrationChange(definition.PrefabName); }; meatVisualConfig[definition.PrefabName] = meatVisualConfigEntries; } private void PreviewMeatCalibrationChange(string prefabName) { prefabName = MeatCatalog.CalibrationPrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName)) { liveCalibrationRevisions.TryGetValue(prefabName, out var value); liveCalibrationRevisions[prefabName] = value + 1; } RebuildCachedVisualProfile(); MeatRackStorage.RefreshAllAppearanceVisuals(); } internal int GetLiveCalibrationRevision(string prefabName) { prefabName = MeatCatalog.CalibrationPrefabName(prefabName); if (string.IsNullOrEmpty(prefabName) || !liveCalibrationRevisions.TryGetValue(prefabName, out var value)) { return 0; } return value; } internal MeatVisualTuning GetMeatVisualTuning(string prefabName) { prefabName = MeatCatalog.CalibrationPrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName) && meatVisualConfig.TryGetValue(prefabName, out var value)) { return new MeatVisualTuning(Mathf.Clamp(value.Scale.Value, 0.05f, 5f), Mathf.Clamp(value.LengthScale.Value, 0.25f, 3f), Mathf.Clamp(value.WidthScale.Value, 0.25f, 3f), Mathf.Clamp(value.ThicknessScale.Value, 0.25f, 3f), NormalizeAngle(value.RotationX.Value), NormalizeAngle(value.RotationY.Value), NormalizeAngle(value.RotationZ.Value), Mathf.Clamp(value.HeightOffset.Value, -2f, 2f), Mathf.Clamp(value.AnchorOffsetX.Value, -1f, 1f), Mathf.Clamp(value.AnchorOffsetY.Value, -1f, 1f), Mathf.Clamp(value.AnchorOffsetZ.Value, -1f, 1f), Mathf.Clamp(value.RotationVarianceY.Value, 0f, 180f), Mathf.Clamp(value.HeightAnchorVariance.Value, 0f, 0.3f), Mathf.Clamp(value.ScaleVariance.Value, 0f, 0.5f)); } return new MeatVisualTuning(1f, 1f, 1f, 1f, 0f, 0f, 0f, 0f); } private void BindHookAnchorCalibrationConfig() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Expected O, but got Unknown //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Expected O, but got Unknown //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Expected O, but got Unknown showStorageDebugTooltip = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced Debug", "Show Storage Debug Tooltip", false, new ConfigDescription("Advanced/debug only. Shows live Meat Rack capacity, grid and item-safety diagnostics in the hover text. Real storage-safety warnings remain visible even when this is disabled.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 110, IsAdvanced = true } })); advancedHookDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced Debug", "Enable Calibration Tools", false, new ConfigDescription("Advanced/debug only. Enables the Meat Rack calibration hover, apply hotkey, hook-anchor orb controls and live advanced meat/hook tuning. Leave disabled for normal play.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 100, IsAdvanced = true } })); globalMeatVisualOverride = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced Debug", "Use Global Meat Visual Tuning On All Racks", false, new ConfigDescription("Advanced/debug only. While enabled, every rack displays current Configuration Manager meat and fish size, rotation, anchor and variation values ahead of saved per-rack tuning for items with global controls. Custom prefab IDs without global controls keep their per-rack tuning. This visual override does not save to placed racks; turn it off to restore their saved appearances.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99, IsAdvanced = true } })); showHookAnchorOrb = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced Debug - Hook Anchor Calibration", "Show Anchor Orb", false, new ConfigDescription("Advanced/debug only: show a small emissive/lighted orb at the selected meat-hook anchor on the focused Meat Rack.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 100, IsAdvanced = true } })); selectedHookAnchor = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced Debug - Hook Anchor Calibration", "Selected Hook", 3, new ConfigDescription("Advanced/debug only. Hook anchor selected for the debug orb. Hooks are numbered left-to-right 1 through 5.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), new object[1] { new ConfigurationManagerAttributes { Order = 95, IsAdvanced = true } })); advancedHookDebug.SettingChanged += delegate { MeatRackVisual.RefreshAllDebugMarkers(); }; globalMeatVisualOverride.SettingChanged += delegate { MeatRackStorage.RefreshAllAppearanceVisuals(); }; showHookAnchorOrb.SettingChanged += delegate { MeatRackVisual.RefreshAllDebugMarkers(); }; selectedHookAnchor.SettingChanged += delegate { MeatRackVisual.RefreshAllDebugMarkers(); }; for (int num = 0; num < 5; num++) { int num2 = num + 1; string text = "Advanced Debug - Hook Anchor " + num2; HookAnchorConfigEntries hookAnchorConfigEntries = new HookAnchorConfigEntries(); Vector3 val = DefaultHookAnchorOffsets[num]; hookAnchorConfigEntries.OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Offset X", val.x, new ConfigDescription("Advanced/debug calibration offset from the automatically estimated Hook " + num2 + " X position. Defaults retain the refined hook-inside calibration values for the vanilla Iron Cooking Station.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1.5f, 1.5f), new object[1] { new ConfigurationManagerAttributes { Order = 100, IsAdvanced = true } })); hookAnchorConfigEntries.OffsetY = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Offset Y", val.y, new ConfigDescription("Advanced/debug calibration offset from the automatically estimated Hook " + num2 + " Y position.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1.5f, 1.5f), new object[1] { new ConfigurationManagerAttributes { Order = 95, IsAdvanced = true } })); hookAnchorConfigEntries.OffsetZ = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Offset Z", val.z, new ConfigDescription("Advanced/debug calibration offset from the automatically estimated Hook " + num2 + " Z position.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1.5f, 1.5f), new object[1] { new ConfigurationManagerAttributes { Order = 90, IsAdvanced = true } })); hookAnchorConfigEntries.OffsetX.SettingChanged += delegate { RebuildCachedVisualProfile(); MeatRackStorage.RefreshAllVisuals(); MeatRackVisual.RefreshAllDebugMarkers(); }; hookAnchorConfigEntries.OffsetY.SettingChanged += delegate { RebuildCachedVisualProfile(); MeatRackStorage.RefreshAllVisuals(); MeatRackVisual.RefreshAllDebugMarkers(); }; hookAnchorConfigEntries.OffsetZ.SettingChanged += delegate { RebuildCachedVisualProfile(); MeatRackStorage.RefreshAllVisuals(); MeatRackVisual.RefreshAllDebugMarkers(); }; hookAnchorConfig[num] = hookAnchorConfigEntries; } } internal Vector3 GetHookAnchorOffset(int hookIndex) { //IL_0070: 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) hookIndex = Mathf.Clamp(hookIndex, 0, 4); HookAnchorConfigEntries hookAnchorConfigEntries = hookAnchorConfig[hookIndex]; if (hookAnchorConfigEntries == null) { return DefaultHookAnchorOffsets[hookIndex]; } return new Vector3(Mathf.Clamp(hookAnchorConfigEntries.OffsetX.Value, -1.5f, 1.5f), Mathf.Clamp(hookAnchorConfigEntries.OffsetY.Value, -1.5f, 1.5f), Mathf.Clamp(hookAnchorConfigEntries.OffsetZ.Value, -1.5f, 1.5f)); } internal int CycleSelectedHookAnchor(int direction) { int selectedHookAnchorIndex = SelectedHookAnchorIndex; if (!AdvancedHookDebugEnabled) { return selectedHookAnchorIndex; } int num = (selectedHookAnchorIndex + ((direction >= 0) ? 1 : (-1)) + 5) % 5; if (selectedHookAnchor != null) { selectedHookAnchor.Value = num + 1; } return num; } internal bool ToggleHookAnchorDebugOrb() { if (!AdvancedHookDebugEnabled || showHookAnchorOrb == null) { return false; } showHookAnchorOrb.Value = !showHookAnchorOrb.Value; return showHookAnchorOrb.Value; } internal MeatRackAppearanceTemplate GetAppearanceTemplate() { if (string.IsNullOrEmpty(cachedVisualProfilePayload)) { RebuildCachedVisualProfile(); } return new MeatRackAppearanceTemplate(Mathf.Clamp((rackScale != null) ? rackScale.Value : 1f, 0.5f, 2f), Mathf.Clamp((rackHeightOffset != null) ? rackHeightOffset.Value : 0f, -2f, 2f), scaleMeatWithRack == null || scaleMeatWithRack.Value, (storageBehaviour != null) ? storageBehaviour.Value : MeatRackBehaviour.Auto, ParseLooksFullAt((looksFullAt != null) ? looksFullAt.Value : "50% Occupied Slots"), cachedVisualProfilePayload); } private void RebuildCachedVisualProfile() { cachedVisualProfilePayload = MeatRackVisualProfile.Capture(this).Serialize(); } private static LooksFullAtMode ParseLooksFullAt(string value) { return value switch { "25% Occupied Slots" => LooksFullAtMode.OccupiedSlots25Percent, "50% Occupied Slots" => LooksFullAtMode.OccupiedSlots50Percent, "75% Occupied Slots" => LooksFullAtMode.OccupiedSlots75Percent, "100% Occupied Slots" => LooksFullAtMode.OccupiedSlots100Percent, "10 Meat" => LooksFullAtMode.MeatCount10, "20 Meat" => LooksFullAtMode.MeatCount20, "40 Meat" => LooksFullAtMode.MeatCount40, "60 Meat" => LooksFullAtMode.MeatCount60, "100 Meat" => LooksFullAtMode.MeatCount100, "Always Full" => LooksFullAtMode.AlwaysFull, _ => LooksFullAtMode.OccupiedSlots50Percent, }; } internal static string LooksFullAtDisplayName(LooksFullAtMode mode) { return mode switch { LooksFullAtMode.OccupiedSlots25Percent => "25% occupied slots", LooksFullAtMode.OccupiedSlots50Percent => "50% occupied slots", LooksFullAtMode.OccupiedSlots75Percent => "75% occupied slots", LooksFullAtMode.OccupiedSlots100Percent => "100% occupied slots", LooksFullAtMode.MeatCount10 => "10 meat", LooksFullAtMode.MeatCount20 => "20 meat", LooksFullAtMode.MeatCount40 => "40 meat", LooksFullAtMode.MeatCount60 => "60 meat", LooksFullAtMode.MeatCount100 => "100 meat", LooksFullAtMode.AlwaysFull => "Always full", _ => mode.ToString(), }; } private void OnPrefabsRegistered() { PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; catalogReady = true; try { MeatCatalog.Initialize(AdditionalRawPrefabs, AdditionalCookedPrefabs); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Meat/fish catalogue initialization failed; registering Meat Rack anyway: " + ex)); } finally { RegisterMeatRack(); } } private void RefreshConfiguredCatalog() { if (!catalogReady) { return; } try { MeatCatalog.Initialize(AdditionalRawPrefabs, AdditionalCookedPrefabs); MeatRackStorage.RefreshAllVisuals(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Custom meat/fish list refresh failed: " + ex)); } } private void RegisterMeatRack() { //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Expected O, but got Unknown //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Expected O, but got Unknown //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Expected O, but got Unknown //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Expected O, but got Unknown //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Expected O, but got Unknown GameObject val = FindPrefab("piece_chest_barrel"); GameObject val2 = FindPrefab("piece_cookingstation_iron"); if (!Object.op_Implicit((Object)(object)val)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not create Meat Rack: functional source 'piece_chest_barrel' was not found."); return; } if (!Object.op_Implicit((Object)(object)val2)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not create Meat Rack: visual source 'piece_cookingstation_iron' was not found."); return; } Piece component = val.GetComponent<Piece>(); ZNetView component2 = val.GetComponent<ZNetView>(); WearNTear component3 = val.GetComponent<WearNTear>(); Container component4 = val.GetComponent<Container>(); Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true); Piece component5 = val2.GetComponent<Piece>(); Renderer[] componentsInChildren2 = val2.GetComponentsInChildren<Renderer>(true); Collider[] componentsInChildren3 = val2.GetComponentsInChildren<Collider>(true); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component3) || !Object.op_Implicit((Object)(object)component4) || componentsInChildren.Length == 0) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not create Meat Rack: 'piece_chest_barrel' was not the expected complete container (Piece=" + Bool((Object)(object)component) + ", ZNetView=" + Bool((Object)(object)component2) + ", WearNTear=" + Bool((Object)(object)component3) + ", " + $"Container={Bool((Object)(object)component4)}, Colliders={componentsInChildren.Length}).")); return; } if (!Object.op_Implicit((Object)(object)component5) || componentsInChildren2.Length == 0) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not create Meat Rack: 'piece_cookingstation_iron' did not expose the expected visual piece " + $"(Piece={Bool((Object)(object)component5)}, Renderers={componentsInChildren2.Length}).")); return; } GameObject val3 = PrefabManager.Instance.CreateClonedPrefab("DSMR_MeatRack", val); if (!Object.op_Implicit((Object)(object)val3)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not clone the known-good DynamicStorage container root for the Meat Rack."); return; } Renderer[] componentsInChildren4 = val3.GetComponentsInChildren<Renderer>(true); int num = 0; Renderer[] array = componentsInChildren4; foreach (Renderer val4 in array) { if (Object.op_Implicit((Object)(object)val4)) { val4.enabled = false; num++; } } int meshRendererCount; int skinnedRendererCount; Vector3 alignmentOffset; GameObject val5 = CreateRackVisual(val3, val2, out meshRendererCount, out skinnedRendererCount, out alignmentOffset); if (!Object.op_Implicit((Object)(object)val5)) { Object.DestroyImmediate((Object)(object)val3); return; } RackColliderReconstructor.Result result; GameObject val6 = CreateRackCollision(val3, val2, alignmentOffset, out result); if (!Object.op_Implicit((Object)(object)val6)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Iron Cooking Station blocking collision could not be reconstructed. The inherited barrel collider remains active as a fallback."); } Piece component6 = val3.GetComponent<Piece>(); component6.m_name = "Dynamic Meat Rack"; component6.m_description = "Dynamic raw or cooked meat storage. The first meat class inserted locks the rack to raw or cooked until it is emptied; raw and cooked meat can never be mixed."; if (Object.op_Implicit((Object)(object)component5.m_icon)) { component6.m_icon = component5.m_icon; } Container component7 = val3.GetComponent<Container>(); component7.m_name = "Dynamic Meat Rack"; int width; int height; if (MeatRackCapacityPatches.ProtectionAvailable) { GetStorageGrid(StorageCapacity, out width, out height); } else { width = 10; height = 10; } component7.m_width = width; component7.m_height = height; if (!Object.op_Implicit((Object)(object)val3.GetComponent<MeatRackCapacity>())) { val3.AddComponent<MeatRackCapacity>(); } if (!Object.op_Implicit((Object)(object)val3.GetComponent<MeatRackStorage>())) { val3.AddComponent<MeatRackStorage>(); } if (!Object.op_Implicit((Object)(object)val3.GetComponent<MeatRackVisual>())) { val3.AddComponent<MeatRackVisual>(); } registeredBaseScale = val3.transform.localScale; MeatRackAppearance meatRackAppearance = val3.GetComponent<MeatRackAppearance>(); if (!Object.op_Implicit((Object)(object)meatRackAppearance)) { meatRackAppearance = val3.AddComponent<MeatRackAppearance>(); } meatRackAppearance.Setup(registeredBaseScale); MeatRackAppearanceTemplate appearanceTemplate = GetAppearanceTemplate(); val3.transform.localScale = Multiply(registeredBaseScale, appearanceTemplate.RackScale); val5.transform.localPosition = Vector3.up * appearanceTemplate.HeightOffset; if (Object.op_Implicit((Object)(object)val6)) { val6.transform.localPosition = Vector3.up * appearanceTemplate.HeightOffset; } WearNTear component8 = val3.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component8)) { component8.m_autoCreateFragments = false; } PieceConfig val7 = new PieceConfig { PieceTable = PieceTables.Hammer, Category = "Dynamic Storage", CraftingStation = "piece_workbench" }; val7.AddRequirement(new RequirementConfig("Wood", 10, 0, true)); val7.AddRequirement(new RequirementConfig("LeatherScraps", 2, 0, true)); val7.AddRequirement(new RequirementConfig("Flint", 2, 0, true)); CustomPiece val8 = new CustomPiece(val3, true, val7); if (!PieceManager.Instance.AddPiece(val8)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Jotunn PieceManager rejected 'Meat Rack'."); return; } registeredPrefab = val3; MeatRackUnlocks.RegisterPiece(component6); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Registered Meat Rack 1.1.0: functionalRoot='piece_chest_barrel', visualSource='piece_cookingstation_iron', " + $"preservedContainerColliders={componentsInChildren.Length}, sourceRackColliders={componentsInChildren3.Length}, " + $"reconstructedRackBlockingColliders={result.ReconstructedColliderCount}, skippedRackTriggers={result.TriggerColliderCount}, " + $"hiddenContainerRenderers={num}, rackMeshRenderers={meshRendererCount}, rackSkinnedRenderers={skinnedRendererCount}, " + $"capacity={StorageCapacity} ({width}x{height}), enabledMeats={MeatCatalog.SupportedCount}, targetMeatsFound={MeatCatalog.FoundCount}/{MeatCatalog.CandidateCount}.")); } private GameObject CreateRackVisual(GameObject prefab, GameObject rackSource, out int meshRendererCount, out int skinnedRendererCount, out Vector3 alignmentOffset) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) meshRendererCount = 0; skinnedRendererCount = 0; alignmentOffset = Vector3.zero; GameObject val = new GameObject("DSMR_IronRackVisual"); val.transform.SetParent(prefab.transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; val.layer = prefab.layer; RackVisualReconstructor.Result result = RackVisualReconstructor.Build(rackSource, val.transform, val.layer); meshRendererCount = result.MeshRendererCount; skinnedRendererCount = result.SkinnedRendererCount; alignmentOffset = result.AlignmentOffset; if (result.TotalRendererCount <= 0) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not reconstruct any renderable mesh from the Iron Cooking Station visual source."); Object.DestroyImmediate((Object)(object)val); return null; } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] obj = new string[5] { "Iron Cooking Station reconstruction created ", result.TotalRendererCount.ToString(), " visual part(s); sanitized ", null, null }; int sanitizedTransformCount = result.SanitizedTransformCount; obj[3] = sanitizedTransformCount.ToString(); obj[4] = " obviously scene-space transform(s). Hook-anchor calibration is available through Advanced Calibration Tools."; logger.LogInfo((object)string.Concat(obj)); return val; } private GameObject CreateRackCollision(GameObject prefab, GameObject rackSource, Vector3 visualAlignmentOffset, out RackColliderReconstructor.Result result) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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) result = new RackColliderReconstructor.Result(0, 0, 0, 0, 0); GameObject val = new GameObject("DSMR_IronRackCollision"); val.transform.SetParent(prefab.transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; val.layer = prefab.layer; result = RackColliderReconstructor.Build(rackSource, val.transform, visualAlignmentOffset); if (result.ReconstructedColliderCount <= 0) { Object.DestroyImmediate((Object)(object)val); return null; } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; int reconstructedColliderCount = result.ReconstructedColliderCount; logger.LogInfo((object)("Iron Cooking Station collision reconstruction created " + reconstructedColliderCount + " blocking collider(s) aligned to the rebuilt rack visual. The inherited barrel collider remains enabled as an interaction fallback.")); return val; } private static GameObject FindPrefab(string prefabName) { GameObject val = null; if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { val = ZNetScene.instance.GetPrefab(prefabName); } if (!Object.op_Implicit((Object)(object)val)) { val = PrefabManager.Instance.GetPrefab(prefabName); } return val; } private void RefreshPlacementTemplateScale() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)registeredPrefab)) { registeredPrefab.transform.localScale = Multiply(registeredBaseScale, GetAppearanceTemplate().RackScale); } } internal static int NormalizeStorageCapacity(int value) { if (value == 10) { return 10; } if (value == 20) { return 20; } if (value == 40) { return 40; } if (value == 60) { return 60; } if (value >= 60) { return 60; } return 20; } private static int NormalizeSafeCapacity(int value) { switch (value) { case 10: return 10; case 20: return 20; case 40: return 40; case 60: return 60; default: _ = 80; return 80; } } internal static void GetSafeStorageGrid(int capacity, out int width, out int height) { switch (NormalizeSafeCapacity(capacity)) { case 10: width = 5; height = 2; break; case 20: width = 5; height = 4; break; case 40: width = 8; height = 5; break; case 60: width = 6; height = 10; break; case 80: width = 8; height = 10; break; default: width = 8; height = 10; break; } } internal static void GetStorageGrid(int capacity, out int width, out int height) { GetSafeStorageGrid(capacity, out width, out height); } private static float NormalizeAngle(float value) { return Mathf.Repeat(value + 180f, 360f) - 180f; } private static Vector3 Multiply(Vector3 value, float multiplier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector3(value.x * multiplier, value.y * multiplier, value.z * multiplier); } private static string Bool(Object value) { if (!Object.op_Implicit(value)) { return "no"; } return "yes"; } } internal static class MeatRackPlacementPatches { private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); internal static bool Install(Harmony harmony) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown if (harmony == null) { return false; } bool result = true; MethodInfo methodInfo = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null) ?? AccessTools.Method(typeof(Player), "UpdatePlacementGhost", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(MeatRackPlacementPatches), "UpdatePlacementGhostPostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogWarning((object)"Meat Rack placement-ghost hook was not found in this Valheim build."); result = false; } else { try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { Logger.LogWarning((object)("Meat Rack placement-ghost hook failed: " + ex.Message)); result = false; } } MethodInfo methodInfo3 = AccessTools.Method(typeof(MeatRackPlacementPatches), "SetCreatorPostfix", (Type[])null, (Type[])null); bool flag = false; MethodInfo[] methods = typeof(Piece).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo4 in methods) { ParameterInfo[] parameters = methodInfo4.GetParameters(); if (!(methodInfo4.Name != "SetCreator") && parameters.Length != 0 && !(parameters[0].ParameterType != typeof(long))) { try { harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); flag = true; } catch (Exception ex2) { Logger.LogWarning((object)("Meat Rack placement snapshot hook failed: " + ex2.Message)); } } } if (!flag) { Logger.LogWarning((object)"No compatible Piece.SetCreator overload was found for Meat Rack appearance snapshots."); result = false; } return result; } private static void UpdatePlacementGhostPostfix(Player __instance) { if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || PlacementGhostField == null) { return; } GameObject val; try { object? value = PlacementGhostField.GetValue(__instance); val = (GameObject)((value is GameObject) ? value : null); } catch { return; } if (!Object.op_Implicit((Object)(object)val)) { return; } MeatRackAppearance component = val.GetComponent<MeatRackAppearance>(); if (Object.op_Implicit((Object)(object)component)) { DynamicStorageMeatRackPlugin current = DynamicStorageMeatRackPlugin.Current; if (!((Object)(object)current == (Object)null)) { MeatRackAppearanceTemplate appearanceTemplate = current.GetAppearanceTemplate(); component.ApplyPlacementPreview(appearanceTemplate.RackScale, appearanceTemplate.HeightOffset); } } } private static void SetCreatorPostfix(Piece __instance) { try { if (Object.op_Implicit((Object)(object)__instance)) { MeatRackAppearance component = ((Component)__instance).GetComponent<MeatRackAppearance>(); if (Object.op_Implicit((Object)(object)component)) { component.SavePlacementDefaults(); } MeatRackCapacity component2 = ((Component)__instance).GetComponent<MeatRackCapacity>(); if (Object.op_Implicit((Object)(object)component2)) { component2.InitializeNewPlacement(); } } } catch (Exception ex) { Logger.LogWarning((object)("Meat Rack placement appearance snapshot failed: " + ex.Message)); } } } internal sealed class MeatDefinition { internal readonly string PrefabName; internal readonly string DisplayName; internal readonly MeatStorageClass StorageClass; internal readonly string CalibrationPrefabName; internal MeatDefinition(string prefabName, string displayName, MeatStorageClass storageClass, string calibrationPrefabName) { PrefabName = prefabName; DisplayName = displayName; StorageClass = storageClass; CalibrationPrefabName = calibrationPrefabName; } } internal static class MeatCatalog { private static readonly MeatDefinition[] CalibrationCandidates = new MeatDefinition[31] { Raw("RawMeat", "Boar Meat"), Raw("DeerMeat", "Deer Meat"), Raw("NeckTail", "Neck Tail"), Raw("BjornMeat", "Bear Meat"), Raw("SerpentMeat", "Serpent Meat"), Raw("WolfMeat", "Wolf Meat"), Raw("LoxMeat", "Lox Meat"), Raw("ChickenMeat", "Chicken Meat"), Raw("HareMeat", "Hare Meat"), Raw("BugMeat", "Seeker Meat"), Raw("AsksvinMeat", "Asksvin Tail"), Raw("VoltureMeat", "Volture Meat"), Raw("BoneMawSerpentMeat", "Bonemaw Meat"), Raw("MooseMeat", "Moose Meat"), Raw("SealBlubber", "Seal Blubber"), Raw("FishRaw", "Raw Fish"), Raw("FishAnglerRaw", "Raw Anglerfish"), Raw("Fish1", "Perch"), Raw("Fish2", "Pike"), Raw("Fish3", "Tuna"), Raw("Fish4_cave", "Tetra"), Raw("Fish5", "Trollfish"), Raw("Fish6", "Giant Herring"), Raw("Fish7", "Grouper"), Raw("Fish8", "Coral Cod"), Raw("Fish9", "Anglerfish"), Raw("Fish10", "Northern Salmon"), Raw("Fish11", "Magmafish"), Raw("Fish12", "Pufferfish"), Cooked("FishCooked", "Cooked Fish", "FishCooked"), Cooked("SmokedFish", "Smoked Fish", "SmokedFish") }; private static readonly MeatDefinition[] Candidates = new MeatDefinition[46] { Raw("RawMeat", "Boar Meat"), Raw("DeerMeat", "Deer Meat"), Raw("NeckTail", "Neck Tail"), Raw("BjornMeat", "Bear Meat"), Raw("SerpentMeat", "Serpent Meat"), Raw("WolfMeat", "Wolf Meat"), Raw("LoxMeat", "Lox Meat"), Raw("ChickenMeat", "Chicken Meat"), Raw("HareMeat", "Hare Meat"), Raw("BugMeat", "Seeker Meat"), Raw("AsksvinMeat", "Asksvin Tail"), Raw("VoltureMeat", "Volture Meat"), Raw("BoneMawSerpentMeat", "Bonemaw Meat"), Raw("MooseMeat", "Moose Meat"), Raw("SealBlubber", "Seal Blubber"), Raw("FishRaw", "Raw Fish"), Raw("FishAnglerRaw", "Raw Anglerfish"), Raw("Fish1", "Perch"), Raw("Fish2", "Pike"), Raw("Fish3", "Tuna"), Raw("Fish4_cave", "Tetra"), Raw("Fish5", "Trollfish"), Raw("Fish6", "Giant Herring"), Raw("Fish7", "Grouper"), Raw("Fish8", "Coral Cod"), Raw("Fish9", "Anglerfish"), Raw("Fish10", "Northern Salmon"), Raw("Fish11", "Magmafish"), Raw("Fish12", "Pufferfish"), Cooked("CookedMeat", "Cooked Boar Meat", "RawMeat"), Cooked("CookedDeerMeat", "Cooked Deer Meat", "DeerMeat"), Cooked("NeckTailGrilled", "Grilled Neck Tail", "NeckTail"), Cooked("CookedBjornMeat", "Cooked Bear Meat", "BjornMeat"), Cooked("SerpentMeatCooked", "Cooked Serpent Meat", "SerpentMeat"), Cooked("CookedWolfMeat", "Cooked Wolf Meat", "WolfMeat"), Cooked("CookedLoxMeat", "Cooked Lox Meat", "LoxMeat"), Cooked("CookedChickenMeat", "Cooked Chicken Meat", "ChickenMeat"), Cooked("CookedHareMeat", "Cooked Hare Meat", "HareMeat"), Cooked("CookedBugMeat", "Cooked Seeker Meat", "BugMeat"), Cooked("CookedAsksvinMeat", "Cooked Asksvin Tail", "AsksvinMeat"), Cooked("CookedVoltureMeat", "Cooked Volture Meat", "VoltureMeat"), Cooked("CookedBoneMawSerpentMeat", "Cooked Bonemaw Meat", "BoneMawSerpentMeat"), Cooked("CookedMooseMeat", "Cooked Moose Meat", "MooseMeat"), Cooked("CookedSealBlubber", "Cooked Seal Blubber", "SealBlubber"), Cooked("FishCooked", "Cooked Fish", "FishCooked"), Cooked("SmokedFish", "Smoked Fish", "SmokedFish") }; private static readonly Dictionary<string, MeatDefinition> Found = new Dictionary<string, MeatDefinition>(StringComparer.Ordinal); private static readonly Dictionary<string, MeatDefinition> Configured = new Dictionary<string, MeatDefinition>(StringComparer.Ordinal); internal static int CandidateCount => Candidates.Length + Configured.Count; internal static int FoundCount => Found.Count; internal static int SupportedCount => Found.Count; internal static IEnumerable<MeatDefinition> Definitions => CalibrationCandidates; internal static IEnumerable<MeatDefinition> LegacyCalibrationDefinitions { get { int i = 0; while (i < 15) { yield return CalibrationCandidates[i]; int num = i + 1; i = num; } } } internal static IEnumerable<MeatDefinition> AllDefinitions => Candidates; internal static IEnumerable<MeatDefinition> AvailableDefinitions => Found.Values; internal static bool IsConfigured(string prefabName) { if (!string.IsNullOrEmpty(prefabName)) { return Configured.ContainsKey(prefabName); } return false; } internal static void Initialize(string additionalRaw = "", string additionalCooked = "") { Found.Clear(); Configured.Clear(); MeatDefinition[] candidates = Candidates; for (int i = 0; i < candidates.Length; i++) { TryEnable(candidates[i]); } HashSet<string> hashSet = ParseConfiguredIds(additionalRaw); HashSet<string> hashSet2 = ParseConfiguredIds(additionalCooked); foreach (string item in hashSet) { if (hashSet2.Contains(item)) { Logger.LogWarning((object)("Custom prefab is in both raw and cooked lists and will be ignored: " + item)); } else { AddConfigured(item, MeatStorageClass.Raw); } } foreach (string item2 in hashSet2) { if (!hashSet.Contains(item2)) { AddConfigured(item2, MeatStorageClass.Cooked); } } foreach (MeatDefinition value in Configured.Values) { TryEnable(value); } Logger.LogInfo((object)$"Meat catalogue initialized: {Found.Count}/{CandidateCount} target raw/cooked meat and fish prefabs found and enabled."); } private static void TryEnable(MeatDefinition candidate) { try { GameObject prefab = PrefabManager.Instance.GetPrefab(candidate.PrefabName); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<ItemDrop>())) { Logger.LogWarning((object)("Meat/fish prefab unavailable or not an ItemDrop: " + candidate.PrefabName)); } else { Found[candidate.PrefabName] = candidate; } } catch (Exception ex) { Logger.LogWarning((object)("Skipping meat/fish prefab " + candidate.PrefabName + ": " + ex.Message)); } } private static HashSet<string> ParseConfiguredIds(string csv) { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); if (string.IsNullOrWhiteSpace(csv)) { return hashSet; } string[] array = csv.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = NormalizePrefabName(array[i]); if (!string.IsNullOrEmpty(text)) { hashSet.Add(text); } } return hashSet; } private static void AddConfigured(string prefabName, MeatStorageClass storageClass) { if (FindBuiltIn(prefabName) != null) { Logger.LogWarning((object)("Custom meat list ignores built-in prefab: " + prefabName)); } else { Configured[prefabName] = new MeatDefinition(prefabName, prefabName, storageClass, prefabName); } } private static MeatDefinition FindBuiltIn(string prefabName) { MeatDefinition[] candidates = Candidates; foreach (MeatDefinition meatDefinition in candidates) { if (string.Equals(meatDefinition.PrefabName, prefabName, StringComparison.Ordinal)) { return meatDefinition; } } return null; } internal static bool IsSupported(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName)) { return Found.ContainsKey(prefabName); } return false; } internal static bool IsAnyTargetMeat(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (string.IsNullOrEmpty(prefabName)) { return false; } if (FindBuiltIn(prefabName) == null) { return Configured.ContainsKey(prefabName); } return true; } internal static MeatStorageClass StorageClassOf(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName) && Found.TryGetValue(prefabName, out var value)) { return value.StorageClass; } MeatDefinition[] candidates = Candidates; foreach (MeatDefinition meatDefinition in candidates) { if (string.Equals(meatDefinition.PrefabName, prefabName, StringComparison.Ordinal)) { return meatDefinition.StorageClass; } } if (Configured.TryGetValue(prefabName, out value)) { return value.StorageClass; } return MeatStorageClass.Unassigned; } internal static string CalibrationPrefabName(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName) && Found.TryGetValue(prefabName, out var value)) { return value.CalibrationPrefabName; } MeatDefinition[] candidates = Candidates; foreach (MeatDefinition meatDefinition in candidates) { if (string.Equals(meatDefinition.PrefabName, prefabName, StringComparison.Ordinal)) { return meatDefinition.CalibrationPrefabName; } } if (Configured.TryGetValue(prefabName, out value)) { return value.CalibrationPrefabName; } return prefabName; } internal static bool IsAnySupportedMeatKnown(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return false; } foreach (MeatDefinition value in Found.Values) { GameObject prefab = PrefabManager.Instance.GetPrefab(value.PrefabName); ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null); string text = (((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null) ? val.m_itemData.m_shared.m_name : null); if (!string.IsNullOrEmpty(text) && player.IsMaterialKnown(text)) { return true; } } return false; } internal static string DisplayName(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!string.IsNullOrEmpty(prefabName) && Found.TryGetValue(prefabName, out var value)) { return value.DisplayName; } MeatDefinition[] candidates = Candidates; foreach (MeatDefinition meatDefinition in candidates) { if (string.Equals(meatDefinition.PrefabName, prefabName, StringComparison.Ordinal)) { return meatDefinition.DisplayName; } } if (Configured.TryGetValue(prefabName, out value)) { return value.DisplayName; } return prefabName; } internal static string StorageClassDisplayName(MeatStorageClass storageClass) { return storageClass switch { MeatStorageClass.Raw => "raw meat or fish", MeatStorageClass.Cooked => "cooked meat or fish", _ => "unassigned", }; } internal static GameObject GetPrefab(string prefabName) { prefabName = NormalizePrefabName(prefabName); if (!IsSupported(prefabName)) { return null; } return PrefabManager.Instance.GetPrefab(prefabName); } internal static string PrefabName(ItemData item) { if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return null; } return NormalizePrefabName(((Object)item.m_dropPrefab).name); } internal static string NormalizePrefabName(string value) { if (string.IsNullOrEmpty(value)) { return null; } if (value.EndsWith("(Clone)", StringComparison.Ordinal)) { value = value.Substring(0, value.Length - "(Clone)".Length); } return value.Trim(); } private static MeatDefinition Raw(string prefabName, string displayName) { return new MeatDefinition(prefabName, displayName, MeatStorageClass.Raw, prefabName); } private static MeatDefinition Cooked(string prefabName, string displayName, string calibrationPrefabName) { return new MeatDefinition(prefabName, displayName, MeatStorageClass.Cooked, calibrationPrefabName); } } internal readonly struct MeatRackAppearanceTemplate { internal readonly float RackScale; internal readonly float HeightOffset; internal readonly bool ScaleMeatWithRack; internal readonly MeatRackBehaviour Behaviour; internal readonly LooksFullAtMode LooksFullAt; internal readonly string VisualProfilePayload; internal MeatRackAppearanceTemplate(float rackScale, float heightOffset, bool scaleMeatWithRack, MeatRackBehaviour behaviour, LooksFullAtMode looksFullAt, string visualProfilePayload) { RackScale = rackScale; HeightOffset = heightOffset; ScaleMeatWithRack = scaleMeatWithRack; Behaviour = behaviour; LooksFullAt = looksFullAt; VisualProfilePayload = visualProfilePayload ?? string.Empty; } } public sealed class MeatRackAppearance : MonoBehaviour { private const string ZdoScaleKey = "DSMR.Appearance.Scale"; private const string ZdoHeightOffsetKey = "DSMR.Appearance.HeightOffset"; private const string ZdoScaleMeatKey = "DSMR.Appearance.ScaleMeat"; private const string ZdoBehaviourKey = "DSMR.Storage.Behaviour"; private const string ZdoLooksFullModeKey = "DSMR.Appearance.LooksFullMode"; private const string ZdoVisualProfileKey = "DSMR.Appearance.MeatProfile"; private const string ZdoRackRotationKey = "DSMR.Appearance.RackRotation"; [SerializeField] private Vector3 baseScale = Vector3.one; private ZNetView nview; private float nextCheck; private float startedAt; private bool pendingPlacementSnapshot; private MeatRackAppearanceTemplate pendingTemplate; private float pendingDeadline; private float currentScaleMultiplier = 1f; private float currentHeightOffset; private float currentRackRotation; private bool currentScaleMeatWithRack = true; private MeatRackBehaviour currentBehaviour; private LooksFullAtMode currentLooksFullAt = LooksFullAtMode.OccupiedSlots50Percent; private string currentVisualProfilePayload = string.Empty; private MeatRackVisualProfile currentVisualProfile; private readonly Dictionary<string, int> editorTouchedCalibrationRevision = new Dictionary<string, int>(StringComparer.Ordinal); internal float CurrentScaleMultiplier => currentScaleMultiplier; internal float CurrentHeightOffset => currentHeightOffset; internal float CurrentRackRotation => currentRackRotation; internal bool CurrentScaleMeatWithRack => currentScaleMeatWithRack; internal MeatRackBehaviour CurrentBehaviour => currentBehaviour; internal LooksFullAtMode CurrentLooksFullAt => currentLooksFullAt; internal void FlashSelectionTwice() { if (((Component)this).gameObject.activeInHierarchy) { ((MonoBehaviour)this).StartCoroutine(FlashSelectionMarker()); } } private IEnumerator FlashSelectionMarker() { int i = 0; while (i < 2) { GameObject marker = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)marker).name = "DSMR_EditorSelectionMarker"; marker.transform.SetParent(((Component)this).transform, false); marker.transform.localPosition = new Vector3(0f, 1.4f, 0f); marker.transform.localScale = Vector3.one * 0.18f; Collider component = marker.GetComponent<Collider>(); if (Object.op_Implicit((Object)(object)component)) { Object.Destroy((Object)(object)component); } Renderer component2 = marker.GetComponent<Renderer>(); Material material = null; Shader val = Shader.Find("Unlit/Color"); if (Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)val)) { material = new Material(val); material.color = new Color(1f, 0.65f, 0.12f, 1f); component2.sharedMaterial = material; } yield return (object)new WaitForSecondsRealtime(0.22f); if (Object.op_Implicit((Object)(object)marker)) { Object.Destroy((Object)(object)marker); } if (Object.op_Implicit((Object)(object)material)) { Object.Destroy((Object)(object)material); } yield return (object)new WaitForSecondsRealtime(0.16f); int num = i + 1; i = num; } } internal MeatRackEditorState ReadEditorState() { TryLoadAndApply(); return new MeatRackEditorState { RackScale = currentScaleMultiplier, HeightOffset = currentHeightOffset, RackRotation = currentRackRotation, ScaleMeatWithRack = currentScaleMeatWithRack, Behaviour = currentBehaviour, LooksFullAt = currentLooksFullAt }; } internal bool TryApplyEditorState(MeatRackEditorState state, out string result) { if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!TryClaimEditorOwnership()) { result = "Could not take ownership of this rack for editing."; return false; } if (state.Behaviour < MeatRackBehaviour.Auto || state.Behaviour > MeatRackBehaviour.MixedMeat || state.LooksFullAt < LooksFullAtMode.OccupiedSlots25Percent || state.LooksFullAt > LooksFullAtMode.AlwaysFull || float.IsNaN(state.RackScale) || float.IsNaN(state.HeightOffset) || float.IsNaN(state.RackRotation) || float.IsInfinity(state.RackRotation)) { result = "Invalid appearance value."; return false; } MeatRackStorage component = ((Component)this).GetComponent<MeatRackStorage>(); if (Object.op_Implicit((Object)(object)component)) { component.ForceRefresh(); } if (state.Behaviour == MeatRackBehaviour.SingleMeat && Object.op_Implicit((Object)(object)component) && component.DistinctMeatCount > 1) { result = "Remove extra item types before switching to Single Meat."; return false; } if (Object.op_Implicit((Object)(object)component) && component.HasUnrecognizedStoredItems() && state.Behaviour != currentBehaviour) { result = "Restore the missing prefab ID before changing storage behaviour."; return false; } float num = Mathf.Clamp(state.RackScale, 0.5f, 2f); float num2 = Mathf.Clamp(state.HeightOffset, -2f, 2f); ZDO zDO = nview.GetZDO(); zDO.Set("DSMR.Appearance.Scale", num); zDO.Set("DSMR.Appearance.HeightOffset", num2); zDO.Set("DSMR.Appearance.RackRotation", Mathf.Clamp(state.RackRotation, -180f, 180f)); zDO.Set("DSMR.Appearance.ScaleMeat", state.ScaleMeatWithRack ? 1 : 0); zDO.Set("DSMR.Storage.Behaviour", (int)state.Behaviour); zDO.Set("DSMR.Appearance.LooksFullMode", (int)state.LooksFullAt); ApplyAppearance(num, num2, state.ScaleMeatWithRack, state.Behaviour, state.LooksFullAt, currentVisualProfilePayload, state.RackRotation); result = "Saved this rack's appearance."; return true; } internal bool TryResetEditorState(out string result) { MeatRackAppearanceTemplate meatRackAppearanceTemplate = CurrentTemplate(); MeatRackEditorState state = new MeatRackEditorState { RackScale = meatRackAppearanceTemplate.RackScale, HeightOffset = meatRackAppearanceTemplate.HeightOffset, RackRotation = 0f, ScaleMeatWithRack = meatRackAppearanceTemplate.ScaleMeatWithRack, Behaviour = meatRackAppearanceTemplate.Behaviour, LooksFullAt = meatRackAppearanceTemplate.LooksFullAt }; return TryApplyEditorState(state, out result); } internal bool TryGetLockedMeat(out string prefabName) { prefabName = null; if (currentBehaviour != MeatRackBehaviour.SingleMeat) { return false; } MeatRackStorage component = ((Component)this).GetComponent<MeatRackStorage>(); if (!Object.op_Implicit((Object)(object)component)) { return false; } component.ForceRefresh(); if (component.HasUnrecognizedStoredItems() || component.DistinctMeatCount != 1 || component.MeatCounts.Count != 1) { return false; } string prefabName2 = component.MeatCounts[0].PrefabName; if (!string.Equals(component.AssignedPrefabName, prefabName2, StringComparison.Ordinal) || !MeatCatalog.IsSupported(prefabName2)) { return false; } prefabName = prefabName2; return true; } internal bool TryApplyEditorMeatTuning(string prefabName, int field, float value, out string result) { if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!TryClaimEditorOwnership()) { result = "Could not take ownership of this rack for editing."; return false; } if (!MeatCatalog.IsSupported(prefabName)) { result = "This prefab is not available in the current server catalogue."; return false; } if (field < 0 || field >= MeatTuningEditorFields.Labels.Length || float.IsNaN(value) || float.IsInfinity(value)) { result = "Invalid meat appearance value."; return false; } if (!MeatRackVisualProfile.TryDeserialize(currentVisualProfilePayload, out var profile)) { profile = MeatRackVisualProfile.Capture(DynamicStorageMeatRackPlugin.Current); } MeatVisualTuning tuning = MeatTuningEditorFields.With(GetMeatVisualTuning(prefabName), field, value); profile.SetEditorTuning(prefabName, tuning); string text = profile.Serialize(); nview.GetZDO().Set("DSMR.Appearance.MeatProfile", text); DynamicStorageMeatRackPlugin current = DynamicStorageMeatRackPlugin.Current; editorTouchedCalibrationRevision[prefabName] = (((Object)(object)current != (Object)null) ? current.GetLiveCalibrationRevision(prefabName) : 0); ApplyAppearance(currentScaleMultiplier, currentHeightOffset, currentScaleMeatWithRack, currentBehaviour, currentLooksFullAt, text, currentRackRotation); result = "Saved this meat's appearance on the selected rack."; return true; } internal void Setup(Vector3 sourceBaseScale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) baseScale = sourceBaseScale; } private void Start() { nview = ((Component)this).GetComponent<ZNetView>(); startedAt = Time.time; nextCheck = 0f; } private void Update() { if (Time.unscaledTime < nextCheck) { return; } nextCheck = Time.unscaledTime + 0.25f; TryLoadAndApply(); DynamicStorageMeatRackPlugin current = DynamicStorageMeatRackPlugin.Current; if ((Object)(object)current != (Object)null && current.GlobalMeatVisualOverride) { MeatRackVisual component = ((Component)this).GetComponent<MeatRackVisual>(); if (Object.op_Implicit((Object)(object)component)) { component.Refresh(((Component)this).GetComponent<MeatRackStorage>()); } } } private MeatRackAppearanceTemplate CurrentTemplate() { DynamicStorageMeatRackPlugin current = DynamicStorageMeatRackPlugin.Current; if (!((Object)(object)current != (Object)null)) { return new MeatRackAppearanceTemplate(1f, 0f, scaleMeatWithRack: true, MeatRackBehaviour.Auto, LooksFullAtMode.OccupiedSlots50Percent, string.Empty); } return current.GetAppearanceTemplate(); } private void TryLoadAndApply() { if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null) { return; } if (pendingPlacementSnapshot) { TryCommitPendingPlacementSnapshot(); } MeatRackAppearanceTemplate meatRackAppearanceTemplate = CurrentTemplate(); ZDO zDO = nview.GetZDO(); float num = zDO.GetFloat("DSMR.Appearance.Scale", -1f); float num2 = zDO.GetFloat("DSMR.Appearance.HeightOffset", float.NaN); int num3 = zDO.GetInt("DSMR.Appearance.ScaleMeat", -1); int num4 = zDO.GetInt("DSMR.Storage.Behaviour", -1); int num5 = zDO.GetInt("DSMR.Appearance.LooksFullMode", -1); float rackRotation = zDO.GetFloat("DSMR.Appearance.RackRotation", 0f); string text = zDO.GetString("DSMR.Appearance.MeatProfile", string.Empty); bool flag = HasProfilePayload(text); if ((num <= 0f || float.IsNaN(num2) || num3 < 0 || num4 < 0 || num4 > 2 || num5 < 0 || num5 > 9 || !flag) && nview.IsOwner()) { if (Time.time - startedAt < 1f && !pendingPlacementSnapshot) { return; } if (num <= 0f) { num = meatRackAppearanceTemplate.RackScale; zDO.Set("DSMR.Appearance.Scale", num); } if (float.IsNaN(num2)) { num2 = meatRackAppearanceTemplate.HeightOffset; zDO.Set("DSMR.Appearance.HeightOffset", num2); } if (num3 < 0) { num3 = (meatRackAppearanceTemplate.ScaleMeatWithRack ? 1 : 0); zDO.Set("DSMR.Appearance.ScaleMeat", num3); } if (num4 < 0 || num4 > 2) { num4 = (int)meatRackAppearanceTemplate.Behaviour; zDO.Set("DSMR.Storage.Behaviour", num4); } if (num5 < 0 || num5 > 9) { num5 = (int)meatRackAppearanceTemplate.LooksFullAt; zDO.Set("DSMR.Appearance.LooksFullMode", num5); } if (!flag) { text = meatRackAppearanceTemplate.VisualProfilePayload; zDO.Set("DSMR.Appearance.MeatProfile", text ?? string.Empty); flag = HasProfilePayload(text); } } if (num <= 0f) { num = meatRackAppearanceTemplate.RackScale; } if (float.IsNaN(num2)) { num2 = meatRackAppearanceTemplate.HeightOffset; } if (num3 < 0) { num3 = (meatRackAppearanceTemplate.ScaleMeatWithRack ? 1 : 0); } if (num4 < 0 || num4 > 2) { num4 = (int)meatRackAppearanceTemplate.Behaviour; } if (num5 < 0 || num5 > 9) { num5 = (int)meatRackAppearanceTemplate.LooksFullAt; } if (!flag) { text = meatRackAppearanceTemplate.VisualProfilePayload; } ApplyAppearance(num, num2, num3 != 0, (MeatRackBehaviour)num4, (LooksFullAtMode)num5, text, rackRotation); } internal void SavePlacementDefaults() { pendingTemplate = CurrentTemplate(); pendingPlacementSnapshot = true; pendingDeadline = Time.time + 15f; TryCommitPendingPlacementSnapshot(); } private bool TryCommitPendingPlacementSnapshot() { if (!pendingPlacementSnapshot) { return false; } if (Time.time > pendingDeadline) { Logger.LogWarning((object)(((Object)((Component)this).gameObject).name + ": Meat Rack placement appearance snapshot timed out before ZDO ownership became ready.")); pendingPlacementSnapshot = false; return false; } if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null || !nview.IsOwner()) { return false; } WriteTemplate(nview.GetZDO(), pendingTemplate); pendingPlacementSnapshot = false; Logger.LogInfo((object)(((Object)((Component)this).gameObject).name + ": saved Meat Rack placement template (behaviour=" + pendingTemplate.Behaviour.ToString() + ").")); return true; } internal void ApplyPlacementPreview(float scaleMultiplier, float heightOffset) { //IL_0033: 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) currentScaleMultiplier = Mathf.Clamp(scaleMultiplier, 0.5f, 2f); currentHeightOffset = Mathf.Clamp(heightOffset, -2f, 2f); ((Component)this).transform.localScale = Multiply(baseScale, currentScaleMultiplier); ApplyRackVisualHeight(currentHeightOffset); } internal bool ApplyCurrentTemplateFromConfig(out string result) { if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null) { result = "Placed Meat Rack has no writable ZDO."; return false; } if (!nview.IsOwner()) { result = "Cannot apply: this client is not the ZDO owner."; return false; } MeatRackAppearanceTemplate template = CurrentTemplate(); WriteTemplate(nview.GetZDO(), template); ApplyAppearance(template.RackScale, template.HeightOffset, template.ScaleMeatWithRack, template.Behaviour, template.LooksFullAt, template.VisualProfilePayload, 0f); result = "Applied current Meat Rack template and visual calibration snapshot."; Logger.LogInfo((object)(((Object)((Component)this).gameObject).name + ": " + result)); return true; } internal MeatVisualTuning GetMeatVisualTuning(string prefabName) { DynamicStorageMeatRackPlugin current = DynamicStorageMeatRackPlugin.Current; if ((Object)(object)current != (Object)null && current.GlobalMeatVisualOverrideApplies(prefabName)) { return current.GetMeatVisualTuning(prefabName); } int num = (((Object)(object)current != (Object)null) ? current.GetLiveCalibrationRevision(prefabName) : 0); if ((Object)(object)current != (Object)null && current.AdvancedCalibrationEnabled && num > 0 && (!editorTouchedCalibrationRevision.TryGetValue(prefabName, out var value) || num > value)) { return current.GetMeatVisualTuning(prefabName); } if (currentVisualProfile != null && currentVisualProfile.HasEditorOverride(prefabName)) { return currentVisualProfile.GetMeatTuning(prefabName); } if ((Object)(object)current != (Object)null && current.AdvancedCalibrationEnabled) { return current.GetMeatVisualTuning(prefabName); } if (currentVisualProfile != null && currentVisualProfile.HasMeatTuning(prefabName)) { return currentVisualProfile.GetMeatTuning(prefabName); } if (!((Object)(object)current != (Object)null)) { return new MeatVisualTuning(1f, 1f, 1f, 1f, 0f, 0f, 0f, 0f); } return current.GetMeatVisualTuning(prefabName); } internal Vector3 GetHookAnchorOffset(int hookIndex) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) DynamicStorageMeatRackPlugin current = DynamicStorageMeatRackPlugin.Current; if ((Object)(object)current != (Object)null && current.AdvancedCalibrationEnabled) { return current.GetHookAnchorOffset(hookIndex); } if (currentVisualProfile != null) { return currentVisualProfile.GetHookOffset(hookIndex); } if (!((Object)(object)current != (Object)null)) { return Vector3.zero; } return current.GetHookAnchorOffset(hookIndex); } private static void WriteTemplate(ZDO zdo, MeatRackAppearanceTemplate template) { zdo.Set("DSMR.Appearance.Scale", Mathf.Clamp(template.RackScale, 0.5f, 2f)); zdo.Set("DSMR.Appearance.HeightOffset", Mathf.Clamp(template.HeightOffset, -2f, 2f)); zdo.Set("DSMR.Appearance.RackRotation", 0f); zdo.Set("DSMR.Appearance.ScaleMeat", template.ScaleMeatWithRack ? 1 : 0); zdo.Set("DSMR.Storage.Behaviour", (int)template.Behaviour); zdo.Set("DSMR.Appearance.LooksFullMode", (int)template.LooksFullAt); zdo.Set("DSMR.Appearance.MeatProfile", template.VisualProfilePayload ?? string.Empty); } private void ApplyAppearance(float scaleMultiplier, float heightOffset, bool scaleMeatWithRack, MeatRackBehaviour behaviour, LooksFullAtMode looksFullAt, string visualProfilePayload, float rackRotation) { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) bool flag = !string.Equals(currentVisualProfilePayload, visualProfilePayload ?? string.Empty, StringComparison.Ordinal); bool num = currentBehaviour != behaviour || currentScaleMeatWithRack != scaleMeatWithRack || currentLooksFullAt != looksFullAt || Mathf.Abs(currentScaleMultiplier - scaleMultiplier) > 0.0001f || Mathf.Abs(currentHeightOffset - heightOffset) > 0.0001f || Mathf.Abs(currentRackRotation - rackRotation) > 0.0001f || flag; currentScaleMultiplier = Mathf.Clamp(scaleMultiplier, 0.5f, 2f); currentHeightOffset = Mathf.Clamp(heightOffset, -2f, 2f); currentRackRotation = Mathf.Clamp(rackRotation, -180f, 180f); currentScaleMeatWithRack = scaleMeatWithRack; currentBehaviour = behaviour; currentLooksFullAt = looksFullAt; currentVisualProfilePayload = visualProfilePayload ?? string.Empty; if (flag || currentVisualProfile == null) { currentVisualProfile = (MeatRackVisualProfile.TryDeserialize(currentVisualProfilePayload, out var profile) ? profile : null); } ((Component)this).transform.localScale = Multiply(baseScale, currentScaleMultiplier); ApplyRackVisualHeight(currentHeightOffset); ApplyRackVisualRotation(currentRackRotation); if (!num) { return; } MeatRackStorage component = ((Component)this).GetComponent<MeatRackStorage>(); if (Object.op_Implicit((Object)(object)component)) { component.ForceRefresh(); return; } MeatRackVisual component2 = ((Component)this).GetComponent<MeatRackVisual>(); if (Object.op_Implicit((Object)(object)component2)) { component2.Refresh(null); } } private void ApplyRackVisualHeight(float heightOffset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0046: Unknown result type (might be due to invalid IL or missing references) Vector3 localPosition = Vector3.up * heightOffset; Transform val = FindDescendant(((Component)this).transform, "DSMR_IronRackVisual"); if (Object.op_Implicit((Object)(object)val)) { val.localPosition = localPosition; } Transform val2 = FindDescendant(((Component)this).transform, "DSMR_IronRackCollision"); if (Object.op_Implicit((Object)(object)val2)) { val2.localPosition = localPosition; } } private void ApplyRackVisualRotation(float degrees) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) Quaternion localRotation = Quaternion.Euler(0f, degrees, 0f); Transform val = FindDescendant(((Component)this).transform, "DSMR_IronRackVisual"); if (Object.op_Implicit((Object)(object)val)) { val.localRotation = localRotation; } Transform val2 = FindDescendant(((Component)this).transform, "DSMR_IronRackCollision"); if (Object.op_Implicit((Object)(object)val2)) { val2.localRotation = localRotation; } } private bool TryClaimEditorOwnership() { if (!Object.op_Implicit((Object)(object)nview)) { nview = ((Component)this).GetComponent<ZNetView>(); } if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid() || nview.GetZDO() == null) {