Please disclose if your mod was created primarily 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 ZenPortal v0.1.0
plugins/ZenPortal.dll
Decompiled 3 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using Zen; using Zen.Interop; using Zen.Lib; using Zen.Lib.Config; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ZenPortal")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ZenPortal")] [assembly: AssemblyCopyright("Copyright \ufffd 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ZenPortal { internal static class Animations { private static Incinerator IncineratorPrefab => GlobalStatic.GetPrefab<Incinerator>("incinerator", true); public static void Kneel(this Player player, float seconds, Action? onFinished = null, bool autoStand = true) { Player player2 = player; Action onFinished2 = onFinished; player2.StartEmote("Kneel".ToLowerInvariant(), true); PlayerController.SetTakeInputDelay(seconds); Timing.Delay((MonoBehaviour)(object)player2, seconds, (Action)delegate { if (Object.op_Implicit((Object)(object)player2) && autoStand) { ((Character)player2).StopEmote(); } onFinished2?.Invoke(); }); } public static void DistantThunder(this RuneStone runestone) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown Transform transform = ((Component)runestone).transform; GameObject[] array = IncineratorPrefab.m_leverEffects.Create(transform.position - transform.forward, Quaternion.identity, (Transform)null, 1f, -1); for (int i = 0; i < array.Length; i++) { foreach (Transform item in array[i].transform) { Transform val = item; string name = ((Object)val).name; if ((name == "Sparks" || name == "sfx_lever") ? true : false) { ((Component)val).gameObject.SetActive(false); } else if (((Object)val).name.StartsWith("Point light")) { ((Component)val).gameObject.SetActive(true); } } } } public static void LightningStrike(this RuneStone runestone) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown Transform transform = ((Component)runestone).transform; Vector3 val = transform.position - transform.forward * 0.5f; Quaternion identity = Quaternion.identity; foreach (Transform item in Object.Instantiate<GameObject>(IncineratorPrefab.m_lightingAOEs, val, identity).transform) { Transform val2 = item; if (((Object)val2).name.StartsWith("vfx_RockHit")) { ((Component)val2).gameObject.SetActive(true); } else if (((Object)val2).name == "AOE_ROD") { ((Component)val2).gameObject.SetActive(false); } } } } internal static class Commands { private sealed class MakeRune : TerminalCommand { public override string Name => "portalrune"; public override string Syntax => "Syntax: " + ((TerminalCommand)this).SyntaxName + " [FFFF]"; public override string Description => "Create new runestones with a given ID, or random ID if none specified. " + ((TerminalCommand)this).Syntax; public override bool IsCheat => true; public override void Exec(string[] args) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (!PlayerExt.IsReady(Player.m_localPlayer)) { Console.instance.Print("Player not ready"); return; } RuneID runeID = RuneID.Create((ushort)Random.Range(0, 65535)); if (args.Length > 1 && !RuneID.TryParse(args[1].Trim(), out runeID, logError: false)) { Console.instance.Print(((TerminalCommand)this).Syntax); return; } Transform transform = ((Component)Player.m_localPlayer).transform; runeID.SpawnItem(transform.position + transform.forward, 2); } } private sealed class CureSickness : TerminalCommand { public override string Name => "portalcure"; public override string Syntax => "Syntax: " + ((TerminalCommand)this).SyntaxName; public override string Description => "Cure the player of portal sickness " + ((TerminalCommand)this).Syntax; public override bool IsCheat => true; public override void Exec(string[] args) { if (!PlayerExt.IsReady(Player.m_localPlayer)) { Console.instance.Print("Player not ready"); } else { PortalSickness.Cure(Player.m_localPlayer); } } } private sealed class CheckRunes : TerminalCommand { public override string Name => "checkrunes"; public override string Syntax => "Syntax: " + ((TerminalCommand)this).SyntaxName; public override string Description => "Print the raw data of every rune in your inventory to the console."; public override bool IsCheat => true; public override void Exec(string[] args) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (!PlayerExt.IsReady(Player.m_localPlayer)) { Console.instance.Print("Player not ready"); return; } string sym; int allSymbols = RuneID.GetAllSymbols(out sym); Console.instance.Print($"{allSymbols} Glyphs: {sym}"); foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()) { string prefabName = ItemDataExt.GetPrefabName(allItem); if (!(prefabName != ((Object)ItemRuneShard.Prefab).name)) { string runeDataString = allItem.GetRuneDataString(); string text = $"{prefabName} ({allItem.m_gridPos}) : "; text = ((runeDataString != null) ? (text + runeDataString) : (text + "(null)")); Console.instance.Print(text); } } } } public static void Init() { ZenMod<Plugin>.Terminal.CreateCommand((TerminalCommand)(object)new MakeRune()); ZenMod<Plugin>.Terminal.CreateCommand((TerminalCommand)(object)new CureSickness()); ZenMod<Plugin>.Terminal.CreateCommand((TerminalCommand)(object)new CheckRunes()); } } internal static class Configs { public static readonly ConfigEntry<StringList> ExclusiveAllowItems; public static readonly ConfigEntry<bool> AllowSameTypeOnly; public static readonly ConfigEntry<Color> ColorRuneHoverTextLinkConnected; public static readonly ConfigEntry<Color> ColorRuneHoverTextLinkPending; public static readonly ConfigEntry<Color> ColorRuneHoverTextLinkAvailable; public static readonly ConfigEntry<Color> ColorRuneHoverTextLinkUnavailable; public static readonly ConfigEntry<Color> ColorRuneInventoryLinkAvailable; public static readonly ConfigEntry<Color> ColorRuneInventoryLinkUnavailable; public static readonly ConfigEntry<int> PortalSicknessDuration; public static readonly ConfigEntry<float> PortalSicknessSpeedAdj; public static readonly ConfigEntry<float> PortalSicknessStaminaRegen; public static readonly ConfigEntry<float> PortalSicknessHealthRegen; public static readonly ConfigEntry<float> PortalSicknessHealthPerTick; public static readonly ConfigEntry<bool> PortalSicknessPukeOnUse; public static readonly ConfigEntry<bool> PortalSicknessPukeOnEat; public static readonly ConfigEntry<bool> PortalSicknessPreventTeleport; public static readonly ConfigEntry<Biome> AllowBiomes; public static readonly ConfigEntry<int> AllowBiomesMargin; private static readonly Dictionary<Biome, ConfigEntry<int>> AllowBiomeMinAltitude; public static readonly ConfigEntry<StringList> CraftPortalWoodResources; public static readonly ConfigEntry<string> CraftPortalWoodStation; public static readonly ConfigEntry<StringList> CraftPortalStoneResources; public static readonly ConfigEntry<string> CraftPortalStoneStation; public static readonly ConfigEntry<string> FractureItem; public static readonly ConfigEntry<int> FractureItemAmount; public static readonly ConfigEntry<bool> RuneShardTeleportable; public static readonly ConfigEntry<float> RuneShardWeight; public static readonly ConfigEntry<bool> RuneShardPerPlayer; public static readonly ConfigEntry<string> FuelItemPortalWood; public static readonly ConfigEntry<string> FuelItemPortalStone; public static readonly ConfigEntry<int> FuelMax; public static int GetBiomeMinAltitude(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetBiomeMinAltitude(Heightmap.FindBiome(position)); } public static int GetBiomeMinAltitude(Biome biome) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!AllowBiomeMinAltitude.TryGetValue(biome, out ConfigEntry<int> value)) { return 0; } return value.Value; } static Configs() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Expected O, but got Unknown //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Expected O, but got Unknown //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Expected O, but got Unknown //IL_03ba: Expected O, but got Unknown //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Expected O, but got Unknown //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Expected O, but got Unknown //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Expected O, but got Unknown //IL_041e: Expected O, but got Unknown AllowBiomeMinAltitude = new Dictionary<Biome, ConfigEntry<int>>(); ColorRuneHoverTextLinkConnected = Config.Define<Color>(false, "Rune - Colors", "Rune HoverText - Link Connected", UIColor.ValheimYellow.Color, "Portal rune's color when connected to another portal."); ColorRuneHoverTextLinkPending = Config.Define<Color>(false, "Rune - Colors", "Rune HoverText - Link Pending", UIColor.Clear.Color, "Portal rune's color when pending a connection to another portal.\r\nNOTE: Clear means that it will fallback to the default color (white)"); ColorRuneHoverTextLinkAvailable = Config.Define<Color>(false, "Rune - Colors", "Rune HoverText - Link Available", UIColor.ValheimYellow.Color, "Rune color when not in use in any portals."); ColorRuneHoverTextLinkUnavailable = Config.Define<Color>(false, "Rune - Colors", "Rune HoverText - Link Unavailable", UIColor.Gray.Color, "Rune color when they are already connected to another portal somewhere in the world."); ColorRuneInventoryLinkAvailable = Config.Define<Color>(false, "Rune - Colors", "Rune Inventory - Link Available", UIColor.ValheimYellow.Color, "Inventory item rune color when not in use in any portals"); ColorRuneInventoryLinkUnavailable = Config.Define<Color>(false, "Rune - Colors", "Rune Inventory - Link Unavailable", UIColor.Gray.Color, "Inventory item rune color when in use by connected portals somewhere in the world"); ExclusiveAllowItems = Config.Define<StringList>(true, "Portal - Travel", "Exclusive Allow Items", StringList.Empty, "Exclusive list of item prefab names that are allowed to be teleported.\r\nIf any items are defined it inverts the vanilla behavior of restricting items.\r\nInstead, only allow teleporting the items listed, all others are restricted.\r\nIf you want to deny all items use the keyword: NONE (Vanilla: Leave blank)\r\n[restart required for changes to take effect]"); AllowSameTypeOnly = Config.Define<bool>(true, "Portal - Travel", "Same Type Only", true, "Wood portals can only link to other wood portals, stone to stone. (Vanilla: false)"); PortalSicknessPukeOnUse = Config.Define<bool>(true, "Portal - Sickness", "Puke On Use", true, "Vomit and lose all food after using a portal."); PortalSicknessPukeOnEat = Config.Define<bool>(true, "Portal - Sickness", "Puke On Eat", true, "If true then the player is unable to eat until portal sickness wears off.\r\nHowever, they can still drink meads and potions."); PortalSicknessPreventTeleport = Config.Define<bool>(true, "Portal - Sickness", "Prevent Teleport", false, "Can not teleport while portal sickness is in effect. \r\nIf false the portal sickness timer will be reset after each portal jump."); PortalSicknessDuration = Config.Define<int>(true, "Portal - Sickness", "Duration (Minutes)", 5, Config.AcceptRange<int>(0, 120), "Number of minutes that players will be sick after using a portal.\r\nSleep will remove the sickness instantly.\r\nSet to 0 to disable portal sickness."); PortalSicknessSpeedAdj = Config.Define<float>(true, "Portal - Sickness", "Debuff - Movement Speed", 0.8f, Config.AcceptRange<float>(0f, 1f), "Movement speed adjustment when portal sickness is in effect.\r\nSet to 1 to for normal movement speed."); PortalSicknessStaminaRegen = Config.Define<float>(true, "Portal - Sickness", "Debuff - Stamina Regen", 0.5f, Config.AcceptRange<float>(0f, 1f), "Stamina regen multiplier when portal sickness is in effect.\r\nSet to 1 for normal regen rate."); PortalSicknessHealthRegen = Config.Define<float>(true, "Portal - Sickness", "Debuff - Health Regen", 0.5f, Config.AcceptRange<float>(0f, 1f), "Health regen multiplier when portal sickness is in effect.\r\nSet to 1 to for normal regen rate."); PortalSicknessHealthPerTick = Config.Define<float>(true, "Portal - Sickness", "Debuff - Health Per Second", -0.5f, Config.AcceptRange<float>(-2f, 2f), "Health regen amount per tick when portal sickness is in effect. Negative numbers do harm.\r\nBecause you can't eat when portal sickness is in effect, you can give small hp regen here.\r\nThis will run for aproximately 10s whenever the player walks through a portal.\r\nSet to 0 to disable."); AllowBiomes = Config.Define<Biome>(true, "Build - Restrictions", "Allow Biomes", (Biome)4, "Biomes which allow portals to be built. (Vanilla: All)\r\n[restart required for changes to take effect]"); AllowBiomesMargin = Config.Define<int>(true, "Build - Restrictions", "Allow Biomes - Margin", 25, Config.AcceptRange<int>(0, 100), "Minimum distance from any disallowed biome before a portal can be built.\r\nThis prevents placing a portal just inside the edge of an allowed biome."); Dictionary<Biome, int> dictionary = new Dictionary<Biome, int> { [(Biome)1] = 0, [(Biome)8] = 0, [(Biome)2] = 0, [(Biome)4] = 150, [(Biome)16] = 0, [(Biome)512] = 0, [(Biome)32] = 0, [(Biome)64] = 0, [(Biome)256] = 0 }; foreach (Biome key in dictionary.Keys) { AllowBiomeMinAltitude[key] = Config.Define<int>(true, "Build - Restrictions", $"Min Altitude - {key}", dictionary[key], Config.AcceptRange<int>(0, 500), $"Only allow portals to be built above this altitude in the {key}."); } CraftPortalWoodStation = Config.Define<string>(true, "Build - Cost", "Portal Wood - Station", "Workbench", CraftingStations.GetAcceptableValueList(), "Crafting station required to build the wood portal"); StringList val = new StringList(); ((List<string>)val).Add("GreydwarfEye:10"); ((List<string>)val).Add("ElderBark:20"); ((List<string>)val).Add("SurtlingCore:2"); CraftPortalWoodResources = Config.Define<StringList>(true, "Build - Cost", "Portal Wood - Resources", val, "List of resources required to build a Wood Portal (Vanilla: GreydwarfEye:10, FineWood:20, SurtlingCore:2)"); CraftPortalStoneStation = Config.Define<string>(true, "Build - Cost", "Portal Stone - Station", "Stonecutter", CraftingStations.GetAcceptableValueList(), "Crafting station required to build the stone portal"); StringList val2 = new StringList(); ((List<string>)val2).Add("GreydwarfEye:10"); ((List<string>)val2).Add("Grausten:30"); ((List<string>)val2).Add("MoltenCore:2"); CraftPortalStoneResources = Config.Define<StringList>(true, "Build - Cost", "Portal Stone - Resources", val2, "List of resources required to build a Stone Portal (Vanilla: GreydwarfEye:10, Grausten:30, MoltenCore:2)"); FractureItem = Config.Define<string>(true, "Rune - Fracture", "Fracture Item", "Obsidian", "Prefab name of the item that is required to fracture runestones."); FractureItemAmount = Config.Define<int>(true, "Rune - Fracture", "Fracture Item - Amount", 2, Config.AcceptRange<int>(1, 100), "The amount of \"" + ((ConfigEntryBase)FractureItem).Definition.Key + "\" required."); RuneShardTeleportable = Config.Define<bool>(true, "Rune - Fracture", "Rune Shard - Teleportable", true, "Is the rune shard teleportable?\r\n[logout required for changes to take effect]"); RuneShardWeight = Config.Define<float>(true, "Rune - Fracture", "Rune Shard - Weight", 2f, Config.AcceptRange<float>(0.1f, 300f), "The weight of a rune shard.\r\n[logout required for changes to take effect]"); RuneShardPerPlayer = Config.Define<bool>(true, "Rune - Fracture", "Rune Shard - Per Player", true, "When this is on each runestone will create a different shard for each player.\r\nWhen this is off each runestone will create the same shard for every player."); FuelItemPortalWood = Config.Define<string>(true, "Portal - Fuel", "Wood Portal Fuel Item", "BoneFragments", "Prefab name of the fuel item for wood portals, leave blank for no fuel requirement"); FuelItemPortalStone = Config.Define<string>(true, "Portal - Fuel", "Stone Portal Fuel Item", "CharredBone", "Prefab name of the fuel item for stone portals, leave blank for no fuel requirement"); FuelMax = Config.Define<int>(true, "Portal - Fuel", "Max Fuel (Minutes)", 10, Config.AcceptRange<int>(1, 60), "Max amount of units of fuel a portal can hold."); } } [HarmonyPatch] internal static class ItemRuneShard { private const string DataRuneID = "ZenRuneID"; public const string PrefabName = "ZenRuneShard"; public static ItemDrop Prefab => GlobalStatic.GetPrefabItem("ZenRuneShard", true); public static Action AddCraftingItem() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info((object)"Add crafting item: ZenRuneShard, based on Thunderstone", 0); Sprite val = AssetIO.LoadSpriteFromResource((BaseUnityPlugin)(object)ZenMod<Plugin>.Instance, "rune_shard.png"); ItemConfig val2 = new ItemConfig(); val2.Name = "$item_rune_shard"; val2.Description = "$item_rune_shard_description"; val2.CraftingStation = CraftingStations.None; val2.MinStationLevel = 0; val2.Requirements = Array.Empty<RequirementConfig>(); val2.Icons = (Sprite[])(object)((!Object.op_Implicit((Object)(object)val)) ? null : new Sprite[1] { val }); val2.StackSize = 1; CustomItem val3 = new CustomItem("ZenRuneShard", "Thunderstone", val2); ItemManager.Instance.AddItem(val3); Transform obj = ((Component)Prefab).transform.Find("model"); ((Renderer)((Component)obj).GetComponent<MeshRenderer>()).material.SetColor("_EmissionColor", Color.red * 2f); Object.Destroy((Object)(object)((Component)obj).GetComponent<ParticleSystemRenderer>()); Object.Destroy((Object)(object)((Component)obj).GetComponent<ParticleSystem>()); Object.Destroy((Object)(object)((Component)obj.parent.GetChild(1)).gameObject); return ConfigSync; static void ConfigSync() { Prefab.m_itemData.m_shared.m_teleportable = Configs.RuneShardTeleportable.Value; Prefab.m_itemData.m_shared.m_weight = Configs.RuneShardWeight.Value; } } internal static string? GetRuneDataString(this ItemData itemData) { if (!itemData.m_customData.TryGetValue("ZenRuneID", out var value)) { return null; } return value; } public static bool TryGetRuneID(this ItemData itemData, out RuneID runeID) { runeID = default(RuneID); string runeDataString = itemData.GetRuneDataString(); if (runeDataString == null) { return false; } if (!ushort.TryParse(runeDataString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) { return false; } runeID = RuneID.Create(result); return true; } public static void SetRuneID(this ItemData itemData, RuneID runeID) { itemData.m_customData["ZenRuneID"] = runeID.ToString(); } [HarmonyPostfix] [HarmonyPatch(typeof(ItemDrop), "GetHoverText")] [HarmonyPriority(0)] private static void ItemDrop_GetHoverText(ItemDrop __instance, ref string __result) { if (__instance.m_itemData.TryGetRuneID(out var runeID)) { UIColor linkStatusColorHoverText = runeID.GetLinkStatusColorHoverText(); string hoverTextMysticSymbols = runeID.GetHoverTextMysticSymbols(linkStatusColorHoverText); if (HoverItem.IsLoaded) { HoverItem.UpdateIcons(ItemDataExt.GetIcon(__instance), hoverTextMysticSymbols); } else { __result += hoverTextMysticSymbols; } } } } [HarmonyPatch] internal static class ExclusiveAllowItems { private static bool IsNothingAllowed { get { if (((List<string>)(object)Configs.ExclusiveAllowItems.Value).Count == 1) { return ((List<string>)(object)Configs.ExclusiveAllowItems.Value)[0].ToUpperInvariant() == "NONE"; } return false; } } private static bool IsExclusive { get { if (((List<string>)(object)Configs.ExclusiveAllowItems.Value).Count <= 0) { return IsNothingAllowed; } return true; } } public static void InitItems() { if (!IsExclusive) { return; } foreach (GameObject item in ObjectDB.instance.m_items) { item.GetComponent<ItemDrop>().m_itemData.m_shared.m_teleportable = !Configs.ExclusiveAllowItems.Value.Contains(((Object)item).name, true); } } public static void UpdateTranslations(string language) { if (IsExclusive) { Localization.instance.m_translations["item_noteleport"] = StringExt.Localize("$item_teleport"); } } [HarmonyPrefix] [HarmonyPatch(typeof(Inventory), "IsTeleportable")] private static void Inventory_IsTeleportable(Inventory __instance, ref bool __result, ref bool __runOriginal) { if (!IsExclusive) { return; } __runOriginal = false; List<ItemData> inventory = __instance.m_inventory; if (inventory.Count > 0 && IsNothingAllowed) { __result = false; return; } StringList allowItems = Configs.ExclusiveAllowItems.Value; __result = inventory.All((ItemData item) => allowItems.Contains(ItemDataExt.GetPrefabName(item), true)); } [HarmonyTranspiler] [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] [HarmonyPriority(100)] private static IEnumerable<CodeInstruction> InventoryGrid_UpdateGui(IEnumerable<CodeInstruction> codes) { FieldInfo field = AccessTools.DeclaredField(typeof(SharedData), "m_teleportable"); Func<SharedData, bool> intercept = InterceptTeleportable; return Transpilers.Manipulator(codes, (Func<CodeInstruction, bool>)((CodeInstruction c) => CodeInstructionExtensions.Is(c, OpCodes.Ldfld, (MemberInfo)field)), (Action<CodeInstruction>)delegate(CodeInstruction c) { c.opcode = OpCodes.Call; c.operand = intercept.Method; }); static bool InterceptTeleportable(SharedData shared) { if (!IsExclusive) { return shared.m_teleportable; } return true; } } } [HarmonyPatch] internal static class ItemRuneShardInventoryGrid { [HarmonyTranspiler] [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] private static IEnumerable<CodeInstruction> InventoryGrid_UpdateGui(IEnumerable<CodeInstruction> codes, ILGenerator gen) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.DeclaredField(typeof(ItemData), "m_shared"), (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.DeclaredField(typeof(SharedData), "m_maxStackSize"), (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ble, (object)null, (string)null) }; MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(List<ItemData>), "GetEnumerator", (Type[])null, (Type[])null); CodeMatch[] array2 = (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldloca_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.EnumeratorMoveNext((MethodBase)methodInfo), (string)null), new CodeMatch((OpCode?)OpCodes.Brtrue, (object)null, (string)null) }; Action<ItemData, Element> action = HandleRuneShard; CodeInstruction[] array3 = (CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)18), new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)19), new CodeInstruction(OpCodes.Call, (object)action.Method) }; Label label = default(Label); return new CodeMatcher(codes, gen).MatchStartForward(array2).ThrowIfInvalid("Unable to match IL sequence: end of loop").Insert(array3) .CreateLabel(ref label) .MatchEndBackwards(array) .ThrowIfInvalid("Unable to match IL sequence: branch correction") .SetOperandAndAdvance((object)label) .InstructionEnumeration(); static void HandleRuneShard(ItemData item, Element element) { //IL_0034: 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 (!(ItemDataExt.GetPrefabName(item) != "ZenRuneShard")) { string text = "<color=red>INVALID</color>"; if (item.TryGetRuneID(out var runeID)) { UIColor linkStatusColorInventory = runeID.GetLinkStatusColorInventory(); string text2 = runeID.ToMysticSymbols(); text = ((UIColor.op_Implicit(linkStatusColorInventory) != Color.clear) ? $"<color={linkStatusColorInventory}>{text2}</color>" : text2); } ((Behaviour)element.m_amount).enabled = true; element.m_amount.text = text; } } } [HarmonyPostfix] [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })] [HarmonyPriority(100)] private static void ItemData_GetTooltip(ItemData __instance, ref string __result) { if (__instance.TryGetRuneID(out var runeID)) { string text = "<size=200%>" + runeID.ToMysticSymbols() + "</size>"; ItemDataExt.SetTooltipExtra(__instance, text); string description = __instance.m_shared.m_description; __result = __result.Replace(description, $"{description}\n\n<color={UIColor.Orange}><align=center>{text}</align></color>"); if (PlayerExt.IsGodMode(Player.m_localPlayer)) { __result += $"\n\n<color=#7F7F7FFF>Rune ID: {runeID}</color>"; } } } } [HarmonyPatch] internal static class PortalConnect { private static readonly HashSet<int> ConnectedPortalTags = new HashSet<int>(); public static bool IsTagInUse(string tag) { return ConnectedPortalTags.Contains(StringExtensionMethods.GetStableHashCode(tag)); } public static bool IsLockedTag(this string tag) { return tag.EndsWith("!"); } public static bool IsLockedTag(this string tag, out string text) { return (tag.IsLockedTag() ? (text = tag.Remove(tag.Length - 1)) : (text = null)) != null; } public static void Init() { if (!ZNet.instance.IsServer()) { ConnectedPortalTags.Clear(); } ZRoutedRpc.instance.Register<ZPackage>("RPC_ReceiveConnectedPortalTags", (Action<long, ZPackage>)RPC_ReceiveConnectedPortalTags); } public static void Shutdown() { ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_ReceiveConnectedPortalTags"); } private static void SendConnectedPortalTags(long target) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (ZNet.instance.GetPeerConnections() == 0) { Logging<Plugin>.Debug((object)"No clients connected, aborting send", 0); return; } ZPackage val = new ZPackage(); foreach (int connectedPortalTag in ConnectedPortalTags) { val.Write(connectedPortalTag); } Logging<Plugin>.Info((object)$"Sending connected portal tags to client: {target}", 0); ZRoutedRpc.instance.InvokeRoutedRPC(target, "RPC_ReceiveConnectedPortalTags", new object[1] { val }); } private static void RPC_ReceiveConnectedPortalTags(long sender, ZPackage pkg) { if (!ZNet.instance.IsServer()) { Logging<Plugin>.Info((object)"Connected portal tags received from server", 0); ConnectedPortalTags.Clear(); while (pkg.GetPos() < pkg.Size()) { ConnectedPortalTags.Add(pkg.ReadInt()); } } } [HarmonyPrefix] [HarmonyPatch(typeof(Game), "ConnectPortals")] private static void Game_ConnectPortals_Prefix(Game __instance) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) ConnectedPortalTags.Clear(); foreach (ZDO portal in ZDOMan.instance.GetPortals()) { ZDOID connectionZDOID = portal.GetConnectionZDOID((ConnectionType)1); if (!((ZDOID)(ref connectionZDOID)).IsNone()) { ConnectedPortalTags.Add(StringExtensionMethods.GetStableHashCode(portal.GetString(ZDOVars.s_tag, ""))); } } if (ZNet.instance.IsServer()) { SendConnectedPortalTags(ZRoutedRpc.Everybody); } } [HarmonyTranspiler] [HarmonyPatch(typeof(Game), "ConnectPortals")] private static IEnumerable<CodeInstruction> Game_ConnectPortals_Transpiler(IEnumerable<CodeInstruction> codes) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZDO), "GetString", new Type[2] { typeof(int), typeof(string) }, (Type[])null); Func<ZDO, int, string, string> func = GetStringIntercept; return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null) }).ThrowIfInvalid("Unable to match IL").Set(OpCodes.Call, (object)func.Method) .InstructionEnumeration(); static string? GetStringIntercept(ZDO zdo, int hash, string defaultValue) { bool num = hash == ZDOVars.s_tag; string @string = zdo.GetString(hash, defaultValue); if (num && Utility.IsNullOrWhiteSpace(@string)) { return null; } return @string; } } [HarmonyPrefix] [HarmonyPatch(typeof(Game), "FindRandomUnconnectedPortal")] [HarmonyPriority(800)] private static bool Prefix_Game_FindRandomUnconnectedPortal(string tag) { if (Utility.IsNullOrWhiteSpace(tag)) { return false; } return !IsTagInUse(tag); } [HarmonyTranspiler] [HarmonyPatch(typeof(Game), "FindRandomUnconnectedPortal")] private static IEnumerable<CodeInstruction> Transpiler_Game_FindRandomUnconnectedPortal(IEnumerable<CodeInstruction> codes) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZDO), "GetString", new Type[2] { typeof(int), typeof(string) }, (Type[])null); Func<ZDO, int, string, ZDO, string> func = GetStringIntercept; return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null) }).ThrowIfInvalid("Unable to match IL").Set(OpCodes.Call, (object)func.Method) .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_2, (object)null) }) .InstructionEnumeration(); static string? GetStringIntercept(ZDO dest, int hash, string defaultValue, ZDO source) { string @string = dest.GetString(hash, defaultValue); if (Configs.AllowSameTypeOnly.Value && !@string.IsLockedTag() && dest.GetPrefab() != source.GetPrefab()) { return null; } return @string; } } } [HarmonyPatch] internal static class Portal { public enum Types { Wood, Stone } public enum LinkStatus { Pending, Connected, Unavailable } private const string RuneTagPrefix = "ZEN:"; public static readonly (Types PortalType, TeleportWorld Portal)[] Prefabs = new(Types, TeleportWorld)[2]; public static bool IsPortal(this Component component) { return component.gameObject.IsPortal(); } public static bool IsPortal(this GameObject g) { GameObject g2 = g; return Prefabs.Any(((Types PortalType, TeleportWorld Portal) p) => ((Object)p.Portal).name == GameObjectExt.GetPrefabName(g2)); } public static bool HaveRune(this TeleportWorld teleport) { RuneID runeID; return teleport.TryGetRuneID(out runeID); } public static Types GetPortalType(this TeleportWorld teleport) { return GetPortalType(((Object)teleport).name); } public static Types GetPortalType(string name) { string name2 = name; return Prefabs.First(((Types PortalType, TeleportWorld Portal) p) => ((Object)p.Portal).name == Utils.GetPrefabName(name2)).PortalType; } public static LinkStatus GetLinkStatus(this TeleportWorld teleport) { if (!teleport.HaveTarget()) { if (!PortalConnect.IsTagInUse(teleport.GetPortalTag(includeRunes: true))) { return LinkStatus.Pending; } return LinkStatus.Unavailable; } return LinkStatus.Connected; } public static UIColor GetLinkStatusColor(this TeleportWorld teleport) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) return teleport.GetLinkStatusColor(UIColor.op_Implicit(Configs.ColorRuneHoverTextLinkConnected.Value), UIColor.op_Implicit(Configs.ColorRuneHoverTextLinkPending.Value), UIColor.op_Implicit(Configs.ColorRuneHoverTextLinkUnavailable.Value)); } public static UIColor GetLinkStatusColor(this TeleportWorld teleport, UIColor connected, UIColor pending, UIColor unavailable) { return (UIColor)(teleport.GetLinkStatus() switch { LinkStatus.Connected => connected, LinkStatus.Pending => pending, LinkStatus.Unavailable => unavailable, _ => throw new ArgumentOutOfRangeException(), }); } public static bool TryGetRuneID(this TeleportWorld teleport, out RuneID runeID) { runeID = default(RuneID); if (!Object.op_Implicit((Object)(object)teleport.m_nview) || !teleport.m_nview.IsValid()) { return false; } string @string = teleport.m_nview.GetZDO().GetString(ZDOVars.s_tag, ""); if (@string.StartsWith("ZEN:")) { return RuneID.TryParse(@string.Substring("ZEN:".Length, 4), out runeID); } return false; } public static bool TryTakeRune(this TeleportWorld teleport, Humanoid human) { ItemData rune; return teleport.TryTakeRune(human, out rune); } public static bool TryTakeRune(this TeleportWorld teleport, Humanoid human, out ItemData rune) { rune = null; if (!teleport.TryGetRuneID(out var runeID)) { return false; } GameObject gameObject = ((Component)ItemRuneShard.Prefab).gameObject; if (!InventoryExt.TryAddItem(human.GetInventory(), gameObject, 1, ref rune)) { ((Character)human).Message((MessageType)2, "$inventory_full", 0, (Sprite)null); return false; } PortalFuel portalFuel = default(PortalFuel); if (((Component)teleport).TryGetComponent<PortalFuel>(ref portalFuel)) { portalFuel.SetExpireTime(0.0); } teleport.SetText(string.Empty); rune.SetRuneID(runeID); ((Character)human).ShowPickupMessage(rune, 1); PlayInventoryFX(); return true; } public static string CreatePortalTag(RuneID runeID) { return "ZEN:" + runeID; } public static string GetPortalTag(this TeleportWorld teleport, bool includeRunes = false) { string text = default(string); string text2 = default(string); teleport.GetTagSignature(ref text, ref text2); if (!includeRunes && text.StartsWith("ZEN:")) { return string.Empty; } return text; } internal static void AssignRune(this TeleportWorld teleport, RuneID runeID) { teleport.SetText(CreatePortalTag(runeID)); teleport.PlayInteractFX(); PlayInventoryFX(); } private static void PlayInventoryFX() { FX.PlayFX((MonoBehaviour)(object)Player.m_localPlayer, "sfx_equip"); } public static void PlayInteractFX(this TeleportWorld teleport) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) EffectList removedPermittedEffect = GlobalStatic.GetPrefab<PrivateArea>("guard_stone", true).m_removedPermittedEffect; Vector3 val = (Vector3)(teleport.GetPortalType() switch { Types.Wood => ((Component)teleport).transform.position + ((Component)teleport).transform.up * 0.35f, Types.Stone => ((StaticTarget)((Component)teleport).GetComponent<Piece>()).GetCenter(), _ => ((Component)teleport).transform.position, }); Logging<Plugin>.Info((object)"Applying client-side portal effects", 0); removedPermittedEffect.Create(val, ((Component)teleport).transform.rotation, (Transform)null, 1f, -1); } [HarmonyPostfix] [HarmonyPatch(typeof(Piece), "DropResources")] private static void Piece_DropResources(Piece __instance) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) TeleportWorld val = default(TeleportWorld); if (((Component)(object)__instance).IsPortal() && ((Component)__instance).TryGetComponent<TeleportWorld>(ref val) && val.TryGetRuneID(out var runeID)) { ItemData obj = ItemRuneShard.Prefab.m_itemData.Clone(); obj.SetRuneID(runeID); Vector3 val2 = ((Component)val).transform.position + Vector3.up * 0.5f + Random.insideUnitSphere * 0.3f; Quaternion rotation = Random.rotation; ItemDrop.DropItem(obj, 0, val2, rotation); } } public static void InitPrefabs() { Prefabs[0] = (Types.Wood, GlobalStatic.GetPrefab<TeleportWorld>("portal_wood", false)); Prefabs[1] = (Types.Stone, GlobalStatic.GetPrefab<TeleportWorld>("portal_stone", false)); InitPortalPrefab(Prefabs[0].Portal, Configs.CraftPortalWoodStation.Value, Configs.CraftPortalWoodResources.Value.ToRequirements(':')); InitPortalPrefab(Prefabs[1].Portal, Configs.CraftPortalStoneStation.Value, Configs.CraftPortalStoneResources.Value.ToRequirements(':')); } private static void InitPortalPrefab(TeleportWorld prefab, string stationName, Requirement[] resources) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info((object)("Init: " + ((Object)prefab).name), 0); if (!Object.op_Implicit((Object)(object)((Component)prefab).transform.Find("ZenPortal_Fireplace_Enabled"))) { new GameObject("ZenPortal_Fireplace_Enabled").transform.SetParent(((Component)prefab).transform, false); } ((Component)prefab).gameObject.AddComponent<PortalFuel>(); Piece component = ((Component)prefab).GetComponent<Piece>(); if (resources.Length != 0) { component.m_resources = resources; } if (!Utility.IsNullOrWhiteSpace(stationName)) { component.m_craftingStation = PrefabManagerExt.GetCraftingStation(PrefabManager.Instance, stationName); } } } [HarmonyPatch] internal class PortalFuel : MonoBehaviour { public const float SecPerFuelUnit = 60f; private static readonly int ZDOVarExpireTime = StringExtensionMethods.GetStableHashCode("ZenFuelExpireTime"); private ZNetView _nview; private Portal.Types _portalType; public ItemDrop? FuelItem => (ItemDrop?)(_portalType switch { Portal.Types.Wood => GlobalStatic.GetPrefabItem(Configs.FuelItemPortalWood.Value, true), Portal.Types.Stone => GlobalStatic.GetPrefabItem(Configs.FuelItemPortalStone.Value, true), _ => null, }); private static int MaxUnits => Configs.FuelMax.Value; private double ExpireTime => ZdoExt.GetDouble(_nview.GetZDO(), ZDOVarExpireTime, 0.0); public double FuelTimeRemaining => Math.Max(0.0, ExpireTime - ZNet.instance.GetTimeSeconds()); private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _portalType = Portal.GetPortalType(((Object)this).name); } public static void Init() { RegisterGlobalRPC(); } private static void RegisterGlobalRPC() { ZRoutedRpc.instance.Register<ZDOID, double>("RPC_SetRemotePortalExpireTime", (Action<long, ZDOID, double>)RPC_SetRemotePortalExpireTime); } private static void UnregisterGlobalRPC() { ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_SetRemotePortalExpireTime"); } public static void HotRestore() { TeleportWorld[] array = Object.FindObjectsByType<TeleportWorld>((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { ((Component)array[i]).gameObject.AddComponent<PortalFuel>(); } } public static void Shutdown() { TeleportWorld[] array = Object.FindObjectsByType<TeleportWorld>((FindObjectsSortMode)0); PortalFuel portalFuel = default(PortalFuel); for (int i = 0; i < array.Length; i++) { if (((Component)array[i]).TryGetComponent<PortalFuel>(ref portalFuel)) { Object.Destroy((Object)(object)portalFuel); } } UnregisterGlobalRPC(); } public bool Interact(TeleportWorld teleport, Humanoid human) { if (!Object.op_Implicit((Object)(object)FuelItem)) { return false; } Inventory inventory = human.GetInventory(); string name = ItemDataExt.GetName(FuelItem); if (!inventory.HaveItem(name, true)) { ((Character)human).Message((MessageType)2, "$msg_donthaveany " + name, 0, (Sprite)null); return false; } if (!teleport.HaveTarget()) { ((Character)human).Message((MessageType)2, "$error_disconnected", 0, (Sprite)null); ((Character)human).Message((MessageType)1, StringExt.Localize("$portal_need", new string[1] { ItemDataExt.GetName(ItemRuneShard.Prefab) }), 0, ItemDataExt.GetIcon(ItemRuneShard.Prefab)); return false; } if (GetFuelUnits() >= MaxUnits) { ((Character)human).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null); return false; } AddFuelUnits(1); inventory.RemoveItem(ItemDataExt.GetName(FuelItem), 1, -1, true); ((Character)human).Message((MessageType)2, StringExt.Localize("$msg_throwinfire", new string[1] { ItemDataExt.GetName(FuelItem) }), 0, (Sprite)null); return true; } public void AddFuelUnits(int units) { double timeSeconds = ZNet.instance.GetTimeSeconds(); float num = (float)units * 60f; double num2 = Math.Max(0.0, ExpireTime - timeSeconds) + (double)num; SetExpireTime(timeSeconds + num2); } public int GetFuelUnits() { double fuelTimeRemaining = FuelTimeRemaining; if (!(fuelTimeRemaining <= 0.0)) { return Mathf.CeilToInt((float)(fuelTimeRemaining / 60.0)); } return 0; } public void SetExpireTime(double expireTime) { UpdateConnectedPortalFuel(expireTime); SetZDOExpireTime(_nview.GetZDO(), expireTime); PlayFuelAddFX(); } private static void SetZDOExpireTime(ZDO zdo, double expireTime) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info((object)$"Set ZDO fuel expire time {expireTime}", 0); if (!zdo.IsOwner()) { zdo.SetOwner(ZDOMan.GetSessionID()); } ZdoExt.Set(zdo, ZDOVarExpireTime, expireTime); if (expireTime == 0.0) { zdo.SetConnection((ConnectionType)1, ZDOID.None); } } public bool IsFuelEmpty() { if (Object.op_Implicit((Object)(object)FuelItem)) { return ZNet.instance.GetTimeSeconds() >= ExpireTime; } return false; } private void PlayFuelAddFX() { ((Component)this).GetComponent<TeleportWorld>().PlayInteractFX(); } private void UpdateConnectedPortalFuel(double expireTime) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) ZDOID connectionZDOID = _nview.GetZDO().GetConnectionZDOID((ConnectionType)1); if (!((ZDOID)(ref connectionZDOID)).IsNone()) { Logging<Plugin>.Info((object)"Update connected portal fuel levels to match this portal.", 0); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RPC_SetRemotePortalExpireTime", new object[2] { connectionZDOID, expireTime }); } } private static void RPC_SetRemotePortalExpireTime(long sender, ZDOID portalID, double expireTime) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(portalID); if (!zDO.IsOwner()) { return; } Logging<Plugin>.Info((object)$"Set expire time on remote portal at {zDO.GetPosition()}: {expireTime:N}", 0); SetZDOExpireTime(zDO, expireTime); if (!ZNet.instance.IsDedicated()) { GameObject val = ZNetScene.instance.FindInstance(portalID); PortalFuel portalFuel = default(PortalFuel); if (Object.op_Implicit((Object)(object)val) && val.TryGetComponent<PortalFuel>(ref portalFuel)) { portalFuel.PlayFuelAddFX(); } } } [HarmonyPostfix] [HarmonyPatch(typeof(TeleportWorld), "TargetFound")] private static void TeleportWorld_TargetFound(TeleportWorld __instance, ref bool __result) { PortalFuel portalFuel = default(PortalFuel); if (((Component)__instance).TryGetComponent<PortalFuel>(ref portalFuel)) { __result = __result && !portalFuel.IsFuelEmpty(); } } } [HarmonyPatch] internal static class PortalPlacement { private static readonly List<Heightmap> BiomeEdgesCache = new List<Heightmap>(); private static Biome _invalidEdgeBiome; private static float _altitudeDelta; private static bool IsAdminOverride { get { if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Character)Player.m_localPlayer).InGodMode()) { return ZInput.GetKey((KeyCode)308, true); } return false; } } private static void ResetState() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _invalidEdgeBiome = (Biome)0; _altitudeDelta = 0f; } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "SetPlacementGhostValid")] private static void Player_SetPlacementGhostValid(Player __instance, ref bool valid) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) ResetState(); if (!__instance.m_placementGhost.IsPortal() || (int)Configs.AllowBiomes.Value == 895 || IsAdminOverride || !valid) { return; } valid = false; Vector3 position = __instance.m_placementGhost.transform.position; Biome val = Heightmap.FindBiome(position); if (!((Enum)Configs.AllowBiomes.Value).HasFlag((Enum)(object)val)) { __instance.m_placementStatus = (PlacementStatus)8; return; } if (Configs.AllowBiomesMargin.Value > 0) { Biome value = Configs.AllowBiomes.Value; Biome val2 = ~value; BiomeEdgesCache.Clear(); Heightmap.FindHeightmap(position, (float)Configs.AllowBiomesMargin.Value, BiomeEdgesCache); foreach (Heightmap item in BiomeEdgesCache) { if (!item.HaveBiome(val2)) { continue; } Biome[] cornerBiomes = item.m_cornerBiomes; foreach (Biome val3 in cornerBiomes) { if (!((Enum)val3).HasFlag((Enum)(object)value)) { _invalidEdgeBiome = val3; __instance.m_placementStatus = (PlacementStatus)1; return; } } } } int biomeMinAltitude = Configs.GetBiomeMinAltitude(position); if (position.y < (float)biomeMinAltitude) { _altitudeDelta = (float)biomeMinAltitude - position.y; __instance.m_placementStatus = (PlacementStatus)1; } else { valid = true; } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static void TryPlacePiece(Player __instance, Piece piece) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((int)__instance.m_placementStatus != 0 && ((Component)(object)piece).IsPortal()) { if ((int)_invalidEdgeBiome != 0) { string text = "$biome_" + ((object)(Biome)(ref _invalidEdgeBiome)).ToString().ToLowerInvariant(); string text2 = StringExt.Localize("$portal_too_close", new string[1] { text }); ((Character)__instance).Message((MessageType)2, text2, 0, (Sprite)null); } else if (_altitudeDelta > 0f) { string text3 = $"$portal_altitude: {_altitudeDelta:N0}m"; ((Character)__instance).Message((MessageType)2, text3, 0, (Sprite)null); } } } } [HarmonyPatch] internal static class PortalSickness { private class SE_PortalSickness : SE_Puke { public const string Name = "SE_ZenPortal_Sickness"; public static readonly int Hash = StringExtensionMethods.GetStableHashCode("SE_ZenPortal_Sickness"); public static bool PukeOnStart = true; private SE_PortalSickness() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) ((Object)this).name = "SE_ZenPortal_Sickness"; ((StatusEffect)this).m_name = "$se_portal_sickness_name"; ((StatusEffect)this).m_tooltip = "$se_portal_sickness_tooltip"; ((StatusEffect)this).m_icon = GUIManager.Instance.GetSprite("mapicon_portal"); StatusEffect consumeStatusEffect = GlobalStatic.GetPrefabItem("Pukeberries", true).m_itemData.m_shared.m_consumeStatusEffect; ((StatusEffect)this).m_startEffects = consumeStatusEffect.m_startEffects; ((StatusEffect)this).m_startMessage = consumeStatusEffect.m_startMessage; ((StatusEffect)this).m_startMessageType = consumeStatusEffect.m_startMessageType; } public override void Setup(Character character) { ((StatusEffect)this).m_ttl = Configs.PortalSicknessDuration.Value * 60; ((SE_Stats)this).m_speedModifier = Configs.PortalSicknessSpeedAdj.Value - 1f; ((SE_Stats)this).m_staminaRegenMultiplier = Configs.PortalSicknessStaminaRegen.Value; ((SE_Stats)this).m_healthRegenMultiplier = Configs.PortalSicknessHealthRegen.Value; ((SE_Stats)this).m_healthPerTick = Configs.PortalSicknessHealthPerTick.Value; ((SE_Stats)this).m_tickInterval = 1f; ((SE_Puke)this).Setup(character); } public override void UpdateStatusEffect(float dt) { ((SE_Puke)this).UpdateStatusEffect(dt); if (!IsEnabled) { Character character = ((StatusEffect)this).m_character; Player val = (Player)(object)((character is Player) ? character : null); if (val != null) { Cure(val); return; } } if (((StatusEffect)this).m_time >= 11f) { ((SE_Stats)this).m_healthPerTick = 0f; } else if (((SE_Stats)this).m_tickTimer == 0f && ((SE_Stats)this).m_healthPerTick < 0f) { Hud.instance.DamageFlash(); } } } [HarmonyPatch] private static class TeleportUse { private static bool _isEnterPortal; [HarmonyPrefix] [HarmonyPatch(typeof(TeleportWorldTrigger), "OnTriggerEnter")] private static void TeleportWorldTrigger_OnTriggerEnter_Prefix() { _isEnterPortal = true; } [HarmonyPostfix] [HarmonyPatch(typeof(TeleportWorldTrigger), "OnTriggerEnter")] private static void TeleportWorldTrigger_OnTriggerEnter_Postfix() { _isEnterPortal = false; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "TeleportTo")] private static void Player_TeleportTo(Player __instance, bool distantTeleport, bool __result) { Player __instance2 = __instance; if (_isEnterPortal && __result && distantTeleport && ((Character)__instance2).m_nview.IsOwner()) { Timing.When((MonoBehaviour)(object)__instance2, (Func<bool>)(() => !((Character)__instance2).IsTeleporting()), (Action)delegate { Inflict(__instance2, -1f, Configs.PortalSicknessPukeOnUse.Value); }); } } } [StructLayout(LayoutKind.Auto)] [CompilerGenerated] private struct <>c__DisplayClass17_0 { public Player player; public StatusEffect sickness; } [CompilerGenerated] private sealed class <PersistSickness>d__17 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public StatusEffect sickness; private <>c__DisplayClass17_0 <>8__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PersistSickness>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = default(<>c__DisplayClass17_0); <>1__state = -2; } private bool MoveNext() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1.player = player; <>8__1.sickness = sickness; break; case 1: <>1__state = -1; break; } if (<PersistSickness>g__UpdateTimeLeft|17_0(ref <>8__1)) { <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; } if (!((Character)<>8__1.player).IsDead()) { <>8__1.player.m_customData.Remove("ZenPortalSicknessTimeLeft"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string KeyTimeLeft = "ZenPortalSicknessTimeLeft"; private static Coroutine? _persistCoroutine; private static SE_PortalSickness _sePrototype; public static bool IsEnabled => Configs.PortalSicknessDuration.Value > 0; public static bool HasPortalSickness(this Character c) { return c.GetSEMan().HaveStatusEffect(SE_PortalSickness.Hash); } public static void Init() { _persistCoroutine = null; _sePrototype = ScriptableObject.CreateInstance<SE_PortalSickness>(); ObjectDB.instance.m_StatusEffects.Add((StatusEffect)(object)_sePrototype); } public static void Shutdown() { Player.m_localPlayer.StopPersistSickness(); if (Object.op_Implicit((Object)(object)ObjectDB.instance) && Object.op_Implicit((Object)(object)_sePrototype)) { ObjectDB.instance.m_StatusEffects.Remove((StatusEffect)(object)_sePrototype); Object.Destroy((Object)(object)_sePrototype); } } public static void HotRestore() { if (((Character)(object)Player.m_localPlayer).HasPortalSickness()) { StatusEffect statusEffect = ((Character)Player.m_localPlayer).GetSEMan().GetStatusEffect(SE_PortalSickness.Hash); Player.m_localPlayer.StartPersistSickness(statusEffect); } } [HarmonyPostfix] [HarmonyPatch(typeof(Game), "SpawnPlayer")] private static void Game_SpawnPlayer(Player __result) { CheckRestoreSickness(__result); } private static void CheckRestoreSickness(Player player) { if (!IsEnabled) { return; } Logging<Plugin>.Info((object)"Checking if sickness needs to be restored", 0); if (((Character)(object)player).HasPortalSickness()) { Logging<Plugin>.Info((object)"Already have portal sickness", 0); return; } if (!player.m_customData.TryGetValue("ZenPortalSicknessTimeLeft", out var value)) { Logging<Plugin>.Info((object)"No persistant sickness key found, nothing to restore.", 0); return; } float num = float.Parse(value); if (num > 0f) { Inflict(player, num, puke: false); } else { Logging<Plugin>.Info((object)"Time remaining 0, nothing to restore", 0); } } public static void Cure(Player player) { Logging<Plugin>.Info((object)"Portal sickness cured!", 0); ((Character)player).GetSEMan().RemoveStatusEffect(((StatusEffect)_sePrototype).NameHash(), false); player.m_customData.Remove("ZenPortalSicknessTimeLeft"); } public static void Inflict(Player player, float timeLeft = -1f, bool puke = true) { if (IsEnabled) { if (PlayerExt.IsGodMode(player)) { Logging<Plugin>.Message((object)"God mode active, no portal sickness applied.", 0); return; } Logging<Plugin>.Info((object)$"Applying portal sickness... puke? {puke}", 0); SEMan sEMan = ((Character)player).GetSEMan(); sEMan.RemoveStatusEffect((StatusEffect)(object)_sePrototype, true); SE_PortalSickness.PukeOnStart = puke; SE_PortalSickness sE_PortalSickness = (SE_PortalSickness)(object)sEMan.AddStatusEffect((StatusEffect)(object)_sePrototype, false, 0, 0f); SE_PortalSickness.PukeOnStart = true; ((StatusEffect)sE_PortalSickness).m_ttl = Configs.PortalSicknessDuration.Value * 60; ((StatusEffect)sE_PortalSickness).m_time = ((timeLeft < 0f) ? 0f : Mathf.Max(0f, ((StatusEffect)sE_PortalSickness).m_ttl - timeLeft)); player.StartPersistSickness((StatusEffect)(object)sE_PortalSickness); } } public static void Puke(this Player player) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info((object)"Puking...", 0); ((Character)player).Message(((StatusEffect)_sePrototype).m_startMessageType, ((StatusEffect)_sePrototype).m_startMessage, 0, (Sprite)null); ((StatusEffect)_sePrototype).m_character = (Character)(object)player; ((StatusEffect)_sePrototype).TriggerStartEffects(); } private static void StartPersistSickness(this Player player, StatusEffect sickness) { player.StopPersistSickness(); _persistCoroutine = ((MonoBehaviour)player).StartCoroutine(PersistSickness(player, sickness)); } private static void StopPersistSickness(this Player player) { if (Object.op_Implicit((Object)(object)player) && _persistCoroutine != null) { ((MonoBehaviour)player).StopCoroutine(_persistCoroutine); } _persistCoroutine = null; } [IteratorStateMachine(typeof(<PersistSickness>d__17))] private static IEnumerator PersistSickness(Player player, StatusEffect sickness) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PersistSickness>d__17(0) { player = player, sickness = sickness }; } [HarmonyPrefix] [HarmonyPatch(typeof(StatusEffect), "TriggerStartEffects")] private static void StatusEffect_TriggerStartEffects(StatusEffect __instance, ref bool __runOriginal) { if (!(__instance is SE_PortalSickness)) { return; } bool flag = (__runOriginal = SE_PortalSickness.PukeOnStart); Logging<Plugin>.Info((object)$"Triggering puke FX? {flag}", 0); if (!flag) { return; } Character character = __instance.m_character; Player player = (Player)(object)((character is Player) ? character : null); if (player != null) { Timing.Delay((MonoBehaviour)(object)player, 2.5f, (Action)delegate { player.Kneel(10f, null, autoStand: false); }); } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "EatFood")] private static void Player_EatFood(Player __instance, ItemData item, bool __result) { if (Configs.PortalSicknessPukeOnEat.Value && __result && !Object.op_Implicit((Object)(object)item.m_shared.m_consumeStatusEffect) && ((Character)(object)__instance).HasPortalSickness()) { __instance.Puke(); } } [HarmonyPostfix] [HarmonyPatch(typeof(Humanoid), "IsTeleportable")] [HarmonyPriority(100)] private static void Humanoid_IsTeleportable(Humanoid __instance, ref bool __result) { if (Configs.PortalSicknessPreventTeleport.Value) { __result = __result && !((Character)(object)__instance).HasPortalSickness(); } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "SetSleeping")] private static void Player_SetSleeping(Player __instance, bool sleep) { if (sleep) { Cure(__instance); } } [CompilerGenerated] internal static bool <PersistSickness>g__UpdateTimeLeft|17_0(ref <>c__DisplayClass17_0 P_0) { if (!IsEnabled) { return false; } if (!((Character)(object)P_0.player).HasPortalSickness()) { return false; } float num = Mathf.Max(0f, P_0.sickness.GetRemaningTime()); if (num <= 0f) { return false; } Logging<Plugin>.Info((object)$"Persist portal sickness seconds remaining: {num:N}", 0); P_0.player.m_customData["ZenPortalSicknessTimeLeft"] = num.ToString("R"); return true; } } [HarmonyPatch] internal static class PortalUI { private const string HiddenTagPrefix = "."; private static bool IsAdminOverride { get { if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Character)Player.m_localPlayer).InGodMode()) { return ZInput.GetKey((KeyCode)308, true); } return false; } } [HarmonyPostfix] [HarmonyPatch(typeof(TeleportWorld), "GetHoverName")] private static void TeleportWorld_GetHoverName(ref string __result) { __result = "$piece_portal"; } [HarmonyPostfix] [HarmonyPatch(typeof(TeleportWorld), "GetHoverText")] private static void TeleportWorld_GetHoverText(TeleportWorld __instance, ref string __result) { PortalFuel portalFuel = default(PortalFuel); if (!((Component)__instance).TryGetComponent<PortalFuel>(ref portalFuel)) { return; } double fuelTimeRemaining = portalFuel.FuelTimeRemaining; Logging<Plugin>.Debug((object)$"Fuel time remaining: {fuelTimeRemaining}", 0); string arg = UI.RemainingTimeText(fuelTimeRemaining, 60f); string text = ((fuelTimeRemaining > 1.0) ? $"\n<color={UIColor.MinorInfo}>{arg}</color>" : string.Empty); ItemDrop? fuelItem = portalFuel.FuelItem; string text2 = (IsAdminOverride ? "$piece_portal_settag" : "$portal_add_fuel"); string text3 = (Object.op_Implicit((Object)(object)fuelItem) ? ("\n" + UI.PromptInteract + " " + text2) : string.Empty); string text4 = __instance.GetPortalTag(); string text5 = "\n" + UI.PromptInteractAlt + " $hud_remove"; bool flag = true; if (!__instance.TryGetRuneID(out var runeID)) { text5 = (__instance.TargetFound() ? string.Empty : ("\n" + UI.PromptUseItem + " $piece_useitem")); flag = false; } if (!WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, false) || text4.IsLockedTag()) { text5 = string.Empty; } bool flag2 = false; if (text4.StartsWith(".")) { flag2 = true; text4 = text4.Substring(1); } if (text4.IsLockedTag(out string text6)) { text4 = text6; } string text7 = ((!flag2 && !Utility.IsNullOrWhiteSpace(text4)) ? (" - " + text4) : string.Empty); string text8 = __instance.GetHoverName() + text7 + text3 + text5 + text; if (flag) { UIColor linkStatusColor = __instance.GetLinkStatusColor(); string hoverTextMysticSymbols = runeID.GetHoverTextMysticSymbols(linkStatusColor); HoverItem.UpdateIcons(ItemDataExt.GetIcon(ItemRuneShard.Prefab), hoverTextMysticSymbols); if (!HoverItem.IsLoaded) { text8 += hoverTextMysticSymbols; } } __result = Localization.instance.Localize(text8); } [HarmonyPrefix] [HarmonyPatch(typeof(TeleportWorld), "UseItem")] private static void TeleportWorld_UseItem(TeleportWorld __instance, Humanoid user, ItemData item, ref bool __runOriginal, ref bool __result) { __runOriginal = false; __result = false; if (ItemDataExt.GetPrefabName(item) != "ZenRuneShard" || !WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, true)) { return; } RuneID runeID; if (__instance.GetPortalTag().IsLockedTag()) { Logging<Plugin>.Message((object)"Admin only portal, can not change via rune interaction", 0); ((Character)user).Message((MessageType)1, "$msg_nobuildzone", 0, ((Component)__instance).GetComponent<Piece>().m_icon); } else if (item.TryGetRuneID(out runeID)) { if (__instance.TryGetRuneID(out var runeID2)) { item.SetRuneID(runeID2); } else if (!user.GetInventory().RemoveOneItem(item)) { return; } __instance.AssignRune(runeID); __result = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(TeleportWorld), "Interact")] private static void TeleportWorld_Interact(TeleportWorld __instance, Humanoid human, bool hold, bool alt, ref bool __result, ref bool __runOriginal) { PortalFuel portalFuel = default(PortalFuel); if (((Component)__instance).TryGetComponent<PortalFuel>(ref portalFuel) && !IsAdminOverride) { __runOriginal = false; if (alt && WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, true)) { __result = __instance.TryTakeRune(human); } else { __result = !alt && portalFuel.Interact(__instance, human); } } } } [BepInPlugin("ZenDragon.ZenPortal", "ZenPortal", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class Plugin : ZenMod<Plugin> { public const string PluginName = "ZenPortal"; public const string PluginVersion = "0.1.0"; public const string PluginGUID = "ZenDragon.ZenPortal"; protected override void Setup() { ((ZenMod)this).RunOnServer = true; base.LanguageChanged += PortalDescription.Init; base.LanguageChanged += ExclusiveAllowItems.UpdateTranslations; base.RegisterCraftingItems += ItemRuneShard.AddCraftingItem; base.ConfigSync += Portal.InitPrefabs; base.ConfigSync += ExclusiveAllowItems.InitItems; RuneID.ValidateSymbols(); Commands.Init(); } protected override void TitleScene(bool isFirstBoot) { } protected override void WorldStart() { PortalFuel.Init(); PortalConnect.Init(); PortalSickness.Init(); } protected override void Shutdown() { PortalFuel.Shutdown(); PortalDescription.Shutdown(); PortalConnect.Shutdown(); PortalSickness.Shutdown(); } protected override void HotRestore() { if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { Portal.InitPrefabs(); PortalSickness.HotRestore(); PortalFuel.HotRestore(); } } } internal static class PortalDescription { private const string WoodID = "piece_portal_description"; private const string StoneID = "piece_portal_stone_description"; private static readonly Dictionary<string, (string Wood, string Stone)> OriginalTranslations = new Dictionary<string, (string, string)>(); internal static void Init(string language) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 Dictionary<string, string> translations = Localization.instance.m_translations; if (!OriginalTranslations.TryGetValue(language, out (string, string) value)) { (string, string) tuple2 = (OriginalTranslations[language] = (translations["piece_portal_description"], translations["piece_portal_stone_description"])); value = tuple2; } if ((int)Configs.AllowBiomes.Value != 895) { string text = string.Join(", ", from Biome biome in Enum.GetValues(typeof(Biome)) where ((Enum)Configs.AllowBiomes.Value).HasFlag((Enum)(object)biome) && (int)biome > 0 select StringExt.Localize($"$biome_{biome}".ToLowerInvariant())); string text2 = ((text.Count((char c) => c == ',') > 2) ? string.Empty : StringExt.Localize("\n$portal_need", new string[1] { text })); translations["piece_portal_description"] = (value.Item1 + text2).Trim(); translations["piece_portal_stone_description"] = (value.Item2 + text2).Trim(); } } public static void Shutdown() { string @string = PlatformPrefs.GetString("language", ""); if (OriginalTranslations.TryGetValue(@string, out (string, string) value)) { Localization.instance.m_translations["piece_portal_description"] = value.Item1; Localization.instance.m_translations["piece_portal_stone_description"] = value.Item2; } } } internal readonly struct RuneID : IEquatable<RuneID> { private static readonly string[] Symbols = new string[41] { "⚡", "◑", "●", "◐", "\ud83c\udf19", "\ud83c\udf00", "\ud83d\udcdc", "\ud83c\udf38", "\ud83d\udc1f\ufe0e", "⚔", "✨", "\ud83c\udf44", "♂", "♀", "\ud83c\udf32", "☀", "\ud83d\udd78", "\ud83d\udc3a", "\ud83d\udc51", "❤", "\ud83d\udd25", "➰", "\ud83d\udcab", "\ud83d\udca5", "\ud83c\udff9", "\ud83d\udc41", "\ud83d\udee1", "\ud83d\udc80", "☯", "\ud83d\udde1", "⚓\ufe0e", "\ud83e\ude93", "⛏", "⭐", "\ud83e\udd8b", "✳", "\ud83d\udca7", "\ud83d\udc8e", "\ud83d\uddff", "\ud83e\uddff", "\ud83d\udddd" }; private const int MaxIconSymbols = 3; private static readonly int MaxSymbolValue = (int)Math.Pow(Symbols.Length, 3.0) - 1; private readonly ushort _id; public bool IsInUse => PortalConnect.IsTagInUse(Portal.CreatePortalTag(this)); public static int GetAllSymbols(out string sym) { sym = string.Join(string.Empty, Symbols); return Symbols.Length; } private RuneID(ushort id) { _id = id; } public UIColor GetLinkStatusColor(UIColor avail, UIColor inUse) { if (!IsInUse) { return avail; } return inUse; } public UIColor GetLinkStatusColorInventory() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return GetLinkStatusColor(UIColor.op_Implicit(Configs.ColorRuneInventoryLinkAvailable.Value), UIColor.op_Implicit(Configs.ColorRuneInventoryLinkUnavailable.Value)); } public UIColor GetLinkStatusColorHoverText() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return GetLinkStatusColor(UIColor.op_Implicit(Configs.ColorRuneHoverTextLinkAvailable.Value), UIColor.op_Implicit(Configs.ColorRuneHoverTextLinkUnavailable.Value)); } public bool Equals(RuneID other) { return _id == other._id; } public override bool Equals(object? obj) { if (obj is RuneID other) { return Equals(other); } return false; } public override int GetHashCode() { ushort id = _id; return id.GetHashCode(); } public override string ToString() { ushort id = _id; return id.ToString("X4"); } public static explicit operator ushort(RuneID runeID) { return runeID._id; } internal static void ValidateSymbols() { if (MaxSymbolValue < 65535) { throw new Exception($"Not enough symbols to map safely across all values [0000-FFFF] with {3} characters and {Symbols.Length} symbols"); } HashSet<string> hashSet = new HashSet<string>(); string[] symbols = Symbols; foreach (string text in symbols) { if (!hashSet.Add(text)) { throw new Exception("Duplicate symbol found in table: " + text); } } Logging<Plugin>.Info((object)$"Unique symbols: {hashSet.Count}", 0); } public string ToMysticSymbols() { string[] array = new string[3]; int num = _id; for (int i = 0; i < array.Length; i++) { int num2 = num % Symbols.Length; array[i] = Symbols[num2]; num /= Symbols.Length; } if (num > 0) { Logging<Plugin>.Error((object)$"ID overflow in base-{Symbols.Length} encoding", (ushort)0); } return string.Join(string.Empty, array); } public static RuneID Create(ushort id) { return new RuneID(id); } public static RuneID Create(byte zoneX, byte zoneY, long playerID) { ushort num = (ushort)((zoneX << 8) | zoneY); if (Configs.RuneShardPerPlayer.Value) { num ^= (ushort)playerID; } return Create(num); } public static bool TryParse(string hex, out RuneID runeID, bool logError = true) { if (ushort.TryParse(hex, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result)) { runeID = Create(result); return true; } if (logError) { Logging<Plugin>.Error((object)("Unable to parse string: " + hex + ", expected ushort hex value."), (ushort)0); } runeID = default(RuneID); return false; } public string GetHoverTextMysticSymbols(UIColor color) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) string text = "<size=135%>" + ToMysticSymbols() + "</size>"; string text2 = "\n\n" + ((UIColor.op_Implicit(color) == Color.clear) ? text : $"<color={color}>{text}</color>"); if (PlayerExt.IsGodMode(Player.m_localPlayer) && ZInput.GetKey((KeyCode)308, true)) { text2 += $"\n\nRune ID: {this}"; } return text2; } public ItemDrop[] SpawnItem(Vector3 origin, int amount, bool autoPickup = false) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) ItemDrop[] array = (ItemDrop[])(object)new ItemDrop[amount]; for (int i = 0; i < amount; i++) { ItemData obj = ItemRuneShard.Prefab.m_itemData.Clone(); obj.SetRuneID(this); Vector3 val = origin + Vector3.up + Random.insideUnitSphere * 0.3f; Quaternion val2 = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); ItemDrop val3 = ItemDrop.DropItem(obj, 1, val, val2); val3.m_autoPickup = autoPickup; array[i] = val3; } return array; } } [HarmonyPatch] internal static class RuneStoneUI { private const string SFX_PlaceItem = "sfx_build_hammer_stone"; private static ItemDrop? FractureItemPrefab => GlobalStatic.GetPrefabItem(Configs.FractureItem.Value, true); private static bool IsInteractCooldownExpired(this RuneStone runestone) { return ZNet.instance.GetTimeSeconds() > runestone.GetLastUseTime() + 12.0; } private static bool IsValid(this RuneStone runestone) { if (!Object.op_Implicit((Object)(object)((Component)runestone).transform.parent)) { return false; } string prefabName = Utils.GetPrefabName(((Object)((Component)runestone).transform.parent).name); if (!prefabName.StartsWith("Runestone_") && !prefabName.StartsWith("RuneStone_") && !prefabName.EndsWith("Lorestone")) { return prefabName.EndsWith("LoreStone"); } return true; } private static void FractureShard(this RuneStone? runestone) { if (Object.op_Implicit((Object)(object)runestone)) { runestone.LightningStrike(); runestone.CreateShards(2); } } private static void CreateShards(this RuneStone runestone, int amount) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) RuneID runeID = runestone.GetRuneID(Player.m_localPlayer); Transform transform = ((Component)runestone).transform; runeID.SpawnItem(transform.position - transform.forward, amount); } private static bool PlaceItem(this RuneStone runestone) { RuneStone runestone2 = runestone; if (!Object.op_Implicit((Object)(object)FractureItemPrefab)) { Logging<Plugin>.Info((object)"No Fracture Item defined", 0); return false; } Player player = Player.m_localPlayer; string itemName = ItemDataExt.GetName(FractureItemPrefab); if (((Humanoid)player).GetInventory().CountItems(itemName, -1, true) < Configs.FractureItemAmount.Value) { ((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null); return false; } if (!runestone2.SetLastUsedTime()) { return false; } player.Kneel(2f, delegate { if (PlayerExt.IsReady(player)) { ((Humanoid)player).GetInventory().RemoveItem(itemName, Configs.FractureItemAmount.Value, -1, true); ((Character)player).ShowRemovedMessage(FractureItemPrefab.m_itemData, Configs.FractureItemAmount.Value); FX.PlayFX((MonoBehaviour)(object)player, "sfx_build_hammer_stone"); runestone2.DistantThunder(); Timing.Delay((MonoBehaviour)(object)runestone2, 4.5f, (Action)runestone2.FractureShard); } }); return true; } private static bool SetLastUsedTime(this RuneStone runestone) { ZNetView zNetView = runestone.GetZNetView(); if (!Object.op_Implicit((Object)(object)zNetView)) { return false; } zNetView.ClaimOwnership(); ZdoExt.Set(zNetView.GetZDO(), ZDOVars.s_lastTime, ZNet.instance.GetTimeSeconds()); return true; } private static double GetLastUseTime(this RuneStone runestone) { ZNetView zNetView = runestone.GetZNetView(); if (!Object.op_Implicit((Object)(object)zNetView)) { return 0.0; } return ZdoExt.GetDouble(zNetView.GetZDO(), ZDOVars.s_lastTime, 0.0); } private static ZNetView? GetZNetView(this RuneStone runestone) { ZNetView componentInParent = ((Component)runestone).GetComponentInParent<ZNetView>(); if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.IsValid()) { return componentInParent; } Logging<Plugin>.Error((object)"ZNetView missing or invalid", (ushort)0); return null; } private static RuneID GetRuneID(this RuneStone runestone, Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Vector2i zone = ZoneSystem.GetZone(((Component)runestone).transform.position); return RuneID.Create((byte)zone.x, (byte)zone.y, player.GetPlayerID()); } [HarmonyPostfix] [HarmonyPatch(typeof(RuneStone), "GetHoverText")] private static void RuneStone_GetHoverText(RuneStone __instance, ref string __result) { if (!__instance.IsValid()) { return; } if (((Character)Player.m_localPlayer).InEmote() || !__instance.IsInteractCooldownExpired()) { __result = string.Empty; } else if (Object.op_Implicit((Object)(object)FractureItemPrefab)) { int value = Configs.FractureItemAmount.Value; string text = ((value > 1) ? $" x{value}" : string.Empty); __result += StringExt.Localize("\n" + UI.PromptInteractAlt + " $piece_use " + ItemDataExt.GetName(FractureItemPrefab) + text); RuneID runeID = __instance.GetRuneID(Player.m_localPlayer); UIColor linkStatusColorHoverText = runeID.GetLinkStatusColorHoverText(); string hoverTextMysticSymbols = runeID.GetHoverTextMysticSymbols(linkStatusColorHoverText); if (HoverItem.IsLoaded) { HoverItem.UpdateIcons(ItemDataExt.GetIcon(ItemRuneShard.Prefab), hoverTextMysticSymbols); } else { __result += hoverTextMysticSymbols; } } } [HarmonyPrefix] [HarmonyPatch(typeof(RuneStone), "UseItem")] [HarmonyPriority(800)] private static void RuneStone_UseItem(RuneStone __instance, Humanoid user, ItemData item, ref bool __result, ref bool __runOriginal) { if (__instance.IsValid() && Object.op_Implicit((Object)(object)FractureItemPrefab) && !(ItemDataExt.GetPrefabName(item) != ((Object)FractureItemPrefab).name)) { __runOriginal = false; __result = __instance.Interact(user, false, true); } } [HarmonyPrefix] [HarmonyPatch(typeof(RuneStone), "Interact")] private static void RuneStone_Interact(RuneStone __instance, Humanoid character, bool alt, bool hold, ref bool __result, ref bool __runOriginal) { if (__instance.IsValid() && PlayerExt.Is(Player.m_localPlayer, (Character)(object)character) && !(!alt || hold) && Object.op_Implicit((Object)(object)FractureItemPrefab)) { __runOriginal = false; if (__instance.IsInteractCooldownExpired()) { __result = __instance.PlaceItem(); } } } } } namespace ZenPortal.VanillaFix { [HarmonyPatch] internal static class FixPlayerControllerTakeInput { [HarmonyPostfix] [HarmonyPatch(typeof(PlayerController), "TakeInput")] private static void PlayerController_TakeInput(PlayerController __instance, bool look, ref bool __result) { if (__result) { __result = look || PlayerController.takeInputDelay <= 0f; } } } }