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 Skyla v0.8.0
Skyla.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using Tali_Skyla.GUI; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Skyla")] [assembly: AssemblyDescription("Tali.Skyla")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyProduct("Skyla")] [assembly: AssemblyCopyright("Copyright © Tali")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6941129c-0802-45bb-b0e2-2a2c7a44bc81")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyCompany("Tali")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Tali_Skyla { internal class ArmorStandPatch { [HarmonyPatch(typeof(ArmorStand), "UseItem")] public static class ArmorStand_UseItem_Patch { public static bool Prefix(ItemStand __instance, Switch caller, Humanoid user, ItemData item) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_ITEMSTAND); } return false; } } } public class Assets { private sealed class AddedChime { public Skyla.ChimeType Chime; public string PrefabName; public string DisplayName; public string Description; } [HarmonyPatch(typeof(ObjectDB), "Awake")] public class ObjectDB_Awake_Patch { public static void Postfix(ObjectDB __instance) { RegisterIntoObjectDB(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public class ObjectDB_CopyOtherDB_Patch { public static void Postfix(ObjectDB __instance) { RegisterIntoObjectDB(__instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public class ZNetScene_Awake_Patch { public static bool Prefix(ZNetScene __instance) { LoadAssets(); GameObject[] s_prefabs = Assets.s_prefabs; foreach (GameObject val in s_prefabs) { if ((Object)(object)val.GetComponent<ZNetView>() != (Object)null) { __instance.m_prefabs.Add(val); } } return true; } public static void Postfix(ZNetScene __instance) { s_applyBlessingFXPrefab = __instance.GetPrefab(s_applyBlessingFX); s_activateFXPrefab = __instance.GetPrefab(s_activateFX); s_deactivateFXPrefab = __instance.GetPrefab(s_deactivateFX); } } private static bool assetsLoaded = false; public static string s_resourceName = "skyla"; public static GameObject[] s_prefabs = null; public static Recipe[] s_recipes = null; private static string s_applyBlessingFX = "vfx_skyla_applyblessing"; public static GameObject s_applyBlessingFXPrefab; private static string s_activateFX = "sfx_skyla_activate"; public static GameObject s_activateFXPrefab; private static string s_deactivateFX = "sfx_skyla_deactivate"; public static GameObject s_deactivateFXPrefab; private static GameObject s_balmyPrefab; private static readonly AddedChime[] s_addedChimes = new AddedChime[3] { new AddedChime { Chime = Skyla.ChimeType.CHIME_VIGOUR, PrefabName = "Skyla_Chime_Vigour", DisplayName = "Chime of Vigour", Description = "Eikthyr's restlessness, bound in bronze. Applied to a Skýla, everything done in range costs less stamina." }, new AddedChime { Chime = Skyla.ChimeType.CHIME_WARMTH, PrefabName = "Skyla_Chime_Warmth", DisplayName = "Chime of Warmth", Description = "Struck from Moder's own heat. Applied to a Skýla, cold and freezing cannot take hold in range." }, new AddedChime { Chime = Skyla.ChimeType.CHIME_EMBERS, PrefabName = "Skyla_Chime_Embers", DisplayName = "Chime of Embers", Description = "An ember of the Ashlands that will not die. Applied to a Skýla, fires in range never burn through their fuel." } }; private static readonly Dictionary<Skyla.ChimeType, GameObject> s_addedPrefabs = new Dictionary<Skyla.ChimeType, GameObject>(); private static AssetBundle GetAssetBundleFromResources(string filename) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); return AssetBundle.LoadFromStream(executingAssembly.GetManifestResourceStream(executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(filename)))); } public static void LoadAssets() { if (!assetsLoaded) { AssetBundle assetBundleFromResources = GetAssetBundleFromResources(s_resourceName); if ((Object)(object)assetBundleFromResources == (Object)null) { Debug.Log((object)("Failed to load AssetBundle " + s_resourceName)); return; } s_prefabs = assetBundleFromResources.LoadAllAssets<GameObject>(); s_recipes = assetBundleFromResources.LoadAllAssets<Recipe>(); Debug.Log((object)$"Loaded {s_prefabs.Length} prefabs and {s_recipes.Length} recipes from assetBundle {s_resourceName}"); assetBundleFromResources.Unload(false); SkylaGUI.Init(); assetsLoaded = true; } } public static void RegisterIntoObjectDB(ObjectDB db) { if ((Object)(object)db == (Object)null) { return; } LoadAssets(); if (s_prefabs == null) { return; } Dictionary<int, GameObject> itemByHash = GetItemByHash(db); int num = 0; GameObject[] array = s_prefabs; foreach (GameObject val in array) { if ((Object)(object)val == (Object)null) { continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { continue; } if (!db.m_items.Contains(val)) { db.m_items.Add(val); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name); itemByHash[stableHashCode] = val; string text = component.m_itemData?.m_shared?.m_name; bool flag = false; if (!string.IsNullOrEmpty(text) && PerkConfig.s_chimeMap.TryGetValue(text, out var value)) { flag = true; } else if (TryMatchChimeByPrefabName(((Object)val).name, out value)) { flag = true; if (!string.IsNullOrEmpty(text) && !PerkConfig.s_chimeMap.ContainsKey(text)) { PerkConfig.s_chimeMap[text] = value; } } if (flag) { Chime.AddChime(val); PerkConfig.s_chimePrefabMap[value] = val; num++; Debug.Log((object)$"[Skyla] Registered Chime item '{((Object)val).name}' shared='{text}' -> {value}"); } else if ((Object)(object)component != (Object)null) { Debug.Log((object)("[Skyla] Prefab '" + ((Object)val).name + "' has ItemDrop shared='" + text + "' but did not match a Chime.")); } } EnsureBalmyChime(db, itemByHash); EnsureAddedUtilityChimes(db, itemByHash); if (s_recipes != null) { Recipe[] array2 = s_recipes; foreach (Recipe val2 in array2) { if ((Object)(object)val2 != (Object)null && !db.m_recipes.Contains(val2)) { db.m_recipes.Add(val2); } } } AccessTools.DeclaredMethod(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null)?.Invoke(db, null); Skyla.EnsureSkylaInHammer(); Debug.Log((object)$"[Skyla] ObjectDB register done — {PerkConfig.s_chimePrefabMap.Count} Chime prefab(s) in map (pass registered {num})."); } private static void EnsureBalmyChime(ObjectDB db, Dictionary<int, GameObject> itemByHash) { if ((Object)(object)db == (Object)null) { return; } GameObject itemPrefab = db.GetItemPrefab("Skyla_Chime_Balmy"); if ((Object)(object)itemPrefab != (Object)null) { s_balmyPrefab = itemPrefab; PerkConfig.s_chimePrefabMap[Skyla.ChimeType.CHIME_CLEAR] = itemPrefab; PerkConfig.s_chimeMap["Balmy Chime"] = Skyla.ChimeType.CHIME_CLEAR; return; } if ((Object)(object)s_balmyPrefab == (Object)null && PerkConfig.s_chimePrefabMap.TryGetValue(Skyla.ChimeType.CHIME_CLEAR, out var value) && (Object)(object)value != (Object)null && ((Object)value).name == "Skyla_Chime_Balmy") { s_balmyPrefab = value; } if ((Object)(object)s_balmyPrefab == (Object)null) { GameObject value2 = null; if (!PerkConfig.s_chimePrefabMap.TryGetValue(Skyla.ChimeType.CHIME_SNOW, out value2) || (Object)(object)value2 == (Object)null) { using Dictionary<Skyla.ChimeType, GameObject>.Enumerator enumerator = PerkConfig.s_chimePrefabMap.GetEnumerator(); if (enumerator.MoveNext()) { value2 = enumerator.Current.Value; } } if ((Object)(object)value2 == (Object)null) { Debug.LogError((object)"[Skyla] Cannot synthesize Balmy Chime — no donor chime prefab."); return; } GameObject val = Object.Instantiate<GameObject>(value2); ((Object)val).name = "Skyla_Chime_Balmy"; Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; val.SetActive(false); ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData?.m_shared == null) { Debug.LogError((object)"[Skyla] Balmy Chime clone has no ItemDrop/shared data."); Object.Destroy((Object)(object)val); return; } component.m_itemData.m_shared.m_name = "Balmy Chime"; component.m_itemData.m_shared.m_description = "A soft meadow chime. Applied to a Skýla, it clears the weather in range."; component.m_itemData.m_dropPrefab = val; Chime.AddChime(val); s_balmyPrefab = val; Debug.Log((object)("[Skyla] Synthesized missing Balmy Chime from '" + ((Object)value2).name + "'.")); } if (!db.m_items.Contains(s_balmyPrefab)) { db.m_items.Add(s_balmyPrefab); } if (itemByHash != null) { itemByHash[StringExtensionMethods.GetStableHashCode(((Object)s_balmyPrefab).name)] = s_balmyPrefab; } PerkConfig.s_chimePrefabMap[Skyla.ChimeType.CHIME_CLEAR] = s_balmyPrefab; PerkConfig.s_chimeMap["Balmy Chime"] = Skyla.ChimeType.CHIME_CLEAR; Debug.Log((object)"[Skyla] Balmy Chime registered into ObjectDB."); } private static void EnsureAddedUtilityChimes(ObjectDB db, Dictionary<int, GameObject> itemByHash) { if ((Object)(object)db == (Object)null) { return; } AddedChime[] array = s_addedChimes; foreach (AddedChime addedChime in array) { GameObject itemPrefab = db.GetItemPrefab(addedChime.PrefabName); GameObject value; if ((Object)(object)itemPrefab != (Object)null) { value = itemPrefab; s_addedPrefabs[addedChime.Chime] = itemPrefab; } else if (!s_addedPrefabs.TryGetValue(addedChime.Chime, out value) || (Object)(object)value == (Object)null) { value = SynthesizeChime(addedChime); if ((Object)(object)value == (Object)null) { continue; } s_addedPrefabs[addedChime.Chime] = value; } if (!db.m_items.Contains(value)) { db.m_items.Add(value); } if (itemByHash != null) { itemByHash[StringExtensionMethods.GetStableHashCode(((Object)value).name)] = value; } PerkConfig.s_chimePrefabMap[addedChime.Chime] = value; PerkConfig.s_chimeMap[addedChime.DisplayName] = addedChime.Chime; } } private static GameObject SynthesizeChime(AddedChime spec) { GameObject value = null; Skyla.ChimeType[] array = new Skyla.ChimeType[4] { Skyla.ChimeType.CHIME_INDUSTRY, Skyla.ChimeType.CHIME_COMFORT, Skyla.ChimeType.CHIME_FARMING, Skyla.ChimeType.CHIME_COOKING }; foreach (Skyla.ChimeType key in array) { if (PerkConfig.s_chimePrefabMap.TryGetValue(key, out value) && (Object)(object)value != (Object)null) { break; } value = null; } if ((Object)(object)value == (Object)null) { using Dictionary<Skyla.ChimeType, GameObject>.Enumerator enumerator = PerkConfig.s_chimePrefabMap.GetEnumerator(); if (enumerator.MoveNext()) { value = enumerator.Current.Value; } } if ((Object)(object)value == (Object)null) { Debug.LogError((object)("[Skyla] Cannot synthesize " + spec.DisplayName + " — no donor chime prefab.")); return null; } GameObject val = Object.Instantiate<GameObject>(value); ((Object)val).name = spec.PrefabName; Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; val.SetActive(false); ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData?.m_shared == null) { Debug.LogError((object)("[Skyla] " + spec.DisplayName + " clone has no ItemDrop/shared data.")); Object.Destroy((Object)(object)val); return null; } component.m_itemData.m_shared.m_name = spec.DisplayName; component.m_itemData.m_shared.m_description = spec.Description; component.m_itemData.m_dropPrefab = val; Chime.AddChime(val); Debug.Log((object)("[Skyla] Synthesized " + spec.DisplayName + " from '" + ((Object)value).name + "'.")); return val; } public static void EnsureBalmyInCurrentObjectDB() { ObjectDB instance = ObjectDB.instance; if (!((Object)(object)instance == (Object)null)) { Dictionary<int, GameObject> itemByHash = GetItemByHash(instance); EnsureBalmyChime(instance, itemByHash); EnsureAddedUtilityChimes(instance, itemByHash); AccessTools.DeclaredMethod(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null)?.Invoke(instance, null); } } private static bool TryMatchChimeByPrefabName(string prefabName, out Skyla.ChimeType chime) { chime = Skyla.ChimeType.CHIME_FARMING; if (string.IsNullOrEmpty(prefabName)) { return false; } string text = prefabName.ToLowerInvariant(); if (text.Contains("fertility") || text.Contains("farming")) { chime = Skyla.ChimeType.CHIME_FARMING; return true; } if (text.Contains("hearth") || text.Contains("cooking")) { chime = Skyla.ChimeType.CHIME_COOKING; return true; } if (text.Contains("comfort")) { chime = Skyla.ChimeType.CHIME_COMFORT; return true; } if (text.Contains("industry")) { chime = Skyla.ChimeType.CHIME_INDUSTRY; return true; } if (text.Contains("blizzard") || text.Contains("snowstorm")) { chime = Skyla.ChimeType.CHIME_SNOWSTORM; return true; } if (text.Contains("snow")) { chime = Skyla.ChimeType.CHIME_SNOW; return true; } if (text.Contains("ash")) { chime = Skyla.ChimeType.CHIME_ASHRAIN; return true; } if (text.Contains("tempest") || text.Contains("mistland")) { chime = Skyla.ChimeType.CHIME_MISTLANDS_STORM; return true; } if (text.Contains("storm") || text.Contains("thunder")) { chime = Skyla.ChimeType.CHIME_STORM; return true; } if (text.Contains("balmy") || text.Contains("clear")) { chime = Skyla.ChimeType.CHIME_CLEAR; return true; } return false; } private static Dictionary<int, GameObject> GetItemByHash(ObjectDB objDB) { FieldInfo field = typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic); if (!(field != null)) { return new Dictionary<int, GameObject>(); } return (Dictionary<int, GameObject>)field.GetValue(objDB); } } internal class BeehivePatch { [HarmonyPatch(typeof(Beehive), "Interact")] public static class Beehive_Interact_Patch { public static bool Prefix(Beehive __instance, Humanoid character, bool repeat, bool alt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_BEEHIVE); } return false; } } } internal static class BossAltarGuard { [HarmonyPatch(typeof(OfferingBowl), "Awake")] public static class OfferingBowl_Awake_Patch { public static void Postfix(OfferingBowl __instance) { Register(__instance); } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] public static class Player_UpdatePlacementGhost_Patch { private static readonly FieldInfo f_ghost = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly FieldInfo f_status = AccessTools.Field(typeof(Player), "m_placementStatus"); private static readonly MethodInfo m_setValid = AccessTools.Method(typeof(Player), "SetPlacementGhostValid", new Type[1] { typeof(bool) }, (Type[])null); public static void Postfix(Player __instance) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!(f_ghost == null) && !(f_status == null)) { object? value = f_ghost.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if (!((Object)(object)val == (Object)null) && IsSkyla(val) && IsBlocked(val.transform.position, out var _)) { f_status.SetValue(__instance, (object)(PlacementStatus)3); m_setValid?.Invoke(__instance, new object[1] { false }); } } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] public static class Player_TryPlacePiece_Patch { private static readonly FieldInfo f_ghost = AccessTools.Field(typeof(Player), "m_placementGhost"); public static bool Prefix(Player __instance, ref bool __result) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (f_ghost == null) { return true; } object? value = f_ghost.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null || !IsSkyla(val)) { return true; } if (!IsBlocked(val.transform.position, out var distance)) { return true; } ((Character)__instance).Message((MessageType)2, $"Too close to a boss altar ({distance:0}m of {SkylaConfig.BossAltarExclusionRadius():0}m).", 0, (Sprite)null, false); __result = false; return false; } } private static readonly List<OfferingBowl> s_altars = new List<OfferingBowl>(); internal static void Register(OfferingBowl bowl) { if (!((Object)(object)bowl == (Object)null)) { s_altars.RemoveAll((OfferingBowl a) => (Object)(object)a == (Object)null); if (!s_altars.Contains(bowl)) { s_altars.Add(bowl); } } } internal static bool IsBlocked(Vector3 position, out float distance) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) distance = float.MaxValue; float num = SkylaConfig.BossAltarExclusionRadius(); if (num <= 0f) { return false; } bool result = false; for (int num2 = s_altars.Count - 1; num2 >= 0; num2--) { OfferingBowl val = s_altars[num2]; if ((Object)(object)val == (Object)null) { s_altars.RemoveAt(num2); } else if (!((Object)(object)val.m_bossPrefab == (Object)null)) { float num3 = Vector3.Distance(((Component)val).transform.position, position); if (!(num3 > num)) { result = true; if (num3 < distance) { distance = num3; } } } } return result; } internal static bool IsSkyla(GameObject go) { if ((Object)(object)go == (Object)null) { return false; } if ((Object)(object)go.GetComponent<Skyla>() != (Object)null) { return true; } return ((Object)go).name.StartsWith(Skyla.s_prefabName, StringComparison.Ordinal); } } public class Chime : MonoBehaviour { private static AudioSource s_master; private static readonly HashSet<AudioSource> s_sources = new HashSet<AudioSource>(); private static readonly object s_lock = new object(); private AudioSource m_source; public static void AddChime(GameObject prefab) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponentInChildren<Chime>() != (Object)null)) { GameObject val = prefab; Transform val2 = prefab.transform.Find("attach"); if ((Object)(object)val2 != (Object)null) { val = ((Component)val2).gameObject; } val.AddComponent<Chime>(); } } private void Awake() { m_source = ((Component)this).GetComponentInChildren<AudioSource>(); if ((Object)(object)m_source == (Object)null) { Debug.LogWarning((object)("[Chime] No AudioSource found on '" + ((Object)((Component)this).gameObject).name + "'. Chime will not be registered.")); return; } lock (s_lock) { s_sources.Add(m_source); if ((Object)(object)s_master == (Object)null) { s_master = m_source; } else if ((Object)(object)s_master != (Object)(object)m_source) { m_source.timeSamples = s_master.timeSamples; } } ZSFX componentInChildren = ((Component)this).GetComponentInChildren<ZSFX>(); if (componentInChildren != null) { componentInChildren.Play(); } } private void OnDestroy() { if ((Object)(object)m_source == (Object)null) { return; } lock (s_lock) { s_sources.Remove(m_source); s_master = null; using HashSet<AudioSource>.Enumerator enumerator = s_sources.GetEnumerator(); if (enumerator.MoveNext()) { s_master = enumerator.Current; } } } } public static class ChimeEffects { [HarmonyPatch(typeof(Character), "UseStamina")] public static class Character_UseStamina_Patch { public static void Prefix(Character __instance, ref float stamina) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!(stamina <= 0f) && !((Object)(object)__instance == (Object)null) && __instance is Player && Skyla.ChimeApplies(((Component)__instance).transform.position, Skyla.ChimeType.CHIME_VIGOUR)) { stamina *= 0.75f; } } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(int), typeof(bool), typeof(int), typeof(float), typeof(short) })] public static class SEMan_AddStatusEffect_Patch { public static bool Prefix(SEMan __instance, int nameHash, ref StatusEffect __result) { if (nameHash != s_coldHash && nameHash != s_freezingHash) { return true; } if (!PlayerCoveredBy(__instance, Skyla.ChimeType.CHIME_WARMTH)) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float), typeof(short) })] public static class SEMan_AddStatusEffectObj_Patch { public static bool Prefix(SEMan __instance, StatusEffect statusEffect, ref StatusEffect __result) { if ((Object)(object)statusEffect == (Object)null) { return true; } int num = statusEffect.NameHash(); if (num != s_coldHash && num != s_freezingHash) { return true; } if (!PlayerCoveredBy(__instance, Skyla.ChimeType.CHIME_WARMTH)) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] public static class Fireplace_UpdateFireplace_Patch { public static void Prefix(Fireplace __instance) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return; } int instanceID = ((Object)__instance).GetInstanceID(); bool flag = s_emberFires.Contains(instanceID); if (Skyla.ChimeApplies(((Component)__instance).transform.position, Skyla.ChimeType.CHIME_EMBERS)) { if (!__instance.m_infiniteFuel) { __instance.m_infiniteFuel = true; s_emberFires.Add(instanceID); } } else if (flag) { __instance.m_infiniteFuel = false; s_emberFires.Remove(instanceID); } } } public const float VigourStaminaMultiplier = 0.75f; private static readonly int s_coldHash = StringExtensionMethods.GetStableHashCode("Cold"); private static readonly int s_freezingHash = StringExtensionMethods.GetStableHashCode("Freezing"); private static readonly FieldInfo s_semanCharacter = AccessTools.Field(typeof(SEMan), "m_character"); private static readonly HashSet<int> s_emberFires = new HashSet<int>(); private static Character OwnerOf(SEMan seman) { if (seman == null || s_semanCharacter == null) { return null; } object? value = s_semanCharacter.GetValue(seman); return (Character)((value is Character) ? value : null); } private static bool PlayerCoveredBy(SEMan seman, Skyla.ChimeType chime) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) Character val = OwnerOf(seman); if ((Object)(object)val == (Object)null || !(val is Player)) { return false; } return Skyla.ChimeApplies(((Component)val).transform.position, chime); } } public static class ChimeTrader { private sealed class Offer { public Skyla.ChimeType Chime; public string GlobalKey; public string TrophyPrefab; public string Label; public bool Weather; } [HarmonyPatch(typeof(Trader), "Start")] public class Trader_Start_Patch { public static void Postfix(Trader __instance) { try { StockHaldor(__instance); } catch (Exception arg) { Debug.LogError((object)$"[Skyla] Haldor stock (Start) failed: {arg}"); } } } [HarmonyPatch(typeof(Trader), "Interact")] public class Trader_Interact_Patch { public static void Prefix(Trader __instance) { try { StockHaldor(__instance); } catch (Exception arg) { Debug.LogError((object)$"[Skyla] Haldor stock (Interact) failed: {arg}"); } } } [HarmonyPatch(typeof(StoreGui), "Show")] public class StoreGui_Show_Patch { public static void Prefix(Trader trader) { try { StockHaldor(trader); } catch (Exception arg) { Debug.LogError((object)$"[Skyla] Haldor stock (Show) failed: {arg}"); } } } [HarmonyPatch(typeof(StoreGui), "FillList")] public class StoreGui_FillList_Patch { private static readonly FieldInfo f_trader = AccessTools.Field(typeof(StoreGui), "m_trader"); public static void Prefix(StoreGui __instance) { try { object? obj = f_trader?.GetValue(__instance); StockHaldor((Trader)((obj is Trader) ? obj : null)); } catch (Exception arg) { Debug.LogError((object)$"[Skyla] Haldor stock (FillList) failed: {arg}"); } } } [HarmonyPatch(typeof(StoreGui), "CanAfford")] public class StoreGui_CanAfford_Patch { public static void Postfix(TradeItem item, ref bool __result) { CanAffordTrophy(item, ref __result); } } [HarmonyPatch(typeof(StoreGui), "BuySelectedItem")] public class StoreGui_BuySelectedItem_Patch { public static bool Prefix(StoreGui __instance) { string blockMessage; bool num = TryBeginBuy(__instance, out blockMessage); if (!num && !string.IsNullOrEmpty(blockMessage) && (Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, blockMessage, 0, (Sprite)null, false); } return num; } public static void Postfix() { FinishBuy(); } } [HarmonyPatch(typeof(StoreGui), "UpdateBuyButton")] public class StoreGui_UpdateBuyButton_Patch { public static void Postfix(StoreGui __instance) { RestrictBuyButton(__instance); } } private static readonly Offer[] s_offers = new Offer[13] { new Offer { Chime = Skyla.ChimeType.CHIME_FARMING, GlobalKey = "defeated_gdking", TrophyPrefab = "TrophyTheElder", Label = "Chime of Fertility", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_COMFORT, GlobalKey = "defeated_bonemass", TrophyPrefab = "TrophyBonemass", Label = "Chime of Comfort", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_COOKING, GlobalKey = "defeated_goblinking", TrophyPrefab = "TrophyGoblinKing", Label = "Chime of the Hearth", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_INDUSTRY, GlobalKey = "defeated_queen", TrophyPrefab = "TrophySeekerQueen", Label = "Chime of Industry", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_VIGOUR, GlobalKey = "defeated_eikthyr", TrophyPrefab = "TrophyEikthyr", Label = "Chime of Vigour", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_WARMTH, GlobalKey = "defeated_dragon", TrophyPrefab = "TrophyDragonQueen", Label = "Chime of Warmth", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_EMBERS, GlobalKey = "defeated_fader", TrophyPrefab = "TrophyFader", Label = "Chime of Embers", Weather = false }, new Offer { Chime = Skyla.ChimeType.CHIME_CLEAR, GlobalKey = "defeated_eikthyr", TrophyPrefab = "TrophyNeck", Label = "Balmy Chime", Weather = true }, new Offer { Chime = Skyla.ChimeType.CHIME_SNOW, GlobalKey = "defeated_dragon", TrophyPrefab = "TrophyWolf", Label = "Snow Chime", Weather = true }, new Offer { Chime = Skyla.ChimeType.CHIME_SNOWSTORM, GlobalKey = "defeated_dragon", TrophyPrefab = "TrophyHatchling", Label = "Blizzard Chime", Weather = true }, new Offer { Chime = Skyla.ChimeType.CHIME_STORM, GlobalKey = "defeated_goblinking", TrophyPrefab = "TrophyDeathsquito", Label = "Storm Chime", Weather = true }, new Offer { Chime = Skyla.ChimeType.CHIME_MISTLANDS_STORM, GlobalKey = "defeated_queen", TrophyPrefab = "TrophyGjall", Label = "Tempest Chime", Weather = true }, new Offer { Chime = Skyla.ChimeType.CHIME_ASHRAIN, GlobalKey = "defeated_fader", TrophyPrefab = "TrophyAsksvin", Label = "Chime of Ashes", Weather = true } }; private static readonly Dictionary<TradeItem, string> s_trophyByTrade = new Dictionary<TradeItem, string>(); private static readonly Dictionary<TradeItem, int> s_priceByTrade = new Dictionary<TradeItem, int>(); private static string s_pendingTrophyPrefab; private static string s_pendingChimeSharedName; private static int s_pendingChimeCountBefore; private static int s_pendingPrice; private static bool s_pendingBuy; private static bool Enabled => SkylaConfig.ChimeTraderEnabled(); private static int PriceFor(Offer offer) { if (!offer.Weather) { return SkylaConfig.ChimeTraderUtilityPrice(); } return SkylaConfig.ChimeTraderWeatherPrice(); } private static string TrophyKind(Offer offer) { if (!offer.Weather) { return "boss trophy"; } return "mob trophy"; } private static bool IsExcludedMerchant(Trader trader) { if ((Object)(object)trader == (Object)null) { return true; } string text = trader.m_name + " " + ((Object)((Component)trader).gameObject).name; if (text.IndexOf("Hildir", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("BogWitch", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("Blidh", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static ItemDrop FindItemDrop(string prefabName) { if (string.IsNullOrEmpty(prefabName) || (Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName); if (!((Object)(object)itemPrefab == (Object)null)) { return itemPrefab.GetComponent<ItemDrop>(); } return null; } private static bool TryGetChimeDrop(Skyla.ChimeType chime, out ItemDrop drop) { drop = null; if (!PerkConfig.s_chimePrefabMap.TryGetValue(chime, out var value) || (Object)(object)value == (Object)null) { if ((Object)(object)ObjectDB.instance != (Object)null) { Assets.RegisterIntoObjectDB(ObjectDB.instance); } if (!PerkConfig.s_chimePrefabMap.TryGetValue(chime, out value) || (Object)(object)value == (Object)null) { return false; } } drop = value.GetComponent<ItemDrop>(); return (Object)(object)drop != (Object)null; } private static bool HasGlobalKey(string key) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(key)) { return true; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return false; } if (instance.GetGlobalKey(key)) { return true; } if (Enum.TryParse<GlobalKeys>(key, ignoreCase: true, out GlobalKeys result) && instance.GetGlobalKey(result)) { return true; } return false; } public static void StockHaldor(Trader trader) { //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Expected O, but got Unknown if (!Enabled) { Debug.Log((object)"[Skyla] Haldor chime sales disabled in config."); } else { if ((Object)(object)trader == (Object)null || IsExcludedMerchant(trader)) { return; } Assets.EnsureBalmyInCurrentObjectDB(); string text = ((Object)((Component)trader).gameObject).name ?? "?"; string text2 = trader.m_name ?? ""; if (trader.m_items == null) { trader.m_items = new List<TradeItem>(); } trader.m_items.RemoveAll((TradeItem ti) => ti != null && s_trophyByTrade.ContainsKey(ti)); trader.m_items.RemoveAll(delegate(TradeItem ti) { if ((Object)(object)ti?.m_prefab == (Object)null) { return false; } Offer[] array3 = s_offers; for (int i = 0; i < array3.Length; i++) { if (TryGetChimeDrop(array3[i].Chime, out var drop2) && (Object)(object)drop2 == (Object)(object)ti.m_prefab) { return true; } } return false; }); List<TradeItem> list = new List<TradeItem>(); foreach (KeyValuePair<TradeItem, string> item in s_trophyByTrade) { if (trader.m_items.Contains(item.Key)) { list.Add(item.Key); } } foreach (TradeItem item2 in list) { s_trophyByTrade.Remove(item2); s_priceByTrade.Remove(item2); } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Offer[] array = s_offers; foreach (Offer offer in array) { if (!TryGetChimeDrop(offer.Chime, out var drop)) { num2++; Debug.LogWarning((object)$"[Skyla] Haldor: chime prefab missing for {offer.Chime} ({offer.Label})."); continue; } if ((Object)(object)FindItemDrop(offer.TrophyPrefab) == (Object)null) { Debug.LogWarning((object)("[Skyla] Haldor: trophy '" + offer.TrophyPrefab + "' not in ObjectDB — skipping " + offer.Label + ".")); continue; } if (!HasGlobalKey(offer.GlobalKey)) { num4++; continue; } int num6 = PriceFor(offer); TradeItem val = new TradeItem { m_prefab = drop, m_stack = 1, m_price = num6, m_requiredGlobalKey = "", m_name = offer.Label, m_tooltip = $"{num6} coins + {offer.TrophyPrefab} ({TrophyKind(offer)})" }; trader.m_items.Add(val); s_trophyByTrade[val] = offer.TrophyPrefab; s_priceByTrade[val] = num6; num++; num3++; } List<string> list2 = new List<string>(); string[] array2 = new string[7] { "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" }; foreach (string text3 in array2) { list2.Add(text3.Replace("defeated_", "") + "=" + (HasGlobalKey(text3) ? "yes" : "no")); } List<string> list3 = new List<string>(); foreach (TradeItem item3 in trader.m_items) { if (s_trophyByTrade.TryGetValue(item3, out var value)) { string text4 = (((Object)(object)item3.m_prefab != (Object)null) ? ((Object)item3.m_prefab).name : "<null>"); list3.Add(item3.m_name + "[" + text4 + "]<-" + value); } } string text5 = $"Haldor ('{text}' / '{text2}'): stocked {num} chime(s), {num4} still locked, missingPrefab={num2}. " + "Bosses: " + string.Join(" ", list2.ToArray()) + "\n" + string.Format(" rows ({0}): {1}", list3.Count, string.Join(" | ", list3.ToArray())); if (Mod.Log != null) { Mod.Log.LogInfo((object)text5); } else { Debug.Log((object)("[Skyla] " + text5)); } } } private static bool TryGetOffer(TradeItem item, out Offer offer) { offer = null; if ((Object)(object)item?.m_prefab == (Object)null) { return false; } Offer[] array = s_offers; foreach (Offer offer2 in array) { if (TryGetChimeDrop(offer2.Chime, out var drop) && (Object)(object)drop == (Object)(object)item.m_prefab) { offer = offer2; return true; } } return false; } private static bool TryGetRequiredTrophy(TradeItem item, out string trophyPrefab) { trophyPrefab = null; if (item == null) { return false; } if (s_trophyByTrade.TryGetValue(item, out trophyPrefab) && !string.IsNullOrEmpty(trophyPrefab)) { return true; } if (!TryGetOffer(item, out var offer)) { return false; } trophyPrefab = offer.TrophyPrefab; return true; } private static int PriceForTrade(TradeItem item) { if (item != null && s_priceByTrade.TryGetValue(item, out var value)) { return value; } if (TryGetOffer(item, out var offer)) { return PriceFor(offer); } return SkylaConfig.ChimeTraderUtilityPrice(); } private static ItemData FindTrophyInInventory(Inventory inv, string trophyPrefab) { if (inv == null || string.IsNullOrEmpty(trophyPrefab)) { return null; } ItemData item = inv.GetItem(trophyPrefab, -1, true); if (item != null) { return item; } ItemDrop val = FindItemDrop(trophyPrefab); if ((Object)(object)val == (Object)null) { return null; } string text = val.m_itemData?.m_shared?.m_name; if (string.IsNullOrEmpty(text)) { return null; } return inv.GetItem(text, -1, false); } private static bool PlayerHasTrophy(string trophyPrefab) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (FindTrophyInInventory(inventory, trophyPrefab) != null) { return true; } string text = FindItemDrop(trophyPrefab)?.m_itemData?.m_shared?.m_name; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != null) { string text2 = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null); if (!string.IsNullOrEmpty(text2) && text2.Equals(trophyPrefab, StringComparison.OrdinalIgnoreCase)) { return true; } if (!string.IsNullOrEmpty(text) && allItem.m_shared != null && allItem.m_shared.m_name == text) { return true; } } } return false; } private static bool TryBeginBuy(StoreGui gui, out string blockMessage) { blockMessage = null; s_pendingBuy = false; s_pendingTrophyPrefab = null; s_pendingChimeSharedName = null; s_pendingChimeCountBefore = 0; s_pendingPrice = 0; if (!Enabled) { return true; } Assets.EnsureBalmyInCurrentObjectDB(); object? obj = AccessTools.Field(typeof(StoreGui), "m_selectedItem")?.GetValue(gui); TradeItem val = (TradeItem)((obj is TradeItem) ? obj : null); if (!TryGetRequiredTrophy(val, out var trophyPrefab)) { return true; } int num = PriceForTrade(val); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if (!PlayerHasTrophy(trophyPrefab)) { blockMessage = $"Haldor wants {trophyPrefab} as well as {num} coins."; return false; } if ((Object)(object)val.m_prefab != (Object)null) { string name = ((Object)val.m_prefab).name; ObjectDB instance = ObjectDB.instance; GameObject val2 = ((instance != null) ? instance.GetItemPrefab(name) : null); if (!((Object)(object)val2 != (Object)null)) { blockMessage = "Haldor can't find " + name + " in the item database."; Debug.LogError((object)("[Skyla] Buy blocked — ObjectDB missing '" + name + "'.")); return false; } ItemDrop component = val2.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { val.m_prefab = component; } } string text = val.m_prefab?.m_itemData?.m_shared?.m_name; s_pendingBuy = true; s_pendingTrophyPrefab = trophyPrefab; s_pendingChimeSharedName = text; s_pendingPrice = num; s_pendingChimeCountBefore = ((!string.IsNullOrEmpty(text)) ? ((Humanoid)localPlayer).GetInventory().CountItems(text, -1, false) : 0); return true; } private static void FinishBuy() { if (!s_pendingBuy) { return; } s_pendingBuy = false; string text = s_pendingTrophyPrefab; string text2 = s_pendingChimeSharedName; int num = s_pendingChimeCountBefore; int num2 = s_pendingPrice; s_pendingTrophyPrefab = null; s_pendingChimeSharedName = null; s_pendingPrice = 0; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || string.IsNullOrEmpty(text)) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (!string.IsNullOrEmpty(text2) && inventory.CountItems(text2, -1, false) <= num) { Debug.LogWarning((object)"[Skyla] Buy finished but chime was not added — trophy not consumed."); return; } ItemData val = FindTrophyInInventory(inventory, text); if (val != null) { inventory.RemoveItem(val, 1); } else { string text3 = FindItemDrop(text)?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text3)) { inventory.RemoveItem(text3, 1, -1, false); } else { inventory.RemoveItem(text, 1, -1, true); } } ((Character)localPlayer).Message((MessageType)2, $"Traded {text} + {num2} coins.", 0, (Sprite)null, false); } private static void RestrictBuyButton(StoreGui gui) { if (!Enabled) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(StoreGui), "m_selectedItem"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(StoreGui), "m_buyButton"); object? obj = fieldInfo?.GetValue(gui); if (!TryGetRequiredTrophy((TradeItem)((obj is TradeItem) ? obj : null), out var trophyPrefab) || PlayerHasTrophy(trophyPrefab)) { return; } try { object? obj2 = fieldInfo2?.GetValue(gui); Button val = (Button)((obj2 is Button) ? obj2 : null); if ((Object)(object)val != (Object)null) { ((Selectable)val).interactable = false; } } catch { } } private static void CanAffordTrophy(TradeItem item, ref bool result) { if (result && Enabled && TryGetRequiredTrophy(item, out var trophyPrefab) && !PlayerHasTrophy(trophyPrefab)) { result = false; } } } internal class ContainerPatch { [HarmonyPatch(typeof(Container), "Interact")] public static class Container_Interact_Patch { public static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)character == (Object)null || !((Character)character).IsPlayer()) { return false; } Vagon componentInParent = ((Component)__instance).gameObject.GetComponentInParent<Vagon>(); if ((Object)(object)componentInParent != (Object)null) { return Skyla.CanUseWagon(componentInParent, (Character)(object)character); } Ship componentInParent2 = ((Component)__instance).gameObject.GetComponentInParent<Ship>(); if ((Object)(object)componentInParent2 != (Object)null) { return Skyla.CanUseShip(componentInParent2, (Character)(object)character); } if (!((Object)(object)((Component)__instance).gameObject.GetComponent<TombStone>() != (Object)null)) { return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_CONTAINER); } return true; } } } [HarmonyPatch] internal static class CookingStationPatch { [HarmonyPatch(typeof(CookingStation), "UpdateFuel")] [HarmonyPrefix] private static void UpdateFuelPrefix(ref float dt, CookingStation __instance) { if (Applies(__instance)) { dt *= 0.5f; } } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] [HarmonyPrefix] private static bool UpdateCookingPrefix(CookingStation __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { return ZNetScene.instance.IsAreaReady(((Component)__instance).transform.position); } return false; } [HarmonyPatch(typeof(CookingStation), "GetSlot")] [HarmonyPostfix] private static void GetSlotPostfix(ref string itemName, ref float cookedTime, ref int status, CookingStation __instance) { if (!Applies(__instance)) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(CookingStation), "GetItemConversion", (Type[])null, (Type[])null); if (methodInfo == null || string.IsNullOrEmpty(itemName)) { return; } object obj = methodInfo.Invoke(__instance, new object[1] { itemName }); if (obj != null) { float num = (float)AccessTools.Field(obj.GetType(), "m_cookTime").GetValue(obj) * 1.1f; if (!((double)cookedTime <= (double)num)) { cookedTime = num; } } } [HarmonyPatch(typeof(CookingStation), "SetSlot")] [HarmonyPrefix] private static void SetSlotPrefix(int slot, ref string itemName, ref float cookedTime, ref int status, CookingStation __instance) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (!Applies(__instance)) { return; } ZNetView val = (ZNetView)AccessTools.Field(typeof(CookingStation), "m_nview").GetValue(__instance); if (!((Object)(object)val == (Object)null) && val.IsValid()) { float num = val.GetZDO().GetFloat("slot" + slot, 0f); if (status == 0) { float num2 = cookedTime - num; cookedTime = num + num2 * 1.25f; } } } private static bool Applies(CookingStation cs) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Skyla.ChimeApplies(((Component)cs).transform.position, Skyla.ChimeType.CHIME_COOKING); } } internal class DestructiblePatch { [HarmonyPatch(typeof(Destructible), "RPC_Damage")] public static class Destructible_Damage_Patch { public static bool Prefix(Destructible __instance, long sender, ref HitData hit) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || hit == null) { return false; } if ((Object)(object)((Component)__instance).GetComponent<RandomFlyingBird>() != (Object)null) { return true; } if ((Object)(object)hit.GetAttacker() != (Object)null && hit.GetAttacker().IsPlayer()) { return Skyla.CheckAccess(hit.GetAttacker(), ((Component)__instance).transform.position, Skyla.ActionType.ACTION_DAMAGE); } float num = 1f - Skyla.FindMaxSkylaPower(((Component)__instance).transform.position); if ((double)num <= 0.0) { return false; } hit.ApplyModifier(num); return true; } } } internal class DoorPatch { [HarmonyPatch(typeof(Door), "Interact")] public static class Door_Interact_Patch { public static bool Prefix(Door __instance, Humanoid character, bool hold, bool alt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_DOOR); } return false; } } } internal class EnvManPatch { [HarmonyPatch(typeof(EnvMan), "GetEnvironmentOverride")] public static class EnvMan_GetEnvironmentOverride_Patch { public static void Postfix(EnvMan __instance, ref string __result) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (__result == null && !((Object)(object)Player.m_localPlayer == (Object)null)) { switch (Skyla.FindWeatherMode(((Component)Player.m_localPlayer).transform.position)) { case PerkConfig.WeatherMode.WEATHER_SNOW: __result = (EnvMan.IsDay() ? "Snow" : "Twilight_Snow"); break; case PerkConfig.WeatherMode.WEATHER_STORM: __result = "ThunderStorm"; break; case PerkConfig.WeatherMode.WEATHER_SNOWSTORM: __result = (EnvMan.IsDay() ? "SnowStorm" : "Twilight_SnowStorm"); break; case PerkConfig.WeatherMode.WEATHER_MISTLANDS_STORM: __result = "Mistlands_thunder"; break; case PerkConfig.WeatherMode.WEATHER_ASHRAIN: __result = "Ashrain"; break; case PerkConfig.WeatherMode.WEATHER_CLEAR: __result = "Clear"; break; } } } } } internal class FermenterPatch { [HarmonyPatch(typeof(Fermenter), "Interact")] public static class Fermenter_Interact_Patch { public static bool Prefix(Fermenter __instance, Humanoid user, bool hold, bool alt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_FERMENTER); } return false; } } } internal class FireplacePatch { [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] public static class Fireplace_UpdateFireplace_Patch { public static bool Prefix(Fireplace __instance, ref float __state) { if ((Object)(object)__instance == (Object)null) { return true; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsOwner()) { __state = component.GetZDO().GetFloat("fuel", 0f); } return true; } public static void Postfix(Fireplace __instance, float __state) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null)) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsOwner()) { float num = component.GetZDO().GetFloat("fuel", 0f); float num2 = Skyla.FindMaxSkylaPower(((Component)__instance).transform.position); float num3 = __state - num; float num4 = (((double)num2 > 0.9900000095367432) ? __instance.m_maxFuel : Math.Min(__instance.m_maxFuel, num + num3 * num2)); component.GetZDO().Set("fuel", num4); } } } } } internal class ItemStandPatch { [HarmonyPatch(typeof(ItemStand), "Interact")] public static class ItemStand_Interact_Patch { public static bool Prefix(ItemStand __instance, Humanoid user, bool hold, bool alt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_ITEMSTAND); } return false; } } [HarmonyPatch(typeof(ItemStand), "UseItem")] public static class ItemStand_UseItem_Patch { public static bool Prefix(ItemStand __instance, Humanoid user, ItemData item) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)user, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_ITEMSTAND); } return false; } } } public class LocalManager { private static ISet<ZDOID> s_localPlayerSkylaSet = new HashSet<ZDOID>(); private static float s_localPlayerSkylaAreaLimit = 0f; private static bool s_hasReceivedInfo = false; public static void RegisterRPC() { ZRoutedRpc.instance.Register<float, ZPackage>("ReceiveServerSkylaData", (Action<long, float, ZPackage>)RPC_ReceiveServerSkylaData); } private static void OutputLocalState() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)"=================================="); Debug.Log((object)"Dumping out local Skyla info:"); float num = 0f; foreach (ZDOID item in s_localPlayerSkylaSet) { float num2 = ZDOMan.instance.GetZDO(item).GetFloat("SkylaRadius", 0f); Debug.Log((object)$"ZDOID {item}, Radius: {num2}"); num += (float)Math.PI * num2 * num2; } Debug.Log((object)$"Total area used: {num}"); Debug.Log((object)"=================================="); } private static ISet<ZDOID> Decode(ZPackage zp) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) ISet<ZDOID> set = new HashSet<ZDOID>(); int num = zp.ReadInt(); for (int i = 0; i < num; i++) { ZDOID item = zp.ReadZDOID(); set.Add(item); } return set; } private static float GetLocalPlayerAreaLimit() { return s_localPlayerSkylaAreaLimit; } private static void RPC_ReceiveServerSkylaData(long sender, float maxWardedArea, ZPackage zp) { if (!float.IsNaN(maxWardedArea)) { s_localPlayerSkylaAreaLimit = maxWardedArea; } s_localPlayerSkylaSet = Decode(zp); s_hasReceivedInfo = true; } private static float GetUsedArea() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) float num = 0f; foreach (ZDOID item in s_localPlayerSkylaSet) { ZDO zDO = ZDOMan.instance.GetZDO(item); float num2 = ((zDO != null) ? zDO.GetFloat("SkylaRadius", 0f) : 0f); num += (float)Math.PI * num2 * num2; } return num; } public static float GetRemainingArea() { return Math.Max(GetLocalPlayerAreaLimit() - GetUsedArea(), 0f); } private static float DistanceToNearestBlockingSkyla(Skyla skyla) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) float val = 9999f; foreach (Skyla s_localSkyla in Skyla.s_localSkylaList) { if (s_localSkyla.GetOwner() != skyla.GetOwner()) { float val2 = Vector3.Distance(((Component)s_localSkyla).transform.position, ((Component)skyla).transform.position) - s_localSkyla.GetRadius(); val = Math.Min(val, val2); } } return Math.Max(val, 0f); } private static float DistanceToNearestNoBuildZone(Skyla skyla) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) float val = 9999f; Location[] array = Object.FindObjectsOfType<Location>(); foreach (Location val2 in array) { if (val2.m_noBuild && (double)val2.m_exteriorRadius > 0.0) { float val3 = Vector3.Distance(((Component)val2).transform.position, ((Component)skyla).transform.position) - val2.m_exteriorRadius; val = Math.Min(val, val3); } } return Math.Max(val, 0f); } public static float GetMaxRadiusForSkyla(Skyla skyla) { double num = GetRemainingArea(); float radius = skyla.GetRadius(); double num2 = 3.1415927410125732 * (double)radius * (double)radius; float num3 = (float)(num + num2); return Math.Min(DistanceToNearestBlockingSkyla(skyla), Math.Min(SkylaConfig.MaxSkylaRadius(), Math.Min(DistanceToNearestNoBuildZone(skyla), (float)Math.Sqrt((double)num3 / 3.1415927410125732)))); } private static void Local_RegisterSkyla(ZDO skylaZDO) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null) && skylaZDO.GetLong("creator", 0L) == Player.m_localPlayer.GetPlayerID()) { s_localPlayerSkylaSet.Add(skylaZDO.m_uid); } } private static void Local_UnregisterSkyla(ZDO skylaZDO) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null) && skylaZDO.GetLong("creator", 0L) == Player.m_localPlayer.GetPlayerID()) { s_localPlayerSkylaSet.Remove(skylaZDO.m_uid); } } public static void RemoveSkyla(ZDO skylaZDO) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) Local_UnregisterSkyla(skylaZDO); ZRoutedRpc.instance.InvokeRoutedRPC("UnregisterSkyla", new object[1] { skylaZDO.m_uid }); } public static void AddSkyla(ZDO skylaZDO) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) Local_RegisterSkyla(skylaZDO); ZRoutedRpc.instance.InvokeRoutedRPC("RegisterSkyla", new object[1] { skylaZDO.m_uid }); } public static void RequestInfo(long playerID) { ZRoutedRpc.instance.InvokeRoutedRPC("RequestInfo", new object[1] { playerID }); } } internal class MineRockPatch { [HarmonyPatch(typeof(MineRock), "RPC_Hit")] public static class MineRock_Hit_Patch { public static bool Prefix(MineRock __instance, long sender, ref HitData hit) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || hit == null) { return false; } if ((Object)(object)hit.GetAttacker() != (Object)null && hit.GetAttacker().IsPlayer()) { return Skyla.CheckAccess(hit.GetAttacker(), ((Component)__instance).transform.position, Skyla.ActionType.ACTION_DAMAGE); } float num = 1f - Skyla.FindMaxSkylaPower(((Component)__instance).transform.position); if ((double)num <= 0.0) { return false; } hit.ApplyModifier(num); return true; } } [HarmonyPatch(typeof(MineRock5), "RPC_Damage")] public static class MineRock5_Damage_Patch { public static bool Prefix(MineRock5 __instance, long sender, ref HitData hit) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || hit == null) { return false; } if ((Object)(object)hit.GetAttacker() != (Object)null && hit.GetAttacker().IsPlayer()) { return Skyla.CheckAccess(hit.GetAttacker(), ((Component)__instance).transform.position, Skyla.ActionType.ACTION_DAMAGE); } float num = 1f - Skyla.FindMaxSkylaPower(((Component)__instance).transform.position); if ((double)num <= 0.0) { return false; } hit.ApplyModifier(num); return true; } } } [BepInPlugin("Tali.Skyla", "Skyla", "0.8.0")] public class Mod : BaseUnityPlugin { public const string ModGuid = "Tali.Skyla"; private const string AuthorName = "Tali"; private const string ModName = "Skyla"; private const string ModVer = "0.8.0"; private readonly ConfigSync configSync = new ConfigSync("Skyla") { DisplayName = "Skyla", CurrentVersion = "0.8.0", MinimumRequiredVersion = "0.8.0", ModRequired = true }; private Harmony _harmony; internal static ManualLogSource Log; private void Awake() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; SkylaConfig.SetupConfig(this); configSync.IsLocked = true; SetupWatcher(); _harmony = new Harmony("Tali.Skyla"); _harmony.PatchAll(); _harmony.CreateClassProcessor(typeof(ChimeTrader.Trader_Start_Patch)).Patch(); _harmony.CreateClassProcessor(typeof(ChimeTrader.Trader_Interact_Patch)).Patch(); _harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_Show_Patch)).Patch(); _harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_FillList_Patch)).Patch(); _harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_CanAfford_Patch)).Patch(); _harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_BuySelectedItem_Patch)).Patch(); _harmony.CreateClassProcessor(typeof(ChimeTrader.StoreGui_UpdateBuyButton_Patch)).Patch(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ChimeTrader Harmony hooks registered."); } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { if (ZNet.instance.IsServer() && File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { ((BaseUnityPlugin)this).Config.Reload(); } } public ConfigEntry<T> SyncedConfig<T>(string group, string name, T defaultVal, string desc) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, defaultVal, new ConfigDescription(desc, (AcceptableValueBase)null, Array.Empty<object>())); configSync.AddConfigEntry<T>(val).SynchronizedConfig = true; return val; } } internal class ParticleMist_Patch { } public class PerkConfig { public enum WeatherMode { WEATHER_NONE, WEATHER_SNOW, WEATHER_STORM, WEATHER_SNOWSTORM, WEATHER_MISTLANDS_STORM, WEATHER_ASHRAIN, WEATHER_CLEAR, WEATHER_MAX } public class Farming { public const float c_harvestIncreaseProbability = 0.5f; public const int c_harvestIncrease = 1; public const float c_growTimeFactor = 0.8f; } public class Cooking { public const float c_fuelBurnRateFactor = 0.5f; public const float c_cookingTimeFactor = 0.8f; } public class Comfort { public const int c_comfortBoost = 3; } public class Industry { public const float c_fuelBurnRateFactor = 0.5f; public const float c_bakeRateFactor = 1.2f; } public static Dictionary<string, Skyla.ChimeType> s_chimeMap = new Dictionary<string, Skyla.ChimeType> { { "Chime of Fertility", Skyla.ChimeType.CHIME_FARMING }, { "Chime of the Hearth", Skyla.ChimeType.CHIME_COOKING }, { "Chime of Comfort", Skyla.ChimeType.CHIME_COMFORT }, { "Chime of Industry", Skyla.ChimeType.CHIME_INDUSTRY }, { "Snow Chime", Skyla.ChimeType.CHIME_SNOW }, { "Blizzard Chime", Skyla.ChimeType.CHIME_SNOWSTORM }, { "Chime of Ashes", Skyla.ChimeType.CHIME_ASHRAIN }, { "Storm Chime", Skyla.ChimeType.CHIME_STORM }, { "Tempest Chime", Skyla.ChimeType.CHIME_MISTLANDS_STORM }, { "Balmy Chime", Skyla.ChimeType.CHIME_CLEAR } }; public static Dictionary<Skyla.ChimeType, GameObject> s_chimePrefabMap = new Dictionary<Skyla.ChimeType, GameObject>(); public static Dictionary<Skyla.ChimeType, string> s_powerNameMap = new Dictionary<Skyla.ChimeType, string> { { Skyla.ChimeType.CHIME_FARMING, "Fertility" }, { Skyla.ChimeType.CHIME_COOKING, "Hearth" }, { Skyla.ChimeType.CHIME_COMFORT, "Comfort" }, { Skyla.ChimeType.CHIME_INDUSTRY, "Industry" } }; public static Dictionary<WeatherMode, string> s_weatherNameMap = new Dictionary<WeatherMode, string> { { WeatherMode.WEATHER_NONE, "<none>" }, { WeatherMode.WEATHER_CLEAR, "Clear" }, { WeatherMode.WEATHER_SNOW, "Snow" }, { WeatherMode.WEATHER_STORM, "Storm" }, { WeatherMode.WEATHER_SNOWSTORM, "Blizzard" }, { WeatherMode.WEATHER_MISTLANDS_STORM, "Tempest" }, { WeatherMode.WEATHER_ASHRAIN, "Ashrain" } }; public static string GetChimeDisplayName(Skyla.ChimeType chime) { return chime switch { Skyla.ChimeType.CHIME_FARMING => "Fertility", Skyla.ChimeType.CHIME_COOKING => "Hearth", Skyla.ChimeType.CHIME_COMFORT => "Comfort", Skyla.ChimeType.CHIME_INDUSTRY => "Industry", Skyla.ChimeType.CHIME_VIGOUR => "Vigour", Skyla.ChimeType.CHIME_WARMTH => "Warmth", Skyla.ChimeType.CHIME_EMBERS => "Embers", Skyla.ChimeType.CHIME_CLEAR => "Balmy", Skyla.ChimeType.CHIME_SNOW => "Snow", Skyla.ChimeType.CHIME_SNOWSTORM => "Blizzard", Skyla.ChimeType.CHIME_STORM => "Storm", Skyla.ChimeType.CHIME_MISTLANDS_STORM => "Tempest", Skyla.ChimeType.CHIME_ASHRAIN => "Ashes", _ => chime.ToString(), }; } public static string GetChimeEffect(Skyla.ChimeType chime) { return chime switch { Skyla.ChimeType.CHIME_FARMING => "Plants grow ~20% faster, with a chance of bonus harvest.", Skyla.ChimeType.CHIME_COOKING => "Cooking is faster and cook stations burn half as much fuel.", Skyla.ChimeType.CHIME_COMFORT => $"+{3} comfort while resting in range.", Skyla.ChimeType.CHIME_INDUSTRY => "Smelters and kilns run faster and use half the fuel.", Skyla.ChimeType.CHIME_VIGOUR => $"Everything you do in range costs ~{25}% less stamina.", Skyla.ChimeType.CHIME_WARMTH => "Cold and Freezing cannot take hold inside the Skýla range.", Skyla.ChimeType.CHIME_EMBERS => "Fires and torches in range never burn through their fuel.", Skyla.ChimeType.CHIME_CLEAR => "Forces clear skies inside the Skýla range.", Skyla.ChimeType.CHIME_SNOW => "Forces snow weather inside the Skýla range.", Skyla.ChimeType.CHIME_SNOWSTORM => "Forces a blizzard inside the Skýla range.", Skyla.ChimeType.CHIME_STORM => "Forces storm weather inside the Skýla range.", Skyla.ChimeType.CHIME_MISTLANDS_STORM => "Forces the Mistlands tempest inside the Skýla range.", Skyla.ChimeType.CHIME_ASHRAIN => "Forces ashrain weather inside the Skýla range.", _ => "", }; } public static string GetWeatherEffect(WeatherMode mode) { return mode switch { WeatherMode.WEATHER_NONE => "No forced weather. The sky follows the normal biome.", WeatherMode.WEATHER_CLEAR => GetChimeEffect(Skyla.ChimeType.CHIME_CLEAR), WeatherMode.WEATHER_SNOW => GetChimeEffect(Skyla.ChimeType.CHIME_SNOW), WeatherMode.WEATHER_STORM => GetChimeEffect(Skyla.ChimeType.CHIME_STORM), WeatherMode.WEATHER_SNOWSTORM => GetChimeEffect(Skyla.ChimeType.CHIME_SNOWSTORM), WeatherMode.WEATHER_MISTLANDS_STORM => GetChimeEffect(Skyla.ChimeType.CHIME_MISTLANDS_STORM), WeatherMode.WEATHER_ASHRAIN => GetChimeEffect(Skyla.ChimeType.CHIME_ASHRAIN), _ => "", }; } } [HarmonyPatch(typeof(PickableItem), "Interact")] public static class PickableItem_Interact_Patch { public static bool Prefix(PickableItem __instance, Humanoid character, bool repeat, bool alt) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return false; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetBool("ProtectedPickable", false)) { return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_PICKABLE); } return true; } } internal class PickablePatch { [HarmonyPatch(typeof(Pickable), "Interact")] public static class Pickable_Interact_Patch { public static bool Prefix(Pickable __instance, Humanoid character, bool repeat, bool alt) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return false; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return true; } __instance.m_amount += component.GetZDO().GetInt("HarvestAmountOverride", __instance.m_amount); if (component.GetZDO().GetBool("ProtectedPickable", false)) { return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_PICKABLE); } return true; } } } internal class PiecePatch { [HarmonyPatch(typeof(Piece), "DropResources")] public static class Piece_DropResources_Patch { public static void Postfix(Piece __instance) { Skyla component = ((Component)__instance).GetComponent<Skyla>(); if (!((Object)(object)component == (Object)null)) { component.DropResources(); } } } [HarmonyPatch(typeof(Piece), "SetCreator")] public static class Piece_SetCreator_Patch { public static void Postfix(Piece __instance, long uid) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { Skyla component2 = ((Component)__instance).gameObject.GetComponent<Skyla>(); if (!((Object)(object)component2 == (Object)null)) { component2.OnPlaced(uid); } } } } } internal class PlantPatch { [HarmonyPatch(typeof(Plant), "Grow")] public static class Plant_Grow_Patch { public static void Postfix(Plant __instance, ref GameObject __result) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__result == (Object)null) { return; } ZNetView component = __result.GetComponent<ZNetView>(); if (!((Object)(object)__result.GetComponent<Pickable>() == (Object)null) && !((Object)(object)component == (Object)null)) { component.GetZDO().Set("ProtectedPickable", true); if (Skyla.ChimeApplies(((Component)__instance).gameObject.transform.position, Skyla.ChimeType.CHIME_FARMING) && !((double)Random.value >= 0.5)) { component.GetZDO().Set("HarvestAmountOverride", 1); } } } } [HarmonyPatch(typeof(Plant), "GetGrowTime")] public static class Plant_GetGrowTime_Patch { public static void Postfix(Plant __instance, ref float __result) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (Skyla.ChimeApplies(((Component)__instance).gameObject.transform.position, Skyla.ChimeType.CHIME_FARMING)) { __result *= 0.8f; } } } } public class PlayerPatch { [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Player_OnSpawned_Patch { public static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { LocalManager.RequestInfo(Player.m_localPlayer.GetPlayerID()); } } } [HarmonyPatch(typeof(Player), "OnRespawn")] public static class Player_OnRespawn_Patch { public static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { LocalManager.RequestInfo(Player.m_localPlayer.GetPlayerID()); } } } [HarmonyPatch(typeof(Player), "CheckCanRemovePiece")] public static class Player_CheckCanRemovePiece_Patch { public static bool Prefix(Player __instance, Piece piece) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return false; } Vagon component = ((Component)piece).gameObject.GetComponent<Vagon>(); if ((Object)(object)component != (Object)null) { return Skyla.CanUseWagon(component, (Character)(object)__instance); } Ship component2 = ((Component)piece).gameObject.GetComponent<Ship>(); if ((Object)(object)component2 != (Object)null) { return Skyla.CanUseShip(component2, (Character)(object)__instance); } Skyla component3 = ((Component)piece).gameObject.GetComponent<Skyla>(); if ((Object)(object)component3 != (Object)null) { return component3.IsPermitted((Character)(object)__instance, Skyla.ActionType.ACTION_REMOVE_SKYLA); } return Skyla.CheckAccess((Character)(object)__instance, ((Component)piece).transform.position, Skyla.ActionType.ACTION_BUILD); } } [HarmonyPatch(typeof(Player), "AutoPickup")] public static class Player_AutoPickup_Patch { public static bool Prefix(Player __instance, float dt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)__instance, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_AUTO_PICKUP); } return false; } } } public class ServerManager { private static bool s_initialized = false; private static Dictionary<long, HashSet<ZDO>> s_playerSkylaMap = new Dictionary<long, HashSet<ZDO>>(); private static Dictionary<string, float> s_playerMaxTotalArea = new Dictionary<string, float>(); private static string s_vipPlayerFileName = "skyla_area_overrides.txt"; public static void Initialize() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) List<ZDO> list = new List<ZDO>(); if (!ZNet.instance.IsServer() || s_initialized) { return; } int num = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(Skyla.s_prefabName, list, ref num)) { } foreach (ZDO item in list) { long playerID = item.GetLong("creator", 0L); if (float.IsNaN(item.GetFloat("SkylaRadius", 0f))) { Debug.Log((object)$"Skyla ServerManager :: Fixing NaN Skyla at {item.GetPosition()}"); item.Set("SkylaRadius", 0f); } ZDO ward = item; RegisterSkyla(playerID, ward); } Debug.Log((object)string.Format("SkylaManager::Initialize - found {0} {1} ZDOs", list.Count, "Skýla")); LoadSpecialPlayerList(); s_initialized = true; } public static void LoadSpecialPlayerList() { Debug.Log((object)"SkylaManager :: Loading Player Override List"); string path = Path.Combine(Paths.ConfigPath, s_vipPlayerFileName); Dictionary<string, float> dictionary = new Dictionary<string, float>(); if (!File.Exists(path)) { return; } try { string[] array = File.ReadAllLines(path); foreach (string text in array) { if (text.StartsWith("//")) { continue; } string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 2) { try { string key = array2[0]; float val = float.Parse(array2[1]); dictionary.Add(key, Math.Max(0f, val)); } catch { } } } } catch { return; } s_playerMaxTotalArea = dictionary; } public static void RegisterRPC() { ZRoutedRpc.instance.Register<ZDOID>("RegisterSkyla", (Action<long, ZDOID>)RPC_RegisterSkyla); ZRoutedRpc.instance.Register<ZDOID>("UnregisterSkyla", (Action<long, ZDOID>)RPC_UnregisterSkyla); ZRoutedRpc.instance.Register<long>("RequestInfo", (Action<long, long>)RPC_RequestInfo); } private static float GetMaxAreaForPlayer(string steamID) { if (s_playerMaxTotalArea.ContainsKey(steamID)) { return s_playerMaxTotalArea[steamID]; } return SkylaConfig.TotalAreaLimit(); } public static float GetMaxRadiusForSkylaZdo(ZDO ward) { if (ward == null) { return SkylaConfig.MaxSkylaRadius(); } long playerID = ward.GetLong("creator", 0L); float num = ward.GetFloat("SkylaRadius", 0f); float usedArea = GetUsedArea(playerID); float num2 = Mathf.Max(0f, usedArea - (float)Math.PI * num * num); float num3 = (float)Math.Sqrt((double)Mathf.Max(0f, SkylaConfig.TotalAreaLimit() - num2) / 3.1415927410125732); return Mathf.Min(SkylaConfig.MaxSkylaRadius(), num3); } private static string GetSteamIDForPeer(long sender) { ZNetPeer peer = ZNet.instance.GetPeer(sender); string text = "<unknown>"; if (peer != null) { text = peer.m_socket.GetHostName(); Debug.Log((object)("SkylaManager :: Finding SteamID for player " + peer.m_playerName + " :: got " + text)); } if (!text.StartsWith("Steam_")) { return text; } return text.Substring(6); } private static void RPC_RequestInfo(long sender, long playerID) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) long num = SkylaNet.ResolvePlayerId(sender); if (num != 0L) { playerID = num; } if (s_playerSkylaMap.ContainsKey(playerID)) { _ = s_playerSkylaMap[playerID].Count; } Initialize(); LoadSpecialPlayerList(); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "ReceiveServerSkylaData", new object[2] { GetMaxAreaForPlayer(GetSteamIDForPeer(sender)), EncodeWards(playerID) }); if (!s_playerSkylaMap.ContainsKey(playerID)) { return; } foreach (ZDO item in s_playerSkylaMap[playerID]) { ZDOMan.instance.ForceSendZDO(sender, item.m_uid); } } private static ZPackage EncodeWards(long playerID) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); if (s_playerSkylaMap.ContainsKey(playerID)) { Debug.Log((object)string.Format("SkylaManager :: Encoding data of {0} {1} for playerID {2}", s_playerSkylaMap[playerID].Count, "Skýla", playerID)); val.Write(s_playerSkylaMap[playerID].Count); foreach (ZDO item in s_playerSkylaMap[playerID]) { val.Write(item.m_uid); } } else { val.Write(0); } return val; } private static float GetUsedArea(long playerID) { float num = 0f; if (s_playerSkylaMap.ContainsKey(playerID)) { foreach (ZDO item in s_playerSkylaMap[playerID]) { float num2 = item.GetFloat("SkylaRadius", 0f); num += (float)Math.PI * num2 * num2; } } return num; } private static float GetRemainingAreaBudget(long playerID) { return SkylaConfig.TotalAreaLimit() - GetUsedArea(playerID); } private static void RegisterSkyla(long playerID, ZDO ward) { if (!s_playerSkylaMap.ContainsKey(playerID)) { s_playerSkylaMap.Add(playerID, new HashSet<ZDO>()); } s_playerSkylaMap[playerID].Add(ward); } private static void RPC_RegisterSkyla(long sender, ZDOID ward) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(ward); if (zDO != null) { long num = zDO.GetLong("creator", 0L); long num2 = SkylaNet.ResolvePlayerId(sender); if (num2 == 0L || num == 0L || num2 == num) { RegisterSkyla(num, zDO); } } } private static void UnregisterSkyla(long playerID, ZDO ward) { if (s_playerSkylaMap.ContainsKey(playerID)) { s_playerSkylaMap[playerID].Remove(ward); } } private static void RPC_UnregisterSkyla(long sender, ZDOID ward) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(ward); if (zDO != null) { long num = zDO.GetLong("creator", 0L); long num2 = SkylaNet.ResolvePlayerId(sender); if (num2 == 0L || num == 0L || num2 == num) { UnregisterSkyla(num, zDO); } } } } internal class SE_Rested_Patch { [HarmonyPatch(typeof(SE_Rested), "CalculateComfortLevel", new Type[] { typeof(bool), typeof(Vector3) })] public static class FE_Resteed_CalculateComfortLevel_Patch { public static void Postfix(bool inShelter, Vector3 position, ref int __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (Skyla.ChimeApplies(position, Skyla.ChimeType.CHIME_COMFORT)) { __result += 3; } } } } internal class ShipControlsPatch { [HarmonyPatch(typeof(ShipControlls), "Interact")] public static class ShipControlls_Interact_Patch { public static bool Prefix(ShipControlls __instance, Humanoid character, bool repeat, bool alt) { if ((Object)(object)__instance == (Object)null) { return false; } if (!IsCreator(__instance.m_ship, (Player)(object)((character is Player) ? character : null))) { return Skyla.CanUseShip(__instance.m_ship, (Character)(object)character); } return true; } } private static bool IsCreator(Ship v, Player p) { if ((Object)(object)v != (Object)null && (Object)(object)p != (Object)null) { return ((Component)v).gameObject.GetComponent<Piece>().GetCreator() == p.GetPlayerID(); } return false; } } internal class SignPatch { [HarmonyPatch(typeof(Sign), "Interact")] public static class Sign_Interact_Patch { public static bool Prefix(Sign __instance, Humanoid character, bool hold, bool alt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { return Skyla.CheckAccess((Character)(object)character, ((Component)__instance).transform.position, Skyla.ActionType.ACTION_USE_SIGN); } return false; } } } public class Skyla : MonoBehaviour, Hoverable, Interactable { public enum ActionType { ACTION_NONE, ACTION_CONTROL_SKYLA, ACTION_REMOVE_SKYLA, ACTION_DAMAGE, ACTION_BUILD, ACTION_TERRAIN_MODIFICATION, ACTION_USE_PORTAL, ACTION_USE_CONTAINER, ACTION_USE_DOOR, ACTION_USE_SIGN, ACTION_USE_ITEMSTAND, ACTION_USE_FERMENTER, ACTION_USE_BEEHIVE, ACTION_PICKUP_FACTORY_OUTPUT, ACTION_AUTO_PICKUP, ACTION_PICKABLE, ACTION_USE_SHIP, ACTION_USE_WAGON, PROTECTION_WEATHER, PROTECTION_MIST } public enum ChimeType { CHIME_FARMING = 0, CHIME_COOKING = 1, CHIME_STABILITY = 2, CHIME_COMFORT = 4, CHIME_INDUSTRY = 5, CHIME_VIGOUR = 3, CHIME_WARMTH = 6, CHIME_EMBERS = 7, CHIME_STORM = 10, CHIME_SNOW = 11, CHIME_SNOWSTORM = 12, CHIME_MISTLANDS_STORM = 13, CHIME_ASHRAIN = 14, CHIME_CLEAR = 15 } [HarmonyPatch(typeof(ZDOMan), "Load")] public class ZDOMan_Load_Patch { public static void Postfix(ZDOMan __instance) { ServerManager.Initialize(); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public class ZNetScene_Awake_Patch { public static void Postfix(ZNetScene __instance) { GameObject prefab = __instance.GetPrefab(s_prefabName); if ((Object)(object)prefab != (Object)null) { s_skylaPrefab = prefab; if ((Object)(object)prefab.GetComponent<Skyla>() == (Object)null) { prefab.AddComponent<Skyla>(); } } AddToHammer(s_skylaPrefab); } } [HarmonyPatch(typeof(ZNet), "Awake")] public static class ZNetAwakePatch { public static void Postfix(ZNet __instance) { ServerManager.RegisterRPC(); LocalManager.RegisterRPC(); } } [HarmonyPatch(typeof(ZNetScene), "Destroy")] private static class ZNetScene_Destroy_Patch { private static bool Prefix(ZNetScene __instance, GameObject go) { Skyla component = go.GetComponent<Skyla>(); if ((Object)(object)component != (Object)null) { LocalManager.RemoveSkyla(component.m_nview.GetZDO()); } return true; } } private static GameObject s_skylaPrefab; private static float s_defaultSkylaRadius = 15f; private static Skyla s_lastHovered; private static float s_lastHoveredTime; private const float c_fullLightIntensity = 3f; private const float c_fullRuneIntensity = 4.8f; private const float c_halfHeight = 50f; private const int c_pulseTimeSecs = 4; public static ISet<Skyla> s_localSkylaList = new HashSet<Skyla>(); public static string s_prefabName = "RunicSkyla"; public const string c_skylaName = "Runic Skýla"; public const string c_skylaShortName = "Skýla"; public const string c_permittedName = "Vinir"; private const string c_zdoSkylaPower = "SkylaPower"; private const string c_zdoIsActive = "IsActive"; public const string c_zdoSkylaRadius = "SkylaRadius"; public const string c_zdoPieceCreator = "creator"; public const string c_zdoProtectedItemDrop = "ProtectedItem"; public const string c_zdoProtectedPickable = "ProtectedPickable"; public const string c_zdoHarvestBonus = "HarvestAmountOverride"; public const string c_zdoChimeBitvector = "ChimesData"; public const string c_zdoWeatherMode = "WeatherMode"; private static Dictionary<ActionType, string> s_zdoAccessMap = new Dictionary<ActionType, string> { { ActionType.ACTION_USE_CONTAINER, "public_use_container" }, { ActionType.ACTION_USE_DOOR, "public_use_door" }, { ActionType.ACTION_USE_SIGN, "public_use_sign" }, { ActionType.ACTION_USE_ITEMSTAND, "public_use_itemstand" }, { ActionType.ACTION_USE_BEEHIVE, "public_use_beehive" }, { ActionType.ACTION_USE_FERMENTER, "public_use_fermenter" }, { ActionType.ACTION_PICKUP_FACTORY_OUTPUT, "public_pickup_factory" }, { ActionType.ACTION_PICKABLE, "public_pickable" }, { ActionType.ACTION_USE_SHIP, "public_use_ship" }, { ActionType.ACTION_USE_WAGON, "public_use_wagon" }, { ActionType.PROTECTION_WEATHER, "weather_protection" }, { ActionType.PROTECTION_MIST, "mist_protection" } }; public static Dictionary<ChimeType, PerkConfig.WeatherMode> s_weatherChimeMap = new Dictionary<ChimeType, PerkConfig.WeatherMode> { { ChimeType.CHIME_STORM, PerkConfig.WeatherMode.WEATHER_STORM }, { ChimeType.CHIME_SNOW, PerkConfig.WeatherMode.WEATHER_SNOW }, { ChimeType.CHIME_SNOWSTORM, PerkConfig.WeatherMode.WEATHER_SNOWSTORM }, { ChimeType.CHIME_MISTLANDS_STORM, PerkConfig.WeatherMode.WEATHER_MISTLANDS_STORM }, { ChimeType.CHIME_ASHRAIN, PerkConfig.WeatherMode.WEATHER_ASHRAIN }, { ChimeType.CHIME_CLEAR, PerkConfig.WeatherMode.WEATHER_CLEAR } }; private MeshRenderer m_model; private ZNetView m_nview; private Light m_lightSource; private Piece m_piece; private CircleProjector m_circleProjector; private DateTime m_awakeTime; public const int ActiveUtilityNone = -1; private const int ActiveUtilityUnset = -999; public float GetSkylaPower() { if (m_nview.IsValid() && IsActive()) { return m_nview.GetZDO().GetFloat("SkylaPower", 0f); } return 0f; } public float GetRadius() { if (m_nview.IsValid()) { return m_nview.GetZDO().GetFloat("SkylaRadius", 0f); } return 0f; } public void SetRadius(float radius) { if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid()) { radius = ClampRadius(radius); if (m_nview.IsOwner()) { SetRadiusLocal(radius); return; } m_nview.InvokeRPC("SetRadius", new object[1] { radius }); } } private void SetRadiusLocal(float radius) { m_nview.GetZDO().Set("SkylaRadius", radius); } private float ClampRadius(float radius) { float num = SkylaConfig.MaxSkylaRadius(); num = ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()) ? Mathf.Min(num, LocalManager.GetMaxRadiusForSkyla(this)) : Mathf.Min(num, ServerManager.GetMaxRadiusForSkylaZdo(m_nview.GetZDO()))); return Mathf.Clamp(radius, 0f, Mathf.Max(0f, num)); } private double GetDeltaTime() { DateTime time = ZNet.instance.GetTime(); DateTime dateTime = new DateTime(m_nview.GetZDO().GetLong("SkylaTime", time.Ticks)); double totalSeconds = (time - dateTime).TotalSeconds; m_nview.GetZDO().Set("SkylaTime", time.Ticks); return totalSeconds; } private void Awake() { m_awakeTime = DateTime.Now; m_piece = ((Component)this).GetComponent<Piece>(); m_lightSource = ((Component)this).GetComponent<Light>(); m_circleProjector = ((Component)this).GetComponentInChildren<CircleProjector>(); if ((Object)(object)m_circleProjector != (Object)null) { ((Component)m_circleProjector).gameObject.SetActive(false); } m_nview = ((Component)this).GetComponent<ZNetView>(); if (!m_nview.IsValid() || m_nview.GetZDO() == null) { return; } s_localSkylaList.Add(this); ((MonoBehaviour)this).InvokeRepeating("UpdateState", 0f, 1f); if (string.IsNullOrEmpty(m_nview.GetZDO().GetString("CreatorName", "")) && m_nview.IsOwner()) { Player player = Player.GetPlayer(m_piece.GetCreator()); if ((Object)(object)player != (Object)null) { m_nview.GetZDO().Set("CreatorName", player.GetPlayerName()); } } m_nview.Register("ToggleEnabled", (Action<long>)RPC_ToggleEnabled); m_nview.Register<long>("TogglePermitted", (Action<long, long>)RPC_TogglePermitted); m_nview.Register<int>("AddChime", (Action<long, int>)RPC_AddChime); m_nview.Register<float>("SetRadius", (Action<long, float>)RPC_SetRadius); m_nview.Register<int, bool>("SetPublicSetting", (Action<long, int, bool>)RPC_SetPublicSetting); m_nview.Register<int>("SetWeatherMode", (Action<long, int>)RPC_SetWeatherMode); m_nview.Register<int>("SetActiveUtilityChime", (Action<long, int>)RPC_SetActiveUtilityChime); m_nview.Register<long>("RequestSetup", (Action<long, long>)RPC_RequestSetup); m_nview.Register<bool>("RequestSetupResponse", (Action<long, bool>)RPC_RequestSetupResponse); LocalManager.AddSkyla(m_nview.GetZDO()); if (m_nview.IsOwner() && !m_nview.GetZDO().GetBool("SkylaRadiusInit", false)) { if ((double)m_nview.GetZDO().GetFloat("SkylaRadius", 0f) <= 0.0) { float maxRadiusForSkyla = LocalManager.GetMaxRadiusForSkyla(this); float num = Mathf.Min(s_defaultSkylaRadius, maxRadiusForSkyla); m_nview.GetZDO().Set("SkylaRadius", Mathf.Max(0f, num)); } m_nview.GetZDO().Set("SkylaRadiusInit", true); } if (!m_nview.IsOwner() || m_nview.GetZDO().GetBool("SkylaDefaultsInit", false)) { return; } foreach (KeyValuePair<ActionType, string> item in s_zdoAccessMap) { m_nview.GetZDO().Set(item.Value, true); } m_nview.GetZDO().Set("WeatherMode", 0); m_nview.GetZDO().Set("SkylaDefaultsInit", true); } private void OnDestroy() { s_localSkylaList.Remove(this); } private void UpdateState() { if (m_nview.IsValid() && m_nview.IsOwner()) { float num = Mathf.Clamp((float)GetDeltaTime(), 0f, 5f); if (IsActive()) { float num2 = Mathf.Min(1f, GetSkylaPower() + num / (float)SkylaConfig.PowerUpTimeSecs()); m_nview.GetZDO().Set("SkylaPower", num2); } } } private void Update() { UpdateVFX(); UpdateMarker(); } private void UpdateVFX() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_model == (Object)null) { m_model = ((Component)this).GetComponentInChildren<MeshRenderer>(); } if (!((Object)(object)m_model == (Object)null)) { Color val = Color.white * 4.8f; val.a = 1f; Color val2 = val; float num = (float)(DateTime.Now - m_awakeTime).TotalSeconds; float skylaPower = GetSkylaPower(); float num2 = 0f; if (IsActive()) { num2 = (((double)skylaPower < 1.0) ? ((float)(Math.Cos((double)num / 4.0 * Math.PI * 2.0) * 0.5 + 0.5) * skylaPower) : 1f); } ((Renderer)m_model).material.SetColor("_EmissionColor", Color.Lerp(Color.black, val2, num2)); if ((Object)(object)m_lightSource != (Object)null) { m_lightSource.intensity = 3f * num2; } } } private void UpdateMarker() { if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)m_circleProjector == (Object)null)) { float radius = GetRadius(); bool active = ((Character)Player.m_localPlayer).InPlaceMode() && m_nview.IsValid() && (double)radius > 0.0; m_circleProjector.m_radius = radius; ((Component)m_circleProjector).gameObject.SetActive(active); } } public bool IsActive() { if (m_nview.IsValid()) { return m_nview.GetZDO().GetBool("IsActive", false); } return false; } public void SetActive(bool active) { if (!m_nview.IsValid()) { return; } bool flag = m_nview.GetZDO().GetBool("IsActive", false); m_nview.GetZDO().Set("IsActive", active); if (!(!active || flag)) { if (!m_nview.GetZDO().GetBool("SkylaEverCharged", false) || !SkylaConfig.PersistChargeOnToggle()) { m_nview.GetZDO().Set("SkylaPower", 0f); } m_nview.GetZDO().Set("SkylaEverCharged", true); long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().Ticks : DateTime.Now.Ticks); m_nview.GetZDO().Set("SkylaTime", num); } } internal static Skyla GetRecentlyHovered(float maxAgeSeconds = 2.5f) { if ((Object)(object)s_lastHovered == (Object)null) { return null; } if (!((double)Time.time - (double)s_lastHoveredTime > (double)maxAgeSeconds)) { return s_lastHovered; } return null; } private List<KeyValuePair<long, string>> GetPermittedPlayers() { List<KeyValuePair<long, string>> list = new List<KeyValuePair<long, string>>(); if (!m_nview.IsValid()) { return list; } int num = m_nview.GetZDO().GetInt("permitted", 0); for (int i = 0; i < num; i++) { long num2 = m_nview.GetZDO().GetLong("pu_id" + i, 0L); string value = m_nview.GetZDO().GetString("pu_name" + i, ""); if (num2 != 0L) { list.Add(new KeyValuePair<long, string>(num2, value)); } } return list; } private void SetPermittedPlayers(List<KeyValuePair<long, string>> users) { if (m_nview.IsValid()) { m_nview.GetZDO().Set("permitted", users.Count); for (int i = 0; i < users.Count; i++) { ZDO zDO = m_nview.GetZDO(); string text = "pu_id" + i; long key = users[i].Key; zDO.Set(text, key); ZDO zDO2 = m_nview.GetZDO(); string text2 = "pu_name" + i; string value = users[i].Value; zDO2.Set(text2, value); } } } private bool IsPermitted(long playerID) { if (m_piece.GetCreator() == playerID) { return true; } foreach (KeyValuePair<long, string> permittedPlayer in GetPermittedPlayers()) { if (permittedPlayer.Key == playerID) { return true; } } return false; } private void AddPermitted(long playerID, string playerName) { List<KeyValuePair<long, string>> permittedPlayers = GetPermittedPlayers(); if (!permittedPlayers.Exists((KeyValuePair<long, string> x) => x.Key == playerID)) { permittedPlayers.Add(new KeyValuePair<long, string>(playerID, playerName)); SetPermittedPlayers(permittedPlayers); } } private void RemovePermitted(long playerID) { List<KeyValuePair<long, string>> permittedPlayers = GetPermittedPlayers(); if (permittedPlayers.RemoveAll((KeyValuePair<long, string> x) => x.Key == playerID) > 0) { SetPermittedPlayers(permittedPlayers); } } public string GetHoverName() { return "Skýla"; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid()) { return ""; } s_lastHovered = this; s_lastHoveredTime = Time.time; string text = (IsActive() ? "Deactivate" : "Activate"); string text2 = "Power: Inactive"; if (IsActive()) { float num = Mathf.Clamp01(GetSkylaPower()); TimeSpan timeSpan = TimeSpan.FromSeconds(Math.Max(0.0, (1.0 - (double)num) * (double)SkylaConfig.PowerUpTimeSecs())); string arg = ((timeSpan.TotalHours >= 1.0) ? $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m" : $"{timeSpan.Minutes}m {timeSpan.Seconds}s"); text2 = $"Power: {(float)((double)num * 100.0):0}% (full in {arg})"; } return "Runic Skýla\n" + text2 + "\n[<color=yellow>E</color>] " + text + "\n[<color=yellow>Shift+E</color>] Configure\n[<color=yellow>Ctrl+E</color>] Vinir (nearest)"; } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { long playerID = val.GetPlayerID(); if (ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true)) { if (!IsOwner(playerID)) { ((Character)user).Message((MessageType)2, "Only the Skýla creator can manage Vinir.", 0, (Sprite)null, false); return true; } Player val2 = FindNearestOtherPlayer(val, 12f); if ((Object)(object)val2 == (Object)null) { ((Character)user).Message((MessageType)2, "No nearby player to grant Vinir.", 0, (Sprite)null, false); return true; } bool flag = IsPermitted(val2.GetPlayerID()) && !IsOwner(val2.GetPlayerID()); RequestTogglePermitted(val2.GetPlayerID()); ((Character)user).Message((MessageType)2, flag ? (val2.GetPlayerName() + " is no longer Vinir.") : (val2.GetPlayerName() + " is now Vinir."), 0, (Sprite)null, false); return true; } if (alt || ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true)) { if (!IsPermitted(playerID)) { ((Character)user).Message((MessageType)2, "You are not permitted.", 0, (Sprite)null, false); return true; } GUIManager.Show(val, this); return true; } if