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 Historical Heritage v2.0.3
plugins/Historical_Heritage.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CannonFire; using HarmonyLib; using Historical_Heritage; using ItemManager; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using PieceManager; using ServerSync; using ShipUpgrades; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; using YourModNamespace; [assembly: AssemblyFileVersion("2.0.3")] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyProduct("Historical_Heritage")] [assembly: AssemblyCompany("Dreanegade")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("Historical_Heritage")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.3.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<628ed641-12bb-4f05-bb8a-142422a5fbf6>Embedded] internal sealed class <628ed641-12bb-4f05-bb8a-142422a5fbf6>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [<628ed641-12bb-4f05-bb8a-142422a5fbf6>Embedded] [CompilerGenerated] internal sealed class <1b7e9e30-9233-4cce-ab17-c3347351c0db>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <1b7e9e30-9233-4cce-ab17-c3347351c0db>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <1b7e9e30-9233-4cce-ab17-c3347351c0db>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [<628ed641-12bb-4f05-bb8a-142422a5fbf6>Embedded] [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class <0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContextAttribute : Attribute { public readonly byte Flag; public <0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContextAttribute(byte P_0) { Flag = P_0; } } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] internal sealed class ConfigurationManagerAttributes { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [HarmonyPatch] public static class RandomSpeakShip { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] private static class DevLog { public const bool Enabled = false; public const bool Announcer = false; public const bool Parrot = false; public const bool Upgrades = false; public const bool Startup = false; public const bool Cycle = false; } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] private sealed class WeightedText { public readonly string text; public readonly float weight; public WeightedText(string text, float weight) { this.text = text; this.weight = weight; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] private enum UpgradeBit { Lantern, Cannon, Nest, Bell, Brazier, Hull, Sail, Barrel, Anvil, Cartography, Anchor, Seating, Quarters } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] private struct UpgradeDef { public UpgradeBit bit; public string zdoBoolKey; public List<WeightedText> lines; public string announcerInstalledLineKey; } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [HarmonyPatch] private static class Patch_UpgradeInstall { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ShipUpgrades.ShipUpgradeTable"); if (type == null) { return null; } return AccessTools.Method(type, "RPC_RequestInstallUpgrade", new Type[3] { typeof(long), typeof(string), typeof(string) }, (Type[])null); } private static void Prefix(object __instance, long sender, string zdoKey, string itemPrefabName, ref bool __state) { __state = false; try { MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } ZNetView componentInParent = ((Component)val).GetComponentInParent<ZNetView>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsValid() && string.Equals(Utils.GetPrefabName(((Component)componentInParent).gameObject), "ShipGalleonDO", StringComparison.Ordinal) && componentInParent.IsOwner()) { ZDO zDO = componentInParent.GetZDO(); if (zDO != null && !string.IsNullOrEmpty(zdoKey)) { __state = zDO.GetBool(zdoKey, false); DLogU($"Install prefix zdoKey={zdoKey} wasInstalled={__state}"); } } } catch (Exception arg) { Debug.LogError((object)string.Format("{0} UpgradeInstall prefix exception: {1}", "[RandomSpeakShip]", arg)); } } private static void Postfix(object __instance, long sender, string zdoKey, string itemPrefabName, bool __state) { try { MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } ZNetView componentInParent = ((Component)val).GetComponentInParent<ZNetView>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid() || !string.Equals(Utils.GetPrefabName(((Component)componentInParent).gameObject), "ShipGalleonDO", StringComparison.Ordinal) || !componentInParent.IsOwner()) { return; } ZDO zDO = componentInParent.GetZDO(); if (zDO == null || string.IsNullOrEmpty(zdoKey)) { return; } bool @bool = zDO.GetBool(zdoKey, false); if (!__state && @bool) { string text = ResolveUpgradeAnnouncerKey(zdoKey); if (!string.IsNullOrEmpty(text)) { DLogU("Install detected zdoKey=" + zdoKey + " -> announce=" + text); AnnounceToEverybody(componentInParent, text); } } } catch (Exception arg) { Debug.LogError((object)string.Format("{0} UpgradeInstall postfix exception: {1}", "[RandomSpeakShip]", arg)); } } } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [HarmonyPatch] private static class Patch_SailColor { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] private struct State { public bool wasOwner; public bool sailInstalled; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(1)] public string prevColor; } private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ShipUpgrades.ShipUpgradeTable"); if (type == null) { return null; } return AccessTools.Method(type, "RPC_SetSailColor", new Type[2] { typeof(long), typeof(string) }, (Type[])null); } private static void Prefix(object __instance, long sender, string colorId, ref State __state) { __state = new State { wasOwner = false, sailInstalled = false, prevColor = "" }; try { MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } ZNetView componentInParent = ((Component)val).GetComponentInParent<ZNetView>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsValid() && string.Equals(Utils.GetPrefabName(((Component)componentInParent).gameObject), "ShipGalleonDO", StringComparison.Ordinal) && componentInParent.IsOwner()) { ZDO zDO = componentInParent.GetZDO(); if (zDO != null) { __state.wasOwner = true; __state.sailInstalled = zDO.GetBool("upgrade_sail", false); __state.prevColor = zDO.GetString("upgrade_sail_color", ""); DLogU($"SailColor prefix owner={__state.wasOwner} sailInstalled={__state.sailInstalled} prevColor={__state.prevColor}"); } } } catch (Exception arg) { Debug.LogError((object)string.Format("{0} SailColor prefix exception: {1}", "[RandomSpeakShip]", arg)); } } private static void Postfix(object __instance, long sender, string colorId, State __state) { try { if (!__state.wasOwner || !__state.sailInstalled) { return; } MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } ZNetView componentInParent = ((Component)val).GetComponentInParent<ZNetView>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid() || !string.Equals(Utils.GetPrefabName(((Component)componentInParent).gameObject), "ShipGalleonDO", StringComparison.Ordinal)) { return; } ZDO zDO = componentInParent.GetZDO(); if (zDO == null) { return; } string @string = zDO.GetString("upgrade_sail_color", ""); string a = NormalizeColorId(__state.prevColor); string b = NormalizeColorId(@string); if (!string.Equals(a, b, StringComparison.OrdinalIgnoreCase)) { string text = ResolveSailColorAnnouncerKey(@string); if (!string.IsNullOrEmpty(text)) { DLogU("SailColor changed prev=" + __state.prevColor + " now=" + @string + " -> announce=" + text); AnnounceToEverybody(componentInParent, text); } } } catch (Exception arg) { Debug.LogError((object)string.Format("{0} SailColor postfix exception: {1}", "[RandomSpeakShip]", arg)); } } } private const string LogPrefix = "[RandomSpeakShip]"; private const string ShipParentPrefabName = "ShipGalleonDO"; private const string ParrotPath = "Interactive/UpgradeTable/Parrot"; private const string AnnouncerPath = "Interactive/UpgradeTable/Announcer"; private const string RpcAnnounce = "RPC_Announce_DO"; private const string ZdoParrotInitializedKey = "parrot_initialized"; private const string ZdoParrotCycleKey = "parrot_cycle"; private const string ZdoParrotCycleIndexKey = "parrot_cycle_index"; private const string ZdoParrotUpgradeMaskKey = "parrot_upgrade_mask"; private static readonly Dictionary<ZDOID, int> _lastSeenMaskByShip = new Dictionary<ZDOID, int>(); private const string UpgradeLantern = "upgrade_lantern"; private const string UpgradeCannon = "upgrade_cannon"; private const string UpgradeNest = "upgrade_nest"; private const string UpgradeBell = "upgrade_bell"; private const string UpgradeBrazier = "upgrade_brazier"; private const string UpgradeHull = "upgrade_hull"; private const string UpgradeSail = "upgrade_sail"; private const string UpgradeBarrel = "upgrade_barrel"; private const string UpgradeAnvil = "upgrade_anvil"; private const string UpgradeCartography = "upgrade_cartography"; private const string UpgradeAnchor = "upgrade_anchor"; private const string UpgradeSeating = "upgrade_seating"; private const string UpgradeQuarters = "upgrade_quarters"; private const string UpgradeSailColorKey = "upgrade_sail_color"; private static bool _parrotEnabled = true; private static bool _announcerEnabled = true; private static readonly WeightedText[] GeneralTexts = new WeightedText[6] { new WeightedText("$parrot_general_text_1_DO", 1f), new WeightedText("$parrot_general_text_2_DO", 1f), new WeightedText("$parrot_general_text_3_DO", 1f), new WeightedText("$parrot_general_text_4_DO", 1f), new WeightedText("$parrot_general_text_5_DO", 1f), new WeightedText("$parrot_general_text_6_DO", 1f) }; private static readonly UpgradeDef[] UpgradeDefs = new UpgradeDef[13] { new UpgradeDef { bit = UpgradeBit.Lantern, zdoBoolKey = "upgrade_lantern", announcerInstalledLineKey = "$parrot_upgrade_lantern_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_lantern_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Cannon, zdoBoolKey = "upgrade_cannon", announcerInstalledLineKey = "$parrot_upgrade_cannon_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_cannon_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Nest, zdoBoolKey = "upgrade_nest", announcerInstalledLineKey = "$parrot_upgrade_nest_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_nest_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Bell, zdoBoolKey = "upgrade_bell", announcerInstalledLineKey = "$parrot_upgrade_bell_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_bell_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Brazier, zdoBoolKey = "upgrade_brazier", announcerInstalledLineKey = "$parrot_upgrade_brazier_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_brazier_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Hull, zdoBoolKey = "upgrade_hull", announcerInstalledLineKey = "$parrot_upgrade_hull_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_hull_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Sail, zdoBoolKey = "upgrade_sail", announcerInstalledLineKey = "$parrot_upgrade_sail_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_sail_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Barrel, zdoBoolKey = "upgrade_barrel", announcerInstalledLineKey = "$parrot_upgrade_barrel_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_barrel_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Anvil, zdoBoolKey = "upgrade_anvil", announcerInstalledLineKey = "$parrot_upgrade_anvil_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_anvil_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Cartography, zdoBoolKey = "upgrade_cartography", announcerInstalledLineKey = "$parrot_upgrade_cartography_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_cartography_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Anchor, zdoBoolKey = "upgrade_anchor", announcerInstalledLineKey = "$parrot_upgrade_anchor_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_anchor_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Seating, zdoBoolKey = "upgrade_seating", announcerInstalledLineKey = "$parrot_upgrade_seating_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_seating_installed_text_DO", 1f) } }, new UpgradeDef { bit = UpgradeBit.Quarters, zdoBoolKey = "upgrade_quarters", announcerInstalledLineKey = "$parrot_upgrade_quarters_installed_text_DO", lines = new List<WeightedText> { new WeightedText("$parrot_upgrade_quarters_installed_text_DO", 1f) } } }; private static readonly Dictionary<string, string> SailColorAnnouncerLine = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "white", "$parrot_sail_color_white_text_DO" }, { "purple", "$parrot_sail_color_purple_text_DO" }, { "blue", "$parrot_sail_color_blue_text_DO" }, { "orange", "$parrot_sail_color_orange_text_DO" }, { "red", "$parrot_sail_color_red_text_DO" }, { "black", "$parrot_sail_color_black_text_DO" } }; private static void DLog(string msg) { } private static void DLogW(string msg) { } private static void DLogA(string msg) { } private static void DLogP(string msg) { } private static void DLogU(string msg) { } private static void DLogS(string msg) { } private static void DLogC(string msg) { } public static void SetParrotEnabled(bool enabled) { _parrotEnabled = enabled; DLog($"ParrotEnabled -> {enabled}"); ApplyParrotEnabledToAllShipsInScene(); ApplyParrotEnabledToShipPrefab(); } public static void SetAnnouncerEnabled(bool enabled) { _announcerEnabled = enabled; DLog($"AnnouncerEnabled -> {enabled}"); } private static bool PFail(RandomSpeak rs, string reason, ZNetView shipZnv = null, ZDO shipZdo = null) { return false; } [HarmonyPostfix] [HarmonyPatch(typeof(ZNetScene), "Awake")] private static void ZNetScene_Awake_Postfix() { ApplyParrotEnabledToShipPrefab(); } [HarmonyPatch(typeof(Ship), "Awake")] [HarmonyPostfix] private static void Ship_Awake_Postfix(Ship __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { string prefabName = Utils.GetPrefabName(((Component)component).gameObject); if (string.Equals(prefabName, "ShipGalleonDO", StringComparison.Ordinal)) { EnsureAnnounceRpcRegistered(component); DLogS(string.Format("Ship.Awake registered RPC on {0} owner={1} id={2}", prefabName, component.IsOwner(), (component.GetZDO() != null) ? ((object)(ZDOID)(ref component.GetZDO().m_uid)).ToString() : "<nozdo>")); } } } catch (Exception arg) { Debug.LogError((object)string.Format("{0} Ship.Awake postfix exception: {1}", "[RandomSpeakShip]", arg)); } } [HarmonyPatch(typeof(RandomSpeak), "Speak")] [HarmonyPrefix] private static bool RandomSpeak_Speak_Prefix(RandomSpeak __instance) { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null) { return true; } if (!((MonoBehaviour)__instance).IsInvoking()) { ((MonoBehaviour)__instance).InvokeRepeating("Speak", Random.Range(0f, __instance.m_interval), __instance.m_interval); DLogS($"InvokeRepeating ensured on '{((Object)__instance).name}' interval={__instance.m_interval:0.00}"); } ZNetView componentInParent = ((Component)__instance).GetComponentInParent<ZNetView>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid()) { return true; } if (!string.Equals(Utils.GetPrefabName(((Component)componentInParent).gameObject), "ShipGalleonDO", StringComparison.Ordinal)) { return true; } string relativePath = GetRelativePath(((Component)componentInParent).transform, ((Component)__instance).transform); if (string.Equals(relativePath, "Interactive/UpgradeTable/Announcer", StringComparison.Ordinal)) { return false; } if (!string.Equals(relativePath, "Interactive/UpgradeTable/Parrot", StringComparison.Ordinal)) { return true; } if (!_parrotEnabled) { return true; } if (Random.value > __instance.m_chance) { return PFail(__instance, "roll>chance", componentInParent, componentInParent.GetZDO()); } if ((Object)(object)Player.m_localPlayer == (Object)null) { return PFail(__instance, "no local player", componentInParent, componentInParent.GetZDO()); } if (Vector3.Distance(((Component)__instance).transform.position, ((Component)Player.m_localPlayer).transform.position) > __instance.m_triggerDistance) { return PFail(__instance, "too far", componentInParent, componentInParent.GetZDO()); } if (__instance.m_onlyOnItemStand && !Object.op_Implicit((Object)(object)((Component)__instance).gameObject.GetComponentInParent<ItemStand>())) { return PFail(__instance, "onlyOnItemStand but no ItemStand", componentInParent, componentInParent.GetZDO()); } float dayFraction = EnvMan.instance.GetDayFraction(); if (!IsTimeAllowed(__instance, dayFraction)) { return PFail(__instance, $"tod blocked dayFraction={dayFraction:0.000}", componentInParent, componentInParent.GetZDO()); } ZDO zDO = componentInParent.GetZDO(); if (zDO == null) { return PFail(__instance, "ship zdo null", componentInParent); } string text = ""; bool num = componentInParent.IsOwner(); bool flag = false; if (num) { flag = UpdateParrotStateAndCycle(zDO); text = GetNextFromCycle(zDO); if (string.IsNullOrEmpty(text)) { return PFail(__instance, "chosenText empty (owner)", componentInParent, zDO); } DLogC($"Owner choose -> {text} changed={flag}"); } else { text = ChooseReadOnlyLineWithLocalCycle(zDO); if (string.IsNullOrEmpty(text)) { return PFail(__instance, "chosenText empty (readonly)", componentInParent, zDO); } DLogC("Client choose -> " + text); } DLogP("Speak -> " + text); __instance.m_speakEffects.Create(((Component)__instance).transform.position, ((Component)__instance).transform.rotation, (Transform)null, 1f, -1); Chat.instance.SetNpcText(((Component)__instance).gameObject, __instance.m_offset, __instance.m_cullDistance, __instance.m_ttl, __instance.m_topic, text, __instance.m_useLargeDialog); return false; } catch (Exception arg) { Debug.LogError((object)string.Format("{0} Speak prefix exception: {1}", "[RandomSpeakShip]", arg)); return true; } } public static void TryAnnounceNow(ZNetView shipZnv, string localizationKey) { if (!((Object)(object)shipZnv == (Object)null) && shipZnv.IsValid() && !string.IsNullOrEmpty(localizationKey) && string.Equals(Utils.GetPrefabName(((Component)shipZnv).gameObject), "ShipGalleonDO", StringComparison.Ordinal)) { AnnounceToEverybody(shipZnv, localizationKey); } } private static void AnnounceToEverybody(ZNetView shipZnv, string localizationKey) { if (_announcerEnabled && !((Object)(object)shipZnv == (Object)null) && shipZnv.IsValid()) { EnsureAnnounceRpcRegistered(shipZnv); shipZnv.InvokeRPC(ZNetView.Everybody, "RPC_Announce_DO", new object[1] { localizationKey }); DLogA("Broadcast announce " + localizationKey); } } private static void EnsureAnnounceRpcRegistered(ZNetView shipZnv) { if ((Object)(object)shipZnv == (Object)null || !shipZnv.IsValid()) { return; } try { shipZnv.Register<string>("RPC_Announce_DO", (Action<long, string>)RPC_Announce); } catch { } } private static void RPC_Announce(long sender, string localizationKey) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) try { if (!_announcerEnabled || string.IsNullOrEmpty(localizationKey)) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { ZNetView val = FindClosestShipZNetView(((Component)localPlayer).transform.position, 25f); if (!((Object)(object)val == (Object)null)) { ShowAnnounceLocally(val, localizationKey); } } } catch (Exception arg) { Debug.LogError((object)string.Format("{0} RPC_Announce exception: {1}", "[RandomSpeakShip]", arg)); } } private static ZNetView FindClosestShipZNetView(Vector3 pos, float maxDist) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) ZNetView result = null; float num = maxDist * maxDist; try { ZNetView[] array = Object.FindObjectsOfType<ZNetView>(); if (array == null) { return null; } ZNetView[] array2 = array; foreach (ZNetView val in array2) { if (!((Object)(object)val == (Object)null) && val.IsValid() && string.Equals(Utils.GetPrefabName(((Component)val).gameObject), "ShipGalleonDO", StringComparison.Ordinal)) { Vector3 val2 = ((Component)val).transform.position - pos; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val; } } } return result; } catch { return result; } } private static void ShowAnnounceLocally(ZNetView shipZnv, string localizationKey) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)shipZnv == (Object)null || !shipZnv.IsValid()) { return; } Transform val = ((Component)shipZnv).transform.Find("Interactive/UpgradeTable/Announcer"); if ((Object)(object)val == (Object)null) { DLogW("Announcer path not found on ship: Interactive/UpgradeTable/Announcer"); return; } RandomSpeak component = ((Component)val).GetComponent<RandomSpeak>(); if ((Object)(object)component == (Object)null) { DLogW("Announcer has no RandomSpeak component, using fallback params"); } Vector3 position = val.position; Quaternion rotation = val.rotation; if ((Object)(object)component != (Object)null) { component.m_speakEffects.Create(position, rotation, (Transform)null, 1f, -1); } Vector3 val2 = (((Object)(object)component != (Object)null) ? component.m_offset : Vector3.zero); float num = (((Object)(object)component != (Object)null) ? component.m_cullDistance : 15f); float num2 = (((Object)(object)component != (Object)null) ? component.m_ttl : 6f); string text = (((Object)(object)component != (Object)null) ? component.m_topic : ""); bool flag = (Object)(object)component != (Object)null && component.m_useLargeDialog; Chat.instance.SetNpcText(((Component)val).gameObject, val2, num, num2, text, localizationKey, flag); DLogA("Local announce " + localizationKey); } private static bool UpdateParrotStateAndCycle(ZDO shipZdo) { int num = ComputeUpgradeMask(shipZdo); if (!shipZdo.GetBool("parrot_initialized", false)) { shipZdo.Set("parrot_initialized", true); shipZdo.Set("parrot_upgrade_mask", num); string text = BuildNewCycle(shipZdo); shipZdo.Set("parrot_cycle", text); shipZdo.Set("parrot_cycle_index", 0); DLogP($"Initialized parrot state maskNow={num} cycle='{text}'"); return true; } int @int = shipZdo.GetInt("parrot_upgrade_mask", 0); if (@int == num) { return false; } shipZdo.Set("parrot_upgrade_mask", num); string text2 = BuildNewCycle(shipZdo); shipZdo.Set("parrot_cycle", text2); shipZdo.Set("parrot_cycle_index", 0); DLogP($"Upgrades changed prevMask={@int} maskNow={num} newCycle='{text2}'"); return true; } private static string GetNextFromCycle(ZDO shipZdo) { string text = shipZdo.GetString("parrot_cycle", ""); int num = shipZdo.GetInt("parrot_cycle_index", 0); if (string.IsNullOrEmpty(text)) { text = BuildNewCycle(shipZdo); shipZdo.Set("parrot_cycle", text); num = 0; shipZdo.Set("parrot_cycle_index", 0); DLogC("Cycle was empty -> rebuilt"); } string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return ""; } if (num >= array.Length) { text = BuildNewCycle(shipZdo); shipZdo.Set("parrot_cycle", text); num = 0; shipZdo.Set("parrot_cycle_index", 0); array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return ""; } DLogC("Cycle ended -> rebuilt"); } if (!int.TryParse(array[num].Trim(), out var result)) { return ""; } shipZdo.Set("parrot_cycle_index", num + 1); List<WeightedText> localTexts = BuildLocalTexts(shipZdo); return ResolveTextByIndex(result, localTexts); } private static string ChooseReadOnlyLineWithLocalCycle(ZDO shipZdo) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (shipZdo == null) { return ""; } int num = ComputeUpgradeMask(shipZdo); ZDOID uid = shipZdo.m_uid; bool flag = true; if (_lastSeenMaskByShip.TryGetValue(uid, out var value)) { flag = value != num; } _lastSeenMaskByShip[uid] = num; List<WeightedText> list = BuildLocalTexts(shipZdo); if (flag) { DLogC(string.Format("Client pool changed id={0} lastMask={1} nowMask={2} localLines={3}", uid, _lastSeenMaskByShip.ContainsKey(uid) ? value.ToString() : "<none>", num, list.Count)); } if (flag && list != null && list.Count > 0) { return PickWeighted(list); } List<WeightedText> list2 = new List<WeightedText>(); if (list != null && list.Count > 0) { list2.AddRange(list); } for (int i = 0; i < GeneralTexts.Length; i++) { list2.Add(GeneralTexts[i]); } return PickWeighted(list2); } private static string BuildNewCycle(ZDO shipZdo) { List<WeightedText> list = BuildLocalTexts(shipZdo); List<int> list2 = new List<int>(); List<float> list3 = new List<float>(); for (int i = 0; i < list.Count; i++) { list2.Add(i); list3.Add(Mathf.Max(0.0001f, list[i].weight)); } for (int j = 0; j < GeneralTexts.Length; j++) { list2.Add(100 + j); list3.Add(Mathf.Max(0.0001f, GeneralTexts[j].weight)); } if (list2.Count == 0) { return ""; } List<int> list4 = new List<int>(); while (list2.Count > 0) { float num = 0f; for (int k = 0; k < list3.Count; k++) { num += list3[k]; } float num2 = Random.Range(0f, num); float num3 = 0f; for (int l = 0; l < list2.Count; l++) { num3 += list3[l]; if (num2 <= num3) { list4.Add(list2[l]); list2.RemoveAt(l); list3.RemoveAt(l); break; } } } StringBuilder stringBuilder = new StringBuilder(); for (int m = 0; m < list4.Count; m++) { if (m > 0) { stringBuilder.Append(","); } stringBuilder.Append(list4[m]); } return stringBuilder.ToString(); } private static string ResolveTextByIndex(int index, List<WeightedText> localTexts) { if (index >= 100) { int num = index - 100; if (num >= 0 && num < GeneralTexts.Length) { return GeneralTexts[num].text; } return ""; } if (index >= 0 && index < localTexts.Count) { return localTexts[index].text; } return ""; } private static List<WeightedText> BuildLocalTexts(ZDO shipZdo) { List<WeightedText> list = new List<WeightedText>(); UpgradeDef[] upgradeDefs = UpgradeDefs; for (int i = 0; i < upgradeDefs.Length; i++) { UpgradeDef upgradeDef = upgradeDefs[i]; if (shipZdo.GetBool(upgradeDef.zdoBoolKey, false) && upgradeDef.lines != null) { for (int j = 0; j < upgradeDef.lines.Count; j++) { list.Add(upgradeDef.lines[j]); } } } return list; } private static int ComputeUpgradeMask(ZDO shipZdo) { int num = 0; UpgradeDef[] upgradeDefs = UpgradeDefs; for (int i = 0; i < upgradeDefs.Length; i++) { UpgradeDef upgradeDef = upgradeDefs[i]; if (shipZdo.GetBool(upgradeDef.zdoBoolKey, false)) { num |= 1 << (int)upgradeDef.bit; } } return num; } private static string PickWeighted(List<WeightedText> pool) { if (pool == null || pool.Count == 0) { return ""; } float num = 0f; for (int i = 0; i < pool.Count; i++) { num += Mathf.Max(0.0001f, pool[i].weight); } float num2 = Random.Range(0f, num); float num3 = 0f; for (int j = 0; j < pool.Count; j++) { num3 += Mathf.Max(0.0001f, pool[j].weight); if (num2 <= num3) { return pool[j].text; } } return pool[pool.Count - 1].text; } private static void ApplyParrotEnabledToShipPrefab() { try { if ((Object)(object)ZNetScene.instance == (Object)null) { return; } GameObject prefab = ZNetScene.instance.GetPrefab("ShipGalleonDO"); if ((Object)(object)prefab == (Object)null) { DLogW("Ship prefab not found: ShipGalleonDO"); return; } Transform val = prefab.transform.Find("Interactive/UpgradeTable/Parrot"); if ((Object)(object)val == (Object)null) { DLogW("Parrot path not found on prefab: Interactive/UpgradeTable/Parrot"); return; } ((Component)val).gameObject.SetActive(_parrotEnabled); DLog($"Prefab parrot active -> {_parrotEnabled}"); } catch (Exception arg) { Debug.LogError((object)string.Format("{0} ApplyParrotEnabledToShipPrefab exception: {1}", "[RandomSpeakShip]", arg)); } } private static void ApplyParrotEnabledToAllShipsInScene() { try { ZNetView[] array = Object.FindObjectsOfType<ZNetView>(); int num = 0; ZNetView[] array2 = array; foreach (ZNetView val in array2) { if (!((Object)(object)val == (Object)null) && val.IsValid() && string.Equals(Utils.GetPrefabName(((Component)val).gameObject), "ShipGalleonDO", StringComparison.Ordinal)) { Transform val2 = ((Component)val).transform.Find("Interactive/UpgradeTable/Parrot"); if (!((Object)(object)val2 == (Object)null)) { ((Component)val2).gameObject.SetActive(_parrotEnabled); num++; } } } DLog($"Runtime parrot toggle applied to ships: {num}, enabled={_parrotEnabled}"); } catch (Exception arg) { Debug.LogError((object)string.Format("{0} ApplyParrotEnabledToAllShipsInScene exception: {1}", "[RandomSpeakShip]", arg)); } } private static string ResolveUpgradeAnnouncerKey(string zdoKey) { if (string.IsNullOrEmpty(zdoKey)) { return ""; } for (int i = 0; i < UpgradeDefs.Length; i++) { if (string.Equals(UpgradeDefs[i].zdoBoolKey, zdoKey, StringComparison.Ordinal)) { return UpgradeDefs[i].announcerInstalledLineKey; } } return ""; } private static string ResolveSailColorAnnouncerKey(string colorRaw) { if (string.IsNullOrEmpty(colorRaw)) { return ""; } string text = NormalizeColorId(colorRaw); if (string.IsNullOrEmpty(text)) { return ""; } if (SailColorAnnouncerLine.TryGetValue(text, out var value)) { return value; } string text2 = colorRaw.Trim().ToLowerInvariant(); if (text2.Contains("white")) { return "$parrot_sail_color_white_text_DO"; } if (text2.Contains("purple") || text2.Contains("violet")) { return "$parrot_sail_color_purple_text_DO"; } if (text2.Contains("blue")) { return "$parrot_sail_color_blue_text_DO"; } if (text2.Contains("orange") || text2.Contains("gold")) { return "$parrot_sail_color_orange_text_DO"; } if (text2.Contains("red") || text2.Contains("crimson")) { return "$parrot_sail_color_red_text_DO"; } if (text2.Contains("black")) { return "$parrot_sail_color_black_text_DO"; } return ""; } private static string NormalizeColorId(string colorRaw) { if (string.IsNullOrEmpty(colorRaw)) { return ""; } string text = colorRaw.Trim(); int num = text.IndexOfAny(new char[5] { ' ', '/', '\\', ',', '.' }); if (num > 0) { text = text.Substring(0, num); } return text.Trim().ToLowerInvariant(); } private static string GetRelativePath(Transform root, Transform t) { if ((Object)(object)root == (Object)null || (Object)(object)t == (Object)null) { return ""; } List<string> list = new List<string>(); Transform val = t; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static bool IsTimeAllowed(RandomSpeak rs, float dayFraction) { if (!rs.m_invertTod) { if (!(dayFraction < rs.m_minTOD)) { return !(dayFraction > rs.m_maxTOD); } return false; } if (!(dayFraction > rs.m_minTOD)) { return !(dayFraction < rs.m_maxTOD); } return false; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] public static class ExtraStats { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] private static class DevLog { public const bool Enabled = false; public const bool AttackSpeed = false; public const bool WetImmune = false; public const bool Tooltips = false; public const bool FoodStats = false; } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public enum ExtraStatType { Health, Stamina, Eitr, AttackSpeed, WetImmune } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public enum ExtraSourceType { ItemDrop, StatusEffect } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] public class ExtraStatEntry { public string PrefabName; public ExtraStatType StatType; public float Value; public float? DisplayValue; public ExtraSourceType SourceType; public ExtraStatEntry(string prefab, ExtraStatType stat, float value, ExtraSourceType source) { PrefabName = prefab; StatType = stat; Value = value; DisplayValue = null; SourceType = source; } public ExtraStatEntry(string prefab, ExtraStatType stat, float value, float? displayValue, ExtraSourceType source) { PrefabName = prefab; StatType = stat; Value = value; DisplayValue = displayValue; SourceType = source; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] public static class Player_GetTotalFoodValue_ExtraStatsPatch { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { if ((Object)(object)__instance == (Object)null) { return; } float num = 0f; float num2 = 0f; float num3 = 0f; try { Inventory inventory = ((Humanoid)__instance).GetInventory(); if (inventory != null) { foreach (ItemData equippedItem in inventory.GetEquippedItems()) { if (equippedItem != null && !((Object)(object)equippedItem.m_dropPrefab == (Object)null)) { string name = ((Object)equippedItem.m_dropPrefab).name; GetItemDropBonusesForPrefab(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var _); if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f) { num += extraHp; num2 += extraStamina; num3 += extraEitr; DLogFood($"ItemDrop matched for food stats: {name} → +HP {extraHp}, +Stamina {extraStamina}, +Eitr {extraEitr}"); } } } } if (((Character)__instance).m_seman != null && ((Character)__instance).m_seman.m_statusEffects != null) { foreach (StatusEffect statusEffect in ((Character)__instance).m_seman.m_statusEffects) { if (!((Object)(object)statusEffect == (Object)null)) { string name2 = ((Object)statusEffect).name; GetStatusEffectBonuses(name2, out var extraHp2, out var extraStamina2, out var extraEitr2, out var _, out var _); if (extraHp2 != 0f || extraStamina2 != 0f || extraEitr2 != 0f) { num += extraHp2; num2 += extraStamina2; num3 += extraEitr2; string prefabName = Utils.GetPrefabName(name2); DLogFood($"StatusEffect matched for food stats: {name2} (clean={prefabName}) → +HP {extraHp2}, +Stamina {extraStamina2}, +Eitr {extraEitr2}"); } } } } } catch (Exception ex) { LogError("Exception in ExtraStats Player.GetTotalFoodValue Postfix: " + ex); } if (num != 0f || num2 != 0f || num3 != 0f) { DLogFood($"Total food bonuses applied to player: +HP {num}, +Stamina {num2}, +Eitr {num3}"); hp += num; stamina += num2; eitr += num3; } } } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [HarmonyPatch] public static class ItemData_StaticGetTooltip_ExtraStatsPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[5] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int) }, (Type[])null); } private static void Postfix(ItemData item, int qualityLevel, bool crafting, float worldLevel, int stackOverride, ref string __result) { try { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return; } string name = ((Object)item.m_dropPrefab).name; DLogTooltip($"Static GetTooltip Postfix called for {name}, q={qualityLevel}, crafting={crafting}, worldLevel={worldLevel}, stackOverride={stackOverride}"); GetItemDropBonusesForPrefab(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var displayAttackSpeedPercent, out var wetImmune); if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f || displayAttackSpeedPercent != 0f || wetImmune) { string text = BuildExtraStatsTooltipBlock(extraHp, extraStamina, extraEitr, displayAttackSpeedPercent, wetImmune); if (!string.IsNullOrEmpty(text)) { DLogTooltip($"Appending extras for {name}: HP {extraHp}, Stamina {extraStamina}, Eitr {extraEitr}, AttackSpeed(Display)% {displayAttackSpeedPercent}, WetImmune {wetImmune}"); __result += text; } } } catch (Exception ex) { LogError("Exception in ItemData_StaticGetTooltip_ExtraStatsPatch: " + ex); } } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(SE_Stats), "GetTooltipString")] public static class SE_Stats_GetTooltipString_ExtraStatsPatch { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static void Postfix(SE_Stats __instance, ref string __result) { try { if ((Object)(object)__instance == (Object)null) { return; } string name = ((Object)__instance).name; string prefabName = Utils.GetPrefabName(name); DLogTooltip("SE GetTooltipString for " + name + " (clean=" + prefabName + ")"); GetStatusEffectBonuses(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var displayAttackSpeedPercent, out var wetImmune); if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f || displayAttackSpeedPercent != 0f || wetImmune) { string text = BuildExtraStatsTooltipBlock(extraHp, extraStamina, extraEitr, displayAttackSpeedPercent, wetImmune); if (!string.IsNullOrEmpty(text)) { DLogTooltip($"Appending SE extras for {name} (clean={prefabName}): HP {extraHp}, Stamina {extraStamina}, Eitr {extraEitr}, AttackSpeed(Display)% {displayAttackSpeedPercent}, WetImmune {wetImmune}"); __result += text; } } } catch (Exception ex) { LogError("Exception in SE_Stats_GetTooltipString_ExtraStatsPatch: " + ex); } } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] private sealed class HumanoidState { public float DesiredSpeed = 1f; public float LastAppliedSpeed = 1f; public bool HasDesiredSpeed; public bool WasInAttack; public int ActiveAttackDepth; public float ActiveAttackMul = 1f; } [HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[] { typeof(Character), typeof(bool) })] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public static class Humanoid_StartAttack_AttackSpeedPatch { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [HarmonyPostfix] private static void Postfix(Humanoid __instance, Character target, bool secondaryAttack, ref bool __result) { EnsureAttackInit(); if (!__result) { return; } HumanoidState attackState = GetAttackState(__instance); float num = ComputeTotalAttackSpeedPercentForHumanoid(__instance); if (num == 0f) { attackState.DesiredSpeed = 1f; attackState.HasDesiredSpeed = false; ApplyAnimSpeed(__instance, attackState, 1f); attackState.ActiveAttackDepth = 0; attackState.ActiveAttackMul = 1f; return; } float num2 = 1f + num / 100f; if (num2 <= 0f || float.IsNaN(num2) || float.IsInfinity(num2)) { attackState.DesiredSpeed = 1f; attackState.HasDesiredSpeed = false; ApplyAnimSpeed(__instance, attackState, 1f); attackState.ActiveAttackDepth = 0; attackState.ActiveAttackMul = 1f; } else { attackState.DesiredSpeed = num2; attackState.HasDesiredSpeed = true; ApplyAnimSpeed(__instance, attackState, num2); attackState.ActiveAttackDepth++; attackState.ActiveAttackMul = num2; DLogAttackSpeed($"StartAttack: total AttackSpeed%={num} → mul={num2} (activeDepth={attackState.ActiveAttackDepth})"); } } } [HarmonyPatch(typeof(Attack), "Stop")] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public static class Attack_Stop_AttackSpeedResetPatch { [HarmonyPostfix] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static void Postfix(Attack __instance) { try { EnsureAttackInit(); if (__instance != null) { Humanoid character = __instance.m_character; if (!((Object)(object)character == (Object)null)) { ResetForHumanoid(character); DLogAttackSpeed("Attack.Stop: ResetForHumanoid"); } } } catch (Exception) { } } } [HarmonyPatch(typeof(Humanoid), "UpdateAttack")] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public static class Humanoid_UpdateAttack_AttackSpeedDtPatch { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [HarmonyPrefix] private static void Prefix(Humanoid __instance, ref float dt) { try { EnsureAttackInit(); if ((Object)(object)__instance == (Object)null) { return; } HumanoidState attackState = GetAttackState(__instance); if (attackState.ActiveAttackDepth > 0) { float activeAttackMul = attackState.ActiveAttackMul; if (!(activeAttackMul <= 0f) && !float.IsNaN(activeAttackMul) && !float.IsInfinity(activeAttackMul)) { dt *= activeAttackMul; } } } catch (Exception ex) { LogError("Exception in Humanoid_UpdateAttack_AttackSpeedDtPatch: " + ex); } } } [HarmonyPatch(typeof(Humanoid), "CustomFixedUpdate")] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public static class Humanoid_CustomFixedUpdate_AttackSpeedPatch { [HarmonyPostfix] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static void Postfix(Humanoid __instance, float fixedDeltaTime) { EnsureAttackInit(); HumanoidState attackState = GetAttackState(__instance); bool flag = ((Character)__instance).InAttack(); if (flag) { if (attackState.HasDesiredSpeed) { ApplyAnimSpeed(__instance, attackState, attackState.DesiredSpeed); } else { ApplyAnimSpeed(__instance, attackState, 1f); } } else if (attackState.WasInAttack) { ApplyAnimSpeed(__instance, attackState, 1f); attackState.HasDesiredSpeed = false; attackState.DesiredSpeed = 1f; } attackState.WasInAttack = flag; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(Character), "RPC_Stagger")] public static class Character_RPC_Stagger_AttackSpeedResetPatch { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [HarmonyPostfix] private static void Postfix(Character __instance, long sender, Vector3 forceDirection) { try { EnsureAttackInit(); Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null); if (!((Object)(object)val == (Object)null)) { ResetForHumanoid(val); } } catch (Exception) { } } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(Character), "OnDeath")] public static class Character_OnDeath_AttackSpeedResetPatch { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [HarmonyPostfix] private static void Postfix(Character __instance) { try { EnsureAttackInit(); Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null); if (!((Object)(object)val == (Object)null)) { ResetForHumanoid(val); } } catch (Exception) { } } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(Character), "FreezeFrame")] public static class Character_FreezeFrame_AttackSpeedScalePatch { [HarmonyPrefix] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static void Prefix(Character __instance, ref float duration) { try { EnsureAttackInit(); if ((Object)(object)__instance == (Object)null || Mathf.Abs(duration - 0.15f) > 0.01f) { return; } Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } HumanoidState attackState = GetAttackState(val); if (!attackState.HasDesiredSpeed) { return; } float desiredSpeed = attackState.DesiredSpeed; if (!(desiredSpeed <= 1.001f) && !float.IsNaN(desiredSpeed) && !float.IsInfinity(desiredSpeed)) { float num = duration / desiredSpeed; if (num < 0.03f) { num = 0.03f; } DLogAttackSpeed($"FreezeFrame scale: {duration:F3} -> {num:F3} (mul={desiredSpeed:F3})"); duration = num; } } catch (Exception ex) { LogError("Exception in Character_FreezeFrame_AttackSpeedScalePatch: " + ex); } } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(CharacterAnimEvent), "UpdateFreezeFrame")] public static class CharacterAnimEvent_UpdateFreezeFrame_ReapplySpeedPatch { [HarmonyPostfix] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static void Postfix(CharacterAnimEvent __instance, float dt) { try { EnsureAttackInit(); if ((Object)(object)__instance == (Object)null) { return; } Character componentInParent = ((Component)__instance).GetComponentInParent<Character>(); Humanoid val = (Humanoid)(object)((componentInParent is Humanoid) ? componentInParent : null); if (!((Object)(object)val == (Object)null)) { HumanoidState attackState = GetAttackState(val); if (attackState.HasDesiredSpeed && (attackState.ActiveAttackDepth > 0 || ((Character)val).InAttack())) { ApplyAnimSpeed(val, attackState, attackState.DesiredSpeed); } else { ApplyAnimSpeed(val, attackState, 1f); } } } catch (Exception ex) { LogError("Exception in CharacterAnimEvent_UpdateFreezeFrame_ReapplySpeedPatch: " + ex); } } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(int), typeof(bool), typeof(int), typeof(float) })] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public static class SEMan_AddStatusEffect_ByHash_WetImmunePatch { [HarmonyPrefix] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static bool Prefix(SEMan __instance, int nameHash, bool resetTime, int itemLevel, float skillLevel) { try { EnsureWetInit(); if (nameHash != SEMan.s_statusEffectWet) { return true; } Character val = null; try { val = _semanCharacterRef.Invoke(__instance); } catch (Exception) { val = null; } if ((Object)(object)val != (Object)null && HasWetImmune(val)) { DLogWet("Blocked Wet (AddStatusEffect by hash) due to WetImmune"); return false; } } catch (Exception ex2) { LogError("Exception in SEMan_AddStatusEffect_ByHash_WetImmunePatch: " + ex2); } return true; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float) })] public static class SEMan_AddStatusEffect_BySE_WetImmunePatch { [HarmonyPrefix] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] private static bool Prefix(SEMan __instance, StatusEffect statusEffect, bool resetTime, int itemLevel, float skillLevel, ref StatusEffect __result) { try { if ((Object)(object)statusEffect == (Object)null) { return true; } if (statusEffect.NameHash() != SEMan.s_statusEffectWet) { return true; } Character character = statusEffect.m_character; if ((Object)(object)character != (Object)null && HasWetImmune(character)) { DLogWet("Blocked Wet (AddStatusEffect by SE) due to WetImmune"); __result = null; return false; } } catch (Exception ex) { LogError("Exception in SEMan_AddStatusEffect_BySE_WetImmunePatch: " + ex); } return true; } } public static bool DEBUG = false; public static readonly List<ExtraStatEntry> ExtraStatsConfig = new List<ExtraStatEntry> { new ExtraStatEntry("SE_ShipAleBarrel_DO", ExtraStatType.Stamina, 20f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_ShipAleBarrel_DO", ExtraStatType.Health, -5f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_CaptainArmor_DO", ExtraStatType.Stamina, 30f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_CaptainBelt_DO", ExtraStatType.Stamina, 10f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SwordCaptainCutlassDO", ExtraStatType.AttackSpeed, 90f, 50f, ExtraSourceType.ItemDrop), new ExtraStatEntry("AxeSailorDO", ExtraStatType.AttackSpeed, 50f, 50f, ExtraSourceType.ItemDrop), new ExtraStatEntry("BastardShogunKatanaDO", ExtraStatType.AttackSpeed, 50f, 50f, ExtraSourceType.ItemDrop), new ExtraStatEntry("SE_SailorArmor_DO", ExtraStatType.WetImmune, 1f, ExtraSourceType.StatusEffect) }; private static readonly ConditionalWeakTable<Humanoid, HumanoidState> _attackState = new ConditionalWeakTable<Humanoid, HumanoidState>(); private static FieldRef<Character, ZSyncAnimation> _zanimRef; private static bool _attackInit; private const float HitFreeze_Default = 0.15f; private const float HitFreeze_Epsilon = 0.01f; private const float HitFreeze_Min = 0.03f; private static FieldRef<SEMan, Character> _semanCharacterRef; private static bool _wetInit; private static void LogInfo(string msg) { } private static void LogError(string msg) { } private static void DLogAttackSpeed(string msg) { } private static void DLogWet(string msg) { } private static void DLogTooltip(string msg) { } private static void DLogFood(string msg) { } private static void GetItemDropBonusesForPrefab(string prefabName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out float displayAttackSpeedPercent, out bool wetImmune) { extraHp = 0f; extraStamina = 0f; extraEitr = 0f; extraAttackSpeedPercent = 0f; displayAttackSpeedPercent = 0f; wetImmune = false; if (string.IsNullOrEmpty(prefabName)) { return; } for (int i = 0; i < ExtraStatsConfig.Count; i++) { ExtraStatEntry extraStatEntry = ExtraStatsConfig[i]; if (extraStatEntry.SourceType == ExtraSourceType.ItemDrop && string.Equals(prefabName, extraStatEntry.PrefabName, StringComparison.OrdinalIgnoreCase)) { switch (extraStatEntry.StatType) { case ExtraStatType.Health: extraHp += extraStatEntry.Value; break; case ExtraStatType.Stamina: extraStamina += extraStatEntry.Value; break; case ExtraStatType.Eitr: extraEitr += extraStatEntry.Value; break; case ExtraStatType.AttackSpeed: extraAttackSpeedPercent += extraStatEntry.Value; displayAttackSpeedPercent += (extraStatEntry.DisplayValue.HasValue ? extraStatEntry.DisplayValue.Value : extraStatEntry.Value); break; case ExtraStatType.WetImmune: wetImmune = true; break; } } } } private static void GetItemDropBonusesForPrefab(string prefabName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out bool wetImmune) { GetItemDropBonusesForPrefab(prefabName, out extraHp, out extraStamina, out extraEitr, out extraAttackSpeedPercent, out var _, out wetImmune); } private static void GetStatusEffectBonuses(string seRawName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out float displayAttackSpeedPercent, out bool wetImmune) { extraHp = 0f; extraStamina = 0f; extraEitr = 0f; extraAttackSpeedPercent = 0f; displayAttackSpeedPercent = 0f; wetImmune = false; if (string.IsNullOrEmpty(seRawName)) { return; } string prefabName = Utils.GetPrefabName(seRawName); for (int i = 0; i < ExtraStatsConfig.Count; i++) { ExtraStatEntry extraStatEntry = ExtraStatsConfig[i]; if (extraStatEntry.SourceType == ExtraSourceType.StatusEffect && string.Equals(prefabName, extraStatEntry.PrefabName, StringComparison.OrdinalIgnoreCase)) { switch (extraStatEntry.StatType) { case ExtraStatType.Health: extraHp += extraStatEntry.Value; break; case ExtraStatType.Stamina: extraStamina += extraStatEntry.Value; break; case ExtraStatType.Eitr: extraEitr += extraStatEntry.Value; break; case ExtraStatType.AttackSpeed: extraAttackSpeedPercent += extraStatEntry.Value; displayAttackSpeedPercent += (extraStatEntry.DisplayValue.HasValue ? extraStatEntry.DisplayValue.Value : extraStatEntry.Value); break; case ExtraStatType.WetImmune: wetImmune = true; break; } } } } private static void GetStatusEffectBonuses(string seRawName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out bool wetImmune) { GetStatusEffectBonuses(seRawName, out extraHp, out extraStamina, out extraEitr, out extraAttackSpeedPercent, out var _, out wetImmune); } private static string BuildExtraStatsTooltipBlock(float extraHp, float extraStamina, float extraEitr, float displayAttackSpeedPercent, bool wetImmune) { if (extraHp == 0f && extraStamina == 0f && extraEitr == 0f && displayAttackSpeedPercent == 0f && !wetImmune) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); string text = "$extrastats_health_DO"; string text2 = "$extrastats_stamina_DO"; string text3 = "$extrastats_eitr_DO"; string text4 = "$extrastats_attackspeed_DO"; string text5 = "$extrastats_immune_DO"; string text6 = "$extrastats_wet_DO"; if (Localization.instance != null) { text = Localization.instance.Localize(text); text2 = Localization.instance.Localize(text2); text3 = Localization.instance.Localize(text3); text4 = Localization.instance.Localize(text4); text5 = Localization.instance.Localize(text5); text6 = Localization.instance.Localize(text6); } if (extraHp != 0f) { string arg = ((extraHp >= 0f) ? "+" : ""); stringBuilder.Append($"\n{text}: <color=#f27979>{arg}{extraHp:F0}</color>"); } if (extraStamina != 0f) { string arg2 = ((extraStamina >= 0f) ? "+" : ""); stringBuilder.Append($"\n{text2}: <color=#ffff80>{arg2}{extraStamina:F0}</color>"); } if (extraEitr != 0f) { string arg3 = ((extraEitr >= 0f) ? "+" : ""); stringBuilder.Append($"\n{text3}: <color=#8686ee>{arg3}{extraEitr:F0}</color>"); } if (displayAttackSpeedPercent != 0f) { int num = Mathf.RoundToInt(displayAttackSpeedPercent); string arg4 = ((num >= 0) ? "+" : ""); stringBuilder.Append($"\n{text4}: <color=orange>{arg4}{num}%</color>"); } if (wetImmune) { stringBuilder.Append("\n" + text5 + ": <color=orange>" + text6 + "</color>"); } return stringBuilder.ToString(); } private static bool HasWetImmune(Character c) { if ((Object)(object)c == (Object)null) { return false; } try { Player val = (Player)(object)((c is Player) ? c : null); if ((Object)(object)val != (Object)null) { Inventory inventory = ((Humanoid)val).GetInventory(); if (inventory != null) { List<ItemData> equippedItems = inventory.GetEquippedItems(); for (int i = 0; i < equippedItems.Count; i++) { ItemData val2 = equippedItems[i]; if (val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null)) { string name = ((Object)val2.m_dropPrefab).name; GetItemDropBonusesForPrefab(name, out var _, out var _, out var _, out var _, out var _, out var wetImmune); if (wetImmune) { DLogWet("WetImmune from ItemDrop: " + name); return true; } } } } } if (c.m_seman != null && c.m_seman.m_statusEffects != null) { List<StatusEffect> statusEffects = c.m_seman.m_statusEffects; for (int j = 0; j < statusEffects.Count; j++) { StatusEffect val3 = statusEffects[j]; if (!((Object)(object)val3 == (Object)null)) { string name2 = ((Object)val3).name; GetStatusEffectBonuses(name2, out var _, out var _, out var _, out var _, out var _, out var wetImmune2); if (wetImmune2) { string prefabName = Utils.GetPrefabName(name2); DLogWet("WetImmune from StatusEffect: " + name2 + " (clean=" + prefabName + ")"); return true; } } } } } catch (Exception ex) { LogError("Exception in HasWetImmune: " + ex); } return false; } private static void EnsureAttackInit() { if (!_attackInit) { _attackInit = true; _zanimRef = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim"); } } private static HumanoidState GetAttackState(Humanoid h) { return _attackState.GetValue(h, (Humanoid _) => new HumanoidState()); } private static void ApplyAnimSpeed(Humanoid h, HumanoidState state, float speed) { ZSyncAnimation val = null; try { val = _zanimRef.Invoke((Character)(object)h); } catch (Exception) { return; } if (!((Object)(object)val == (Object)null) && !Mathf.Approximately(state.LastAppliedSpeed, speed)) { val.SetSpeed(speed); state.LastAppliedSpeed = speed; } } private static void ResetForHumanoid(Humanoid h) { if (!((Object)(object)h == (Object)null)) { EnsureAttackInit(); HumanoidState attackState = GetAttackState(h); ApplyAnimSpeed(h, attackState, 1f); attackState.HasDesiredSpeed = false; attackState.DesiredSpeed = 1f; attackState.WasInAttack = false; attackState.ActiveAttackDepth = 0; attackState.ActiveAttackMul = 1f; } } private static float ComputeTotalAttackSpeedPercentForHumanoid(Humanoid h) { float num = 0f; if ((Object)(object)h == (Object)null) { return 0f; } try { Player val = (Player)(object)((h is Player) ? h : null); if ((Object)(object)val != (Object)null) { Inventory inventory = ((Humanoid)val).GetInventory(); if (inventory != null) { List<ItemData> equippedItems = inventory.GetEquippedItems(); for (int i = 0; i < equippedItems.Count; i++) { ItemData val2 = equippedItems[i]; if (val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null)) { string name = ((Object)val2.m_dropPrefab).name; GetItemDropBonusesForPrefab(name, out var _, out var _, out var _, out var extraAttackSpeedPercent, out var _, out var _); if (extraAttackSpeedPercent != 0f) { num += extraAttackSpeedPercent; DLogAttackSpeed($"AttackSpeed from ItemDrop: {name} → {extraAttackSpeedPercent}%"); } } } } } if (((Character)h).m_seman != null && ((Character)h).m_seman.m_statusEffects != null) { List<StatusEffect> statusEffects = ((Character)h).m_seman.m_statusEffects; for (int j = 0; j < statusEffects.Count; j++) { StatusEffect val3 = statusEffects[j]; if (!((Object)(object)val3 == (Object)null)) { string name2 = ((Object)val3).name; GetStatusEffectBonuses(name2, out var _, out var _, out var _, out var extraAttackSpeedPercent2, out var _, out var _); if (extraAttackSpeedPercent2 != 0f) { num += extraAttackSpeedPercent2; string prefabName = Utils.GetPrefabName(name2); DLogAttackSpeed($"AttackSpeed from StatusEffect: {name2} (clean={prefabName}) → {extraAttackSpeedPercent2}%"); } } } } } catch (Exception ex) { LogError("Exception in ComputeTotalAttackSpeedPercentForHumanoid: " + ex); } return num; } private static void EnsureWetInit() { if (!_wetInit) { _wetInit = true; _semanCharacterRef = AccessTools.FieldRefAccess<SEMan, Character>("m_character"); } } } namespace PieceManager { [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [PublicAPI] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] public static class MaterialReplacer { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] public enum ShaderType { PieceShader, VegetationShader, RockShader, RugShader, GrassShader, CustomCreature, UseUnityShader } private static readonly Dictionary<GameObject, bool> ObjectToSwap; private static readonly Dictionary<string, Material> OriginalMaterials; private static readonly Dictionary<GameObject, ShaderType> ObjectsForShaderReplace; private static readonly HashSet<Shader> CachedShaders; private static bool hasRun; static MaterialReplacer() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown CachedShaders = new HashSet<Shader>(); hasRun = false; OriginalMaterials = new Dictionary<string, Material>(); ObjectToSwap = new Dictionary<GameObject, bool>(); ObjectsForShaderReplace = new Dictionary<GameObject, ShaderType>(); new Harmony("org.bepinex.helpers.PieceManager").Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZoneSystem), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(MaterialReplacer), "ReplaceAllMaterialsWithOriginal", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } public static void RegisterGameObjectForShaderSwap(GameObject go, ShaderType type) { if (!ObjectsForShaderReplace.ContainsKey(go)) { ObjectsForShaderReplace.Add(go, type); } } public static void RegisterGameObjectForMatSwap(GameObject go, bool isJotunnMock = false) { if (!ObjectToSwap.ContainsKey(go)) { ObjectToSwap.Add(go, isJotunnMock); } } private static void GetAllMaterials() { Material[] array = Resources.FindObjectsOfTypeAll<Material>(); foreach (Material val in array) { OriginalMaterials[((Object)val).name] = val; } } [HarmonyPriority(700)] private static void ReplaceAllMaterialsWithOriginal() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType == 4 || hasRun) { return; } if (OriginalMaterials.Count == 0) { GetAllMaterials(); } foreach (KeyValuePair<GameObject, bool> item in ObjectToSwap) { GameObject key = item.Key; bool value = item.Value; ProcessGameObjectMaterials(key, value); } AssetBundle[] array = Resources.FindObjectsOfTypeAll<AssetBundle>(); foreach (AssetBundle val in array) { IEnumerable<Shader> enumerable3; try { IEnumerable<Shader> enumerable2; if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val)) { IEnumerable<Shader> enumerable = val.LoadAllAssets<Shader>(); enumerable2 = enumerable; } else { enumerable2 = from shader in ((IEnumerable<string>)val.GetAllAssetNames()).Select((Func<string, Shader>)val.LoadAsset<Shader>) where (Object)(object)shader != (Object)null select shader; } enumerable3 = enumerable2; } catch (Exception) { continue; } if (enumerable3 == null) { continue; } foreach (Shader item2 in enumerable3) { CachedShaders.Add(item2); } } foreach (KeyValuePair<GameObject, ShaderType> item3 in ObjectsForShaderReplace) { GameObject key2 = item3.Key; ShaderType value2 = item3.Value; ProcessGameObjectShaders(key2, value2); } hasRun = true; } private static void ProcessGameObjectMaterials(GameObject go, bool isJotunnMock) { Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); foreach (Renderer obj in componentsInChildren) { Material[] sharedMaterials = obj.sharedMaterials.Select([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Material material) => ReplaceMaterial(material, isJotunnMock)).ToArray(); obj.sharedMaterials = sharedMaterials; } } private static Material ReplaceMaterial(Material originalMaterial, bool isJotunnMock) { string text = (isJotunnMock ? "JVLmock_" : "_REPLACE_"); if (!((Object)originalMaterial).name.StartsWith(text, StringComparison.Ordinal)) { return originalMaterial; } string text2 = ((Object)originalMaterial).name.Replace(" (Instance)", "").Replace(text, ""); if (OriginalMaterials.TryGetValue(text2, out var value)) { return value; } Debug.LogWarning((object)("No suitable material found to replace: " + text2)); return originalMaterial; } private static void ProcessGameObjectShaders(GameObject go, ShaderType shaderType) { Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)(object)val != (Object)null) { val.shader = GetShaderForType(val.shader, shaderType, ((Object)val.shader).name); } } } } private static Shader GetShaderForType(Shader orig, ShaderType shaderType, string originalShaderName) { return (Shader)(shaderType switch { ShaderType.PieceShader => FindShaderWithName(orig, "Custom/Piece"), ShaderType.VegetationShader => FindShaderWithName(orig, "Custom/Vegetation"), ShaderType.RockShader => FindShaderWithName(orig, "Custom/StaticRock"), ShaderType.RugShader => FindShaderWithName(orig, "Custom/Rug"), ShaderType.GrassShader => FindShaderWithName(orig, "Custom/Grass"), ShaderType.CustomCreature => FindShaderWithName(orig, "Custom/Creature"), ShaderType.UseUnityShader => FindShaderWithName(orig, ((Object)(object)FindShaderWithName(orig, originalShaderName) != (Object)null) ? originalShaderName : "ToonDeferredShading2017"), _ => FindShaderWithName(orig, "Standard"), }); } public static Shader FindShaderWithName(Shader origShader, string name) { foreach (Shader cachedShader in CachedShaders) { if (((Object)cachedShader).name == name) { return cachedShader; } } return origShader; } } [PublicAPI] public enum CraftingTable { None, [InternalName("piece_workbench")] Workbench, [InternalName("piece_cauldron")] Cauldron, [InternalName("forge")] Forge, [InternalName("piece_artisanstation")] ArtisanTable, [InternalName("piece_stonecutter")] StoneCutter, [InternalName("piece_magetable")] MageTable, [InternalName("blackforge")] BlackForge, [InternalName("piece_preptable")] FoodPreparationTable, [InternalName("piece_MeadCauldron")] MeadKetill, Custom } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] public class InternalName : Attribute { public readonly string internalName; public InternalName(string internalName) { this.internalName = internalName; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [PublicAPI] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] public class ExtensionList { public readonly List<ExtensionConfig> ExtensionStations = new List<ExtensionConfig>(); public void Set(CraftingTable table, int maxStationDistance = 5) { ExtensionStations.Add(new ExtensionConfig { Table = table, maxStationDistance = maxStationDistance }); } public void Set(string customTable, int maxStationDistance = 5) { ExtensionStations.Add(new ExtensionConfig { Table = CraftingTable.Custom, custom = customTable, maxStationDistance = maxStationDistance }); } } public struct ExtensionConfig { public CraftingTable Table; public float maxStationDistance; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] public string custom; } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [PublicAPI] public class CraftingStationList { public readonly List<CraftingStationConfig> Stations = new List<CraftingStationConfig>(); public void Set(CraftingTable table) { Stations.Add(new CraftingStationConfig { Table = table }); } public void Set(string customTable) { Stations.Add(new CraftingStationConfig { Table = CraftingTable.Custom, custom = customTable }); } } public struct CraftingStationConfig { public CraftingTable Table; public int level; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] public string custom; } [PublicAPI] public enum BuildPieceCategory { Misc = 0, Crafting = 1, BuildingWorkbench = 2, BuildingStonecutter = 3, Furniture = 4, All = 100, Custom = 99 } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [PublicAPI] public class RequiredResourcesList { public readonly List<Requirement> Requirements = new List<Requirement>(); public void Add(string item, int amount, bool recover) { Requirements.Add(new Requirement { itemName = item, amount = amount, recover = recover }); } } public struct Requirement { [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(1)] public string itemName; public int amount; public bool recover; } public struct SpecialProperties { [Description("Admins should be the only ones that can build this piece.")] public bool AdminOnly; [Description("Turns off generating a config for this build piece.")] public bool NoConfig; } [PublicAPI] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] public class BuildingPieceCategory { public BuildPieceCategory Category; public string custom = ""; public void Set(BuildPieceCategory category) { Category = category; } public void Set(string customCategory) { Category = BuildPieceCategory.Custom; custom = customCategory; } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [PublicAPI] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] public class PieceTool { public readonly HashSet<string> Tools = new HashSet<string>(); public void Add(string tool) { Tools.Add(tool); } } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(1)] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] [PublicAPI] public class BuildPiece { [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] internal class PieceConfig { public ConfigEntry<string> craft; public ConfigEntry<BuildPieceCategory> category; public ConfigEntry<string> customCategory; public ConfigEntry<string> tools; public ConfigEntry<CraftingTable> extensionTable; public ConfigEntry<string> customExtentionTable; public ConfigEntry<float> maxStationDistance; public ConfigEntry<CraftingTable> table; public ConfigEntry<string> customTable; } [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] public string Category; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(new byte[] { 2, 1 })] [UsedImplicitly] public Action<ConfigEntryBase> CustomDrawer; } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(0)] private class SerializedRequirements { public readonly List<Requirement> Reqs; public SerializedRequirements(List<Requirement> reqs) { Reqs = reqs; } public SerializedRequirements(string reqs) { Reqs = reqs.Split(new char[1] { ',' }).Select([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (string r) => { string[] array = r.Split(new char[1] { ':' }); Requirement result = default(Requirement); result.itemName = array[0]; result.amount = ((array.Length <= 1 || !int.TryParse(array[1], out var result2)) ? 1 : result2); bool result3 = default(bool); result.recover = array.Length <= 2 || !bool.TryParse(array[2], out result3) || result3; return result; }).ToList(); } public override string ToString() { return string.Join(",", Reqs.Select([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Requirement r) => $"{r.itemName}:{r.amount}:{r.recover}")); } [return: <1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] public static ItemDrop fetchByName(ObjectDB objectDB, string name) { GameObject itemPrefab = objectDB.GetItemPrefab(name); ItemDrop obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)obj == (Object)null) { Debug.LogWarning((object)(((!string.IsNullOrWhiteSpace(((Object)plugin).name)) ? ("[" + ((Object)plugin).name + "]") : "") + " The required item '" + name + "' does not exist.")); } return obj; } public static Requirement[] toPieceReqs(SerializedRequirements craft) { return craft.Reqs.Where((Requirement r) => r.itemName != "").ToDictionary((Func<Requirement, string>)([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Requirement r) => r.itemName), (Func<Requirement, Requirement>)([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Requirement r) => { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ItemDrop val = ResItem(r); return (val != null) ? new Requirement { m_amount = r.amount, m_resItem = val, m_recover = r.recover } : ((Requirement)null); })).Values.Where([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Requirement v) => v != null).ToArray(); [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(2)] static ItemDrop ResItem(Requirement r) { return fetchByName(ObjectDB.instance, r.itemName); } } } internal static readonly List<BuildPiece> registeredPieces = new List<BuildPiece>(); private static readonly Dictionary<Piece, BuildPiece> pieceMap = new Dictionary<Piece, BuildPiece>(); internal static Dictionary<BuildPiece, PieceConfig> pieceConfigs = new Dictionary<BuildPiece, PieceConfig>(); internal List<Conversion> Conversions = new List<Conversion>(); internal List<ItemConversion> conversions = new List<ItemConversion>(); [Description("Disables generation of the configs for your pieces. This is global, this turns it off for all pieces in your mod.")] public static bool ConfigurationEnabled = true; public readonly GameObject Prefab; [Description("Specifies the resources needed to craft the piece.\nUse .Add to add resources with their internal ID and an amount.\nUse one .Add for each resource type the building piece should need.")] public readonly RequiredResourcesList RequiredItems = new RequiredResourcesList(); [Description("Sets the category for the building piece.")] public readonly BuildingPieceCategory Category = new BuildingPieceCategory(); [Description("Specifies the tool needed to build your piece.\nUse .Add to add a tool.")] public readonly PieceTool Tool = new PieceTool(); [Description("Specifies the crafting station needed to build your piece.\nUse .Add to add a crafting station, using the CraftingTable enum and a minimum level for the crafting station.")] public CraftingStationList Crafting = new CraftingStationList(); [Description("Makes this piece a station extension")] public ExtensionList Extension = new ExtensionList(); [Description("Change the extended/special properties of your build piece.")] public SpecialProperties SpecialProperties; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] [Description("Specifies a config entry which toggles whether a recipe is active.")] public ConfigEntryBase RecipeIsActive; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] private LocalizeKey _name; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] private LocalizeKey _description; internal string[] activeTools; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] private static object configManager; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] private static Localization _english; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] internal static BaseUnityPlugin _plugin = null; private static bool hasConfigSync = true; [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] private static object _configSync; public LocalizeKey Name { get { LocalizeKey name = _name; if (name != null) { return name; } Piece component = Prefab.GetComponent<Piece>(); if (component.m_name.StartsWith("$")) { _name = new LocalizeKey(component.m_name); } else { string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_"); _name = new LocalizeKey(text).English(component.m_name); component.m_name = text; } return _name; } } public LocalizeKey Description { get { LocalizeKey description = _description; if (description != null) { return description; } Piece component = Prefab.GetComponent<Piece>(); if (component.m_description.StartsWith("$")) { _description = new LocalizeKey(component.m_description); } else { string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_") + "_description"; _description = new LocalizeKey(text).English(component.m_description); component.m_description = text; } return _description; } } private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English")); internal static BaseUnityPlugin plugin { get { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown if (_plugin != null) { return _plugin; } IEnumerable<TypeInfo> source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); return _plugin; } } [<1b7e9e30-9233-4cce-ab17-c3347351c0db>Nullable(2)] private static object configSync { [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(2)] get { if (_configSync != null || !hasConfigSync) { return _configSync; } Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync"); if ((object)type != null) { _configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " PieceManager"); type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString()); type.GetProperty("IsLocked").SetValue(_configSync, true); } else { hasConfigSync = false; } return _configSync; } } public BuildPiece(string assetBundleFileName, string prefabName, string folderName = "assets") : this(PiecePrefabManager.RegisterAssetBundle(assetBundleFileName, folderName), prefabName) { } public BuildPiece(AssetBundle bundle, string prefabName) { Prefab = PiecePrefabManager.RegisterPrefab(bundle, prefabName); registeredPieces.Add(this); } internal static void Patch_FejdStartup(FejdStartup __instance) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Expected O, but got Unknown //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Expected O, but got Unknown //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Expected O, but got Unknown //IL_0586: Unknown result type (might be due to invalid IL or missing references) //IL_0590: Expected O, but got Unknown //IL_0849: Unknown result type (might be due to invalid IL or missing references) //IL_0853: Expected O, but got Unknown //IL_05f6: Unknown result type (might be due to invalid IL or missing references) //IL_0600: Expected O, but got Unknown //IL_0697: Unknown result type (might be due to invalid IL or missing references) //IL_06a1: Expected O, but got Unknown //IL_08b9: Unknown result type (might be due to invalid IL or missing references) //IL_08c3: Expected O, but got Unknown //IL_0ac1: Unknown result type (might be due to invalid IL or missing references) //IL_0acb: Expected O, but got Unknown //IL_0b5a: Unknown result type (might be due to invalid IL or missing references) //IL_0b64: Expected O, but got Unknown Type configManagerType = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Assembly a) => a.GetName().Name == "ConfigurationManager")?.GetType("ConfigurationManager.ConfigurationManager"); configManager = ((configManagerType == null) ? null : Chainloader.ManagerObject.GetComponent(configManagerType)); foreach (BuildPiece registeredPiece in registeredPieces) { registeredPiece.activeTools = registeredPiece.Tool.Tools.DefaultIfEmpty("Hammer").ToArray(); if (registeredPiece.Category.Category != BuildPieceCategory.Custom) { registeredPiece.Prefab.GetComponent<Piece>().m_category = (PieceCategory)registeredPiece.Category.Category; } else { registeredPiece.Prefab.GetComponent<Piece>().m_category = PiecePrefabManager.GetCategory(registeredPiece.Category.custom); } } if (!ConfigurationEnabled) { return; } bool saveOnConfigSet = plugin.Config.SaveOnConfigSet; plugin.Config.SaveOnConfigSet = false; foreach (BuildPiece registeredPiece2 in registeredPieces) { BuildPiece piece = registeredPiece2; if (piece.SpecialProperties.NoConfig) { continue; } PieceConfig pieceConfig2 = (pieceConfigs[piece] = new PieceConfig()); PieceConfig cfg = pieceConfig2; Piece piecePrefab2 = piece.Prefab.GetComponent<Piece>(); string pieceName = piecePrefab2.m_name; string englishName = new Regex("[=\\n\\t\\\\\"\\'\\[\\]]*").Replace(english.Localize(pieceName), "").Trim(); string localizedName = Localization.instance.Localize(pieceName).Trim(); int order = 0; cfg.category = config(englishName, "Build Table Category", piece.Category.Category, new ConfigDescription("Build Category where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = (order -= 1), Category = localizedName } })); ConfigurationManagerAttributes customTableAttributes = new ConfigurationManagerAttributes { Order = (order -= 1), Browsable = (cfg.category.Value == BuildPieceCategory.Custom), Category = localizedName }; cfg.customCategory = config(englishName, "Custom Build Category", piece.Category.custom, new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes })); cfg.category.SettingChanged += BuildTableConfigChanged; cfg.customCategory.SettingChanged += BuildTableConfigChanged; if (cfg.category.Value == BuildPieceCategory.Custom) { piecePrefab2.m_category = PiecePrefabManager.GetCategory(cfg.customCategory.Value); } else { piecePrefab2.m_category = (PieceCategory)cfg.category.Value; } cfg.tools = config(englishName, "Tools", string.Join(", ", piece.activeTools), new ConfigDescription("Comma separated list of tools where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1] { customTableAttributes })); piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' }) select s.Trim()).ToArray(); cfg.tools.SettingChanged += [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (object _, EventArgs _) => { Inventory[] source = (from c in Player.s_players.Select([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Player p) => ((Humanoid)p).GetInventory()).Concat(from c in Object.FindObjectsOfType<Container>() select c.GetInventory()) where c != null select c).ToArray(); Dictionary<string, List<PieceTable>> dictionary = (from kv in (from i in (from p in ObjectDB.instance.m_items select p.GetComponent<ItemDrop>() into c where Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>()) select c).Concat(ItemDrop.s_instances) select new KeyValuePair<string, ItemData>(Utils.GetPrefabName(((Component)i).gameObject), i.m_itemData)).Concat(from i in source.SelectMany([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (Inventory i) => i.GetAllItems()) select new KeyValuePair<string, ItemData>(((Object)i.m_dropPrefab).name, i)) where Object.op_Implicit((Object)(object)kv.Value.m_shared.m_buildPieces) group kv by kv.Key).ToDictionary([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (IGrouping<string, KeyValuePair<string, ItemData>> g) => g.Key, [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (IGrouping<string, KeyValuePair<string, ItemData>> g) => g.Select([<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (KeyValuePair<string, ItemData> kv) => kv.Value.m_shared.m_buildPieces).Distinct().ToList()); string[] array5 = piece.activeTools; foreach (string key in array5) { if (dictionary.TryGetValue(key, out var value2)) { foreach (PieceTable item3 in value2) { item3.m_pieces.Remove(piece.Prefab); } } } piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' }) select s.Trim()).ToArray(); if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { array5 = piece.activeTools; foreach (string key2 in array5) { if (dictionary.TryGetValue(key2, out var value3)) { foreach (PieceTable item4 in value3) { if (!item4.m_pieces.Contains(piece.Prefab)) { item4.m_pieces.Add(piece.Prefab); } } } } if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_buildPieces)) { PiecePrefabManager.CategoryRefreshNeeded = true; ((Humanoid)Player.m_localPlayer).SetPlaceMode(Player.m_localPlayer.m_buildPieces); } } }; StationExtension pieceExtensionComp; List<ConfigurationManagerAttributes> hideWhenNoneAttributes2; if (piece.Extension.ExtensionStations.Count > 0) { pieceExtensionComp = piece.Prefab.GetOrAddComponent<StationExtension>(); PieceConfig pieceConfig3 = cfg; string group = englishName; CraftingTable table = piece.Extension.ExtensionStations.First().Table; string text = "Crafting station that " + localizedName + " extends."; object[] array = new object[1]; ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes(); int num = order - 1; order = num; configurationManagerAttributes.Order = num; array[0] = configurationManagerAttributes; pieceConfig3.extensionTable = config(group, "Extends Station", table, new ConfigDescription(text, (AcceptableValueBase)null, array)); cfg.customExtentionTable = config(englishName, "Custom Extend Station", piece.Extension.ExtensionStations.First().custom ?? "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes })); PieceConfig pieceConfig4 = cfg; string group2 = englishName; float maxStationDistance = piece.Extension.ExtensionStations.First().maxStationDistance; string text2 = "Distance from the station that " + localizedName + " can be placed."; object[] array2 = new object[1]; ConfigurationManagerAttributes configurationManagerAttributes2 = new ConfigurationManagerAttributes(); num = order - 1; order = num; configurationManagerAttributes2.Order = num; array2[0] = configurationManagerAttributes2; pieceConfig4.maxStationDistance = config(group2, "Max Station Distance", maxStationDistance, new ConfigDescription(text2, (AcceptableValueBase)null, array2)); hideWhenNoneAttributes2 = new List<ConfigurationManagerAttributes>(); cfg.extensionTable.SettingChanged += ExtensionTableConfigChanged; cfg.customExtentionTable.SettingChanged += ExtensionTableConfigChanged; cfg.maxStationDistance.SettingChanged += ExtensionTableConfigChanged; ConfigurationManagerAttributes configurationManagerAttributes3 = new ConfigurationManagerAttributes(); num = order - 1; order = num; configurationManagerAttributes3.Order = num; configurationManagerAttributes3.Browsable = cfg.extensionTable.Value != CraftingTable.None; ConfigurationManagerAttributes item = configurationManagerAttributes3; hideWhenNoneAttributes2.Add(item); } List<ConfigurationManagerAttributes> hideWhenNoneAttributes; if (piece.Crafting.Stations.Count > 0) { hideWhenNoneAttributes = new List<ConfigurationManagerAttributes>(); PieceConfig pieceConfig5 = cfg; string group3 = englishName; CraftingTable table2 = piece.Crafting.Stations.First().Table; string text3 = "Crafting station where " + localizedName + " is available."; object[] array3 = new object[1]; ConfigurationManagerAttributes configurationManagerAttributes4 = new ConfigurationManagerAttributes(); int num = order - 1; order = num; configurationManagerAttributes4.Order = num; array3[0] = configurationManagerAttributes4; pieceConfig5.table = config(group3, "Crafting Station", table2, new ConfigDescription(text3, (AcceptableValueBase)null, array3)); cfg.customTable = config(englishName, "Custom Crafting Station", piece.Crafting.Stations.First().custom ?? "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes })); cfg.table.SettingChanged += TableConfigChanged; cfg.customTable.SettingChanged += TableConfigChanged; ConfigurationManagerAttributes configurationManagerAttributes5 = new ConfigurationManagerAttributes(); num = order - 1; order = num; configurationManagerAttributes5.Order = num; configurationManagerAttributes5.Browsable = cfg.table.Value != CraftingTable.None; ConfigurationManagerAttributes item2 = configurationManagerAttributes5; hideWhenNoneAttributes.Add(item2); } cfg.craft = itemConfig("Crafting Costs", new SerializedRequirements(piece.RequiredItems.Requirements).ToString(), "Item costs to craft " + localizedName); cfg.craft.SettingChanged += [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (object _, EventArgs _) => { if (Object.op_Implicit((Object)(object)ObjectDB.instance) && (Object)(object)ObjectDB.instance.GetItemPrefab("YmirRemains") != (Object)null) { Requirement[] resources = SerializedRequirements.toPieceReqs(new SerializedRequirements(cfg.craft.Value)); piecePrefab2.m_resources = resources; Piece[] array4 = Object.FindObjectsOfType<Piece>(); foreach (Piece val in array4) { if (val.m_name == pieceName) { val.m_resources = resources; } } } }; for (int j = 0; j < piece.Conversions.Count; j++) { string text4 = ((piece.Conversions.Count > 1) ? $"{j + 1}. " : ""); Conversion conversion = piece.Conversions[j]; conversion.config = new Conversion.ConversionConfig(); int index = j; conversion.config.input = config(englishName, text4 + "Conversion Input Item", conversion.Input, new ConfigDescription("Conversion input item within " + englishName, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Category = localizedName } })); conversion.config.input.SettingChanged += [<0b8b779e-e92b-4295-b4ce-c0b2d8a3a96b>NullableContext(0)] (object _, EventArgs _) => { if (index < piece.conversions.Count) { ObjectDB instance2 = ObjectDB.instance; if (instance2 != null) { ItemDrop from = SerializedRequirements.fetchByName(instance2, conversion.config.input.Value); piece.conversions[index].m_from = from; } } }; conversion.config.output = config(englishName, text4 + "Conversion Output Item", conversion.Output, new ConfigDescription("Conversion outp