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 Valhalla Duels v0.3.7
plugins/ValhallaDuels/ValhallaDuels.dll
Decompiled 6 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; 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 UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ValhallaDuels")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.7.0")] [assembly: AssemblyInformationalVersion("0.3.7")] [assembly: AssemblyProduct("ValhallaDuels")] [assembly: AssemblyTitle("ValhallaDuels")] [assembly: AssemblyVersion("0.3.7.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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ValhallaDuels { public sealed class ArenaPole : MonoBehaviour, Hoverable, Interactable { internal static readonly HashSet<ArenaPole> Loaded = new HashSet<ArenaPole>(); public string DisplayName = "Arena flag"; private ZNetView view; private LineRenderer? boundary; private float showUntil; private float drawnRadius; private Vector3 drawnPosition; private static Material? ringMaterial; private SpawnPreview? spawnPreview; internal bool Valid { get { if (Object.op_Implicit((Object)(object)this) && ((Behaviour)this).isActiveAndEnabled && Object.op_Implicit((Object)(object)view) && view.IsValid()) { return PolePrefabs.IsPole(view.GetZDO().GetPrefab()); } return false; } } internal ZDOID Id => view.GetZDO().m_uid; private static string WorldKey => ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture); internal static string SelectionKey => "ValhallaDuels.pole." + WorldKey; private void LateUpdate() { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Plugin.Ready && Plugin.ModEnabled.Value && (SpawnPreview.IsPlacementGhost(localPlayer, ((Component)this).gameObject) || (Valid && Time.unscaledTime < showUntil))) { (spawnPreview ?? (spawnPreview = new SpawnPreview())).Draw(this, localPlayer); } else { spawnPreview?.Hide(); } } private void OnDisable() { spawnPreview?.Hide(); } private void Awake() { view = ((Component)this).GetComponent<ZNetView>(); } private void Start() { view = ((Component)this).GetComponent<ZNetView>(); Loaded.Add(this); } private void OnDestroy() { Loaded.Remove(this); spawnPreview?.Destroy(); } internal bool Covers(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) Vector3 val = position - ((Component)this).transform.position; if (Valid) { return DeathPolicy.Inside(val.x, val.y, val.z, Plugin.ArenaRadius.Value); } return false; } internal static ArenaPole? Covering(Vector3 position) { //IL_0026: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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) ArenaPole result = null; float num = float.PositiveInfinity; foreach (ArenaPole item in Loaded) { if (Object.op_Implicit((Object)(object)item) && item.Covers(position)) { Vector3 val = ((Component)item).transform.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude >= num)) { num = sqrMagnitude; result = item; } } } return result; } internal static bool IsProtected(Player player) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)player)) { return DeathPolicy.Protect(Plugin.Ready && Plugin.ModEnabled.Value, (Object)(object)player == (Object)(object)Player.m_localPlayer, ((Character)player).IsPVPEnabled(), (Object)(object)Covering(((Component)player).transform.position) != (Object)null); } return false; } internal static bool TrySelected(Player player, out ZDOID id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) id = ZDOID.None; if (!Object.op_Implicit((Object)(object)ZNet.instance) || !MigrationData.ReadSelection(player.m_customData, WorldKey, out string value)) { return false; } string[] array = value.Split(':'); if (array.Length != 2 || !long.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !uint.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { return false; } id = new ZDOID(result, result2); return !((ZDOID)(ref id)).IsNone(); } public string GetHoverName() { return DisplayName; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!Valid) { return DisplayName; } showUntil = Time.unscaledTime + 2f; if (!Plugin.Ready || !Plugin.ModEnabled.Value) { return DisplayName + "\nDisabled"; } ZDOID id; bool flag = Object.op_Implicit((Object)(object)Player.m_localPlayer) && TrySelected(Player.m_localPlayer, out id) && id == Id; return Localization.instance.Localize(DisplayName + (flag ? " <color=#e8c56b>✓</color>" : "") + "\n[<color=yellow><b>$KEY_Use</b></color>] Set respawn\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Clear respawn"); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00d3: Unknown result type (might be due to invalid IL or missing references) if (!hold && Valid && Plugin.Ready && Plugin.ModEnabled.Value) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (alt) { MigrationData.ClearSelection(val.m_customData, WorldKey); ((Character)val).Message((MessageType)2, "Respawn cleared", 0, (Sprite)null, false); return true; } if (!SafeSpawn.TryFind(this, out var _, val)) { ((Character)val).Message((MessageType)2, "Spawn blocked", 0, (Sprite)null, false); return false; } MigrationData.ClearSelection(val.m_customData, WorldKey); Dictionary<string, string> customData = val.m_customData; string selectionKey = SelectionKey; ZDOID id = Id; string text = ((ZDOID)(ref id)).UserID.ToString(CultureInfo.InvariantCulture); id = Id; customData[selectionKey] = text + ":" + ((ZDOID)(ref id)).ID.ToString(CultureInfo.InvariantCulture); showUntil = Time.unscaledTime + 8f; ((Character)val).Message((MessageType)2, "Respawn set", 0, (Sprite)null, false); return true; } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } private void Update() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Plugin.Ready || !Plugin.ModEnabled.Value || ((!Valid || !(Time.unscaledTime < showUntil)) && !SpawnPreview.IsPlacementGhost(localPlayer, ((Component)this).gameObject))) { if (Object.op_Implicit((Object)(object)boundary)) { ((Renderer)boundary).enabled = false; } return; } if (!Object.op_Implicit((Object)(object)boundary)) { GameObject val = new GameObject("Arena radius preview"); val.transform.SetParent(((Component)this).transform, false); boundary = val.AddComponent<LineRenderer>(); if (!Object.op_Implicit((Object)(object)ringMaterial)) { ringMaterial = new Material(Shader.Find("Sprites/Default")); } ((Renderer)boundary).sharedMaterial = ringMaterial; boundary.useWorldSpace = true; boundary.loop = true; boundary.widthMultiplier = 0.065f; LineRenderer? obj = boundary; LineRenderer? obj2 = boundary; Color val2 = default(Color); ((Color)(ref val2))..ctor(0.9f, 0.75f, 0.35f, 0.8f); obj2.endColor = val2; obj.startColor = val2; boundary.positionCount = 96; } ((Renderer)boundary).enabled = true; if (drawnRadius != Plugin.ArenaRadius.Value || !(drawnPosition == ((Component)this).transform.position)) { drawnRadius = Plugin.ArenaRadius.Value; drawnPosition = ((Component)this).transform.position; for (int i = 0; i < 96; i++) { float num = (float)i * MathF.PI * 2f / 96f; boundary.SetPosition(i, ((Component)this).transform.position + new Vector3(Mathf.Cos(num) * drawnRadius, 0.1f, Mathf.Sin(num) * drawnRadius)); } } } } internal static class SafeSpawn { internal const float Distance = 3f; internal static Vector3 Facing(ArenaPole pole) { //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_0015: 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) Vector3 val = Vector3.ProjectOnPlane(((Component)pole).transform.forward, Vector3.up); return ((Vector3)(ref val)).normalized; } internal static bool TryFind(ArenaPole pole, out Vector3 result, Player? ignore = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) result = default(Vector3); if (pole.Valid) { return TryPreview(pole, out result, ignore); } return false; } internal static bool TryPreview(ArenaPole pole, out Vector3 result, Player? ignore) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_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) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) result = ((Component)pole).transform.position + Facing(pole) * 3f; int mask = LayerMask.GetMask(new string[4] { "terrain", "piece", "static_solid", "Default" }); int num = mask | LayerMask.GetMask(new string[3] { "character", "character_net", "vehicle" }); RaycastHit val = default(RaycastHit); if (!Physics.Raycast(result + Vector3.up * 2.5f, Vector3.down, ref val, 5f, mask, (QueryTriggerInteraction)1)) { return false; } result = ((RaycastHit)(ref val)).point + Vector3.up * 0.15f; if (((RaycastHit)(ref val)).normal.y < 0.75f || Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<ArenaPole>())) { return false; } if (Object.op_Implicit((Object)(object)ZoneSystem.instance) && result.y < ZoneSystem.instance.m_waterLevel + 0.2f) { return false; } Vector3 val2 = result - ((Component)pole).transform.position; if (!DeathPolicy.Inside(val2.x, val2.y, val2.z, Plugin.ArenaRadius.Value)) { return false; } Collider[] array = Physics.OverlapCapsule(result + Vector3.up * 0.45f, result + Vector3.up * 1.55f, 0.4f, num, (QueryTriggerInteraction)1); foreach (Collider val3 in array) { if (!Object.op_Implicit((Object)(object)ignore) || (Object)(object)((Component)val3).GetComponentInParent<Player>() != (Object)(object)ignore) { return false; } } return true; } } internal sealed class PendingSpawn { internal Game Game; internal long World; internal long Character; internal ZDOID Pole; internal Vector3 Position; internal Quaternion Rotation; internal float Wait; internal bool Resolved; } internal static class ArenaRespawn { internal static PendingSpawn? Pending; internal static readonly FieldRef<Game, bool> AfterDeath = AccessTools.FieldRefAccess<Game, bool>("m_respawnAfterDeath"); internal static void Clear() { Pending = null; } internal static void Capture(Player player) { //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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if (!ArenaPole.TrySelected(player, out var id)) { Plugin.Log("Protected death has no chosen arena pole; using normal respawn."); return; } ArenaPole arenaPole = null; foreach (ArenaPole item in ArenaPole.Loaded) { if (Object.op_Implicit((Object)(object)item) && item.Valid && item.Id == id) { arenaPole = item; break; } } if (!Object.op_Implicit((Object)(object)arenaPole)) { Plugin.Log("Chosen pole unavailable; using normal respawn."); return; } bool flag = false; foreach (ArenaPole item2 in ArenaPole.Loaded) { if (Object.op_Implicit((Object)(object)item2) && item2.Covers(((Component)player).transform.position)) { Vector3 val = ((Component)item2).transform.position - ((Component)arenaPole).transform.position; if (DeathPolicy.SpawnBelongsToArena(((Vector3)(ref val)).sqrMagnitude, Plugin.ArenaRadius.Value)) { flag = true; break; } } } if (!flag) { Plugin.Log("Chosen pole is in another arena; using normal respawn."); return; } Pending = new PendingSpawn { Game = Game.instance, World = ZNet.instance.GetWorldUID(), Character = player.GetPlayerID(), Pole = id, Position = ((Component)arenaPole).transform.position }; } } [HarmonyPatch(typeof(Game), "FindSpawnPoint")] internal static class ArenaSpawnPointPatch { private static bool Prefix(Game __instance, ref Vector3 __0, ref bool __1, float __2, ref bool __result) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0127: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) PendingSpawn pending = ArenaRespawn.Pending; if (pending == null) { return true; } if ((Object)(object)__instance != (Object)(object)pending.Game || !ArenaRespawn.AfterDeath.Invoke(__instance) || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.GetWorldUID() != pending.World || __instance.GetPlayerProfile().GetPlayerID() != pending.Character || !Plugin.ModEnabled.Value) { ArenaRespawn.Clear(); return true; } pending.Wait += __2; ZNet.instance.SetReferencePosition(pending.Position); __0 = default(Vector3); __1 = true; __result = false; if (pending.Wait > 30f) { Plugin.Log("Arena area did not load in 30 seconds; falling back to normal spawn."); ArenaRespawn.Clear(); return true; } if (pending.Wait < 3f || !ZNetScene.instance.IsAreaReady(pending.Position)) { return false; } GameObject val = ZNetScene.instance.FindInstance(pending.Pole); ArenaPole arenaPole = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ArenaPole>() : null); if (!Object.op_Implicit((Object)(object)arenaPole) || !arenaPole.Valid || !SafeSpawn.TryFind(arenaPole, out var result)) { Plugin.Log("Chosen arena pole was removed or blocked; falling back to normal spawn."); ArenaRespawn.Clear(); return true; } __0 = result; __result = true; pending.Resolved = true; pending.Rotation = Quaternion.LookRotation(SafeSpawn.Facing(arenaPole)); return false; } } [HarmonyPatch(typeof(Game), "SpawnPlayer")] internal static class ArenaSpawnedPatch { private static void Postfix(Player __result) { //IL_0041: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) PendingSpawn pending = ArenaRespawn.Pending; ArenaRespawn.Clear(); if (pending != null && pending.Resolved && Object.op_Implicit((Object)(object)__result) && __result.GetPlayerID() == pending.Character) { __result.SetPVP(true); ((Component)__result).transform.rotation = pending.Rotation; Rigidbody component = ((Component)__result).GetComponent<Rigidbody>(); if (Object.op_Implicit((Object)(object)component)) { component.rotation = pending.Rotation; } ((Character)__result).SetLookDir(pending.Rotation * Vector3.forward, 0f); ((Character)__result).Message((MessageType)2, "PvP ON", 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Game), "OnDestroy")] internal static class ArenaSessionEndPatch { private static void Prefix() { ArenaRespawn.Clear(); MatchNetwork.ResetSession(); } } internal static class DeathPolicy { internal static bool Protect(bool enabled, bool local, bool pvp, bool inside) { return enabled && local && pvp && inside; } internal static bool Inside(float dx, float dy, float dz, float radius) { if (radius > 0f) { return dx * dx + dy * dy + dz * dz <= radius * radius; } return false; } internal static bool SpawnBelongsToArena(float distanceSquared, float radius) { if (radius > 0f) { return distanceSquared <= 4f * radius * radius; } return false; } internal static bool BlockWear(bool protectedPlayer, bool ownedItem, float before, float after) { if (protectedPlayer && ownedItem) { return after < before; } return false; } } [HarmonyPatch] internal static class EquipmentWear { internal static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Humanoid), "DrainEquipedItemDurability", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Humanoid), "BlockAttack", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Player), "UpdatePlacement", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Player), "DamageArmorDurability", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Attack), "ProjectileAttackTriggered", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Attack), "DoNonAttack", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Attack), "DoAreaAttack", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Attack), "DoMeleeAttack", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); FieldInfo objB = AccessTools.Field(typeof(ItemData), "m_durability"); int num = 0; foreach (CodeInstruction item in list) { if (!(item.opcode != OpCodes.Stfld) && object.Equals(item.operand, objB)) { item.opcode = OpCodes.Call; item.operand = AccessTools.Method(typeof(EquipmentWear), "WriteDurability", (Type[])null, (Type[])null); num++; } } int num2 = ((!(__originalMethod.Name == "UpdatePlacement")) ? 1 : 2); if (num != num2) { throw new InvalidOperationException("Durability patch contract changed: " + __originalMethod.Name); } return list; } private static void WriteDurability(ItemData item, float value) { Player localPlayer = Player.m_localPlayer; bool flag = Object.op_Implicit((Object)(object)localPlayer) && ((Humanoid)localPlayer).GetInventory().GetAllItems().Contains(item); if (!DeathPolicy.BlockWear(flag && Plugin.PreventWear.Value && ArenaPole.IsProtected(localPlayer), flag, item.m_durability, value)) { item.m_durability = value; } } } internal static class LegacyCompatibility { private static readonly int oldRed = StringExtensionMethods.GetStableHashCode("FriendlyPvP_RavenPole"); private static readonly int oldBlue = StringExtensionMethods.GetStableHashCode("FriendlyPvP_AxesPole"); private static readonly int oldTable = StringExtensionMethods.GetStableHashCode("FriendlyPvP_RoundTable"); internal static readonly int PreviousAttackStamp = StringExtensionMethods.GetStableHashCode("FriendlyPvP.matchAttack"); internal static int CanonicalPrefab(int hash) { if (hash == oldRed) { return StringExtensionMethods.GetStableHashCode("ValhallaDuels_RavenPole"); } if (hash == oldBlue) { return StringExtensionMethods.GetStableHashCode("ValhallaDuels_AxesPole"); } if (hash == oldTable) { return StringExtensionMethods.GetStableHashCode("ValhallaDuels_RoundTable"); } return hash; } } [HarmonyPatch(typeof(ZNetScene), "GetPrefab", new Type[] { typeof(int) })] internal static class LegacyPrefabLookupPatch { private static void Postfix(ZNetScene __instance, int __0, ref GameObject __result) { if (!Object.op_Implicit((Object)(object)__result)) { int num = LegacyCompatibility.CanonicalPrefab(__0); if (num != __0) { __result = __instance.GetPrefab(num); } } } } internal sealed class FighterPulse { internal long Peer; internal long Sequence; internal ZDOID Character; internal ZDOID Flag; internal string Name = ""; internal Vector3 Position; internal bool Alive; internal bool Pvp; internal bool Teleporting; internal float Seen; internal float LastRequest; } internal sealed class ServerMatch { internal sealed class Arrival { internal int Ticket; internal ZDOID Character; internal Vector3 Position; internal long Sequence; } internal readonly Arrival[] Arrivals = new Arrival[2] { new Arrival(), new Arrival() }; internal ZDOID Board; internal ZDOID Flag0; internal ZDOID Flag1; internal Vector3 Centre; internal long Peer0; internal long Peer1; internal long Generation; internal string Token = Guid.NewGuid().ToString("N"); internal MatchRules Rules; internal int SentRevision; internal float LastBroadcast; internal float CompletedAt; } internal static class MatchNetwork { private const string InputRpc = "ValhallaDuels_MatchInput_v1"; private const string OutputRpc = "ValhallaDuels_MatchOutput_v1"; private static ZRoutedRpc? registered; private static readonly Dictionary<long, FighterPulse> players = new Dictionary<long, FighterPulse>(); private static readonly Dictionary<ZDOID, ServerMatch> matches = new Dictionary<ZDOID, ServerMatch>(); private static float nextPulse; private static float nextTick; private static long sequence; private static long matchSerial; private static string prepared = ""; private static long ServerPeer() { if (Object.op_Implicit((Object)(object)ZNet.instance)) { if (!ZNet.instance.IsServer()) { return ZNet.instance.GetServerPeer()?.m_uid ?? 0; } return ZNet.GetUID(); } return 0L; } internal static void ResetSession() { players.Clear(); matches.Clear(); MatchOverlay.Clear(); MatchPositioning.Clear(); prepared = ""; matchSerial = 0L; nextPulse = (nextTick = 0f); } internal static void Update() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && Object.op_Implicit((Object)(object)ZNet.instance)) { if (registered != instance) { ResetSession(); registered = instance; sequence = 0L; instance.Register<ZPackage>("ValhallaDuels_MatchInput_v1", (Action<long, ZPackage>)OnInput); instance.Register<ZPackage>("ValhallaDuels_MatchOutput_v1", (Action<long, ZPackage>)OnOutput); } float unscaledTime = Time.unscaledTime; MatchPositioning.Update(); if (unscaledTime >= nextPulse) { nextPulse = unscaledTime + 0.5f; Pulse(); MatchOverlay.Prune(); } if (ZNet.instance.IsServer() && unscaledTime >= nextTick) { nextTick = unscaledTime + 0.2f; TickServer(unscaledTime); } } } private static void SendInput(ZPackage package) { if (registered != null && Object.op_Implicit((Object)(object)ZNet.instance)) { long num = ServerPeer(); if (num != 0L) { registered.InvokeRoutedRPC(num, "ValhallaDuels_MatchInput_v1", new object[1] { package }); } } } private static void Pulse() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Game.instance) && (Object.op_Implicit((Object)(object)Player.m_localPlayer) || MatchOverlay.LocalMatch != null)) { ZPackage val = new ZPackage(); val.Write(0); val.Write(++sequence); Player localPlayer = Player.m_localPlayer; val.Write((Object)(object)localPlayer != (Object)null); if (Object.op_Implicit((Object)(object)localPlayer)) { val.Write(((Character)localPlayer).GetZDOID()); ArenaPole.TrySelected(localPlayer, out var id); val.Write(id); val.Write(!((Character)localPlayer).IsDead() && ((Character)localPlayer).GetHealth() > 0f); val.Write(((Character)localPlayer).IsPVPEnabled()); val.Write(((Character)localPlayer).IsTeleporting()); } SendInput(val); } } internal static void Request(ZDOID board, bool forfeit) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown Pulse(); ZPackage val = new ZPackage(); val.Write((!forfeit) ? 1 : 3); val.Write(board); SendInput(val); } internal static void Arrived(MatchView view, Player player, Vector3 position) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0013: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0042: 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_0058: Expected O, but got Unknown Pulse(); ZPackage val = new ZPackage(); val.Write(4); val.Write(view.Board); val.Write(view.Token); val.Write(view.PlacementTicket); val.Write(((Character)player).GetZDOID()); val.Write(position); val.Write(sequence); SendInput(val); } internal static void ReportDeath(Player player) { //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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_004d: 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_005e: Expected O, but got Unknown if (!((Object)(object)player != (Object)(object)Player.m_localPlayer)) { MatchView localMatch = MatchOverlay.LocalMatch; if (localMatch != null) { Pulse(); ZPackage val = new ZPackage(); val.Write(2); val.Write(localMatch.Board); val.Write(localMatch.Token); val.Write(localMatch.Epoch); val.Write(((Character)player).GetZDOID()); SendInput(val); } } } private static bool PeerInfo(long sender, out ZDOID character, out string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) character = ZDOID.None; name = ""; if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } if (sender == ZNet.GetUID()) { if (!Object.op_Implicit((Object)(object)Game.instance) || (!Object.op_Implicit((Object)(object)Player.m_localPlayer) && MatchOverlay.LocalMatch == null) || Game.instance.GetPlayerProfile() == null) { return false; } name = CleanName(Game.instance.GetPlayerProfile().GetName()); if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { character = ((Character)Player.m_localPlayer).GetZDOID(); } if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return MatchOverlay.LocalMatch != null; } return true; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || !peer.IsReady()) { return false; } character = peer.m_characterID; name = CleanName(peer.m_playerName); return true; } private static string CleanName(string value) { string text = new string((value ?? "Viking").Where((char c) => !char.IsControl(c) && c != '<' && c != '>').Take(32).ToArray()); if (!string.IsNullOrWhiteSpace(text)) { return text; } return "Viking"; } private static void OnInput(long sender, ZPackage package) { //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !Object.op_Implicit((Object)(object)Game.instance) || ZDOMan.instance == null || !ZNet.instance.IsServer() || package.Size() > 1024 || !PeerInfo(sender, out ZDOID character, out string name)) { return; } try { int num = package.ReadInt(); if (num == 0) { long num2 = package.ReadLong(); bool flag = package.ReadBool(); if (!players.TryGetValue(sender, out FighterPulse value)) { Dictionary<long, FighterPulse> dictionary = players; FighterPulse obj = new FighterPulse { Peer = sender }; value = obj; dictionary[sender] = obj; } if (num2 <= value.Sequence) { return; } if (!flag) { value.Sequence = num2; value.Seen = Time.unscaledTime; value.Alive = false; return; } ZDOID val = package.ReadZDOID(); ZDOID flag2 = package.ReadZDOID(); bool flag3 = package.ReadBool(); bool pvp = package.ReadBool(); bool teleporting = package.ReadBool(); if (!(val != character)) { ZDO zDO = ZDOMan.instance.GetZDO(val); if (zDO != null && zDO.IsValid()) { value.Sequence = num2; value.Seen = Time.unscaledTime; value.Name = name; value.Character = val; value.Flag = flag2; value.Position = zDO.GetPosition(); value.Alive = flag3 && !zDO.GetBool(ZDOVars.s_dead, false); value.Pvp = pvp; value.Teleporting = teleporting; } } } else { if (!players.TryGetValue(sender, out FighterPulse value2)) { return; } ZDOID val2 = package.ReadZDOID(); switch (num) { case 4: { string text = package.ReadString(); int num3 = package.ReadInt(); ZDOID val3 = package.ReadZDOID(); Vector3 val4 = package.ReadVector3(); long num4 = package.ReadLong(); if (!matches.TryGetValue(val2, out ServerMatch value4) || value4.Token != text || value4.Rules.Phase != MatchPhase.Waiting || num3 != value4.Rules.PlacementTicket || val3 != value2.Character || val3 != character || !Alive(sender, Time.unscaledTime) || value2.Teleporting || num4 != value2.Sequence) { break; } int num5 = ((sender != value4.Peer0) ? ((sender == value4.Peer1) ? 1 : (-1)) : 0); if (num5 < 0) { break; } ZDO val5 = Flag((num5 == 0) ? value4.Flag0 : value4.Flag1); if (val5 != null && Within(val4, val5.GetPosition(), 6f)) { ServerMatch.Arrival arrival = value4.Arrivals[num5]; if (arrival.Ticket != num3 || !(arrival.Character == val3) || num4 > arrival.Sequence) { arrival.Ticket = num3; arrival.Character = val3; arrival.Position = val4; arrival.Sequence = num4; } } break; } case 2: { string text2 = package.ReadString(); int epoch = package.ReadInt(); ZDOID val6 = package.ReadZDOID(); if (matches.TryGetValue(val2, out ServerMatch value5) && value5.Token == text2 && value2.Character == val6) { int side2 = ((sender != value5.Peer0) ? ((sender == value5.Peer1) ? 1 : (-1)) : 0); value5.Rules.Death(side2, epoch, Time.unscaledTime); } break; } case 1: case 3: if (!(Time.unscaledTime - value2.LastRequest < 1f)) { value2.LastRequest = Time.unscaledTime; ServerMatch value3; if (num == 1) { Start(sender, val2); } else if (matches.TryGetValue(val2, out value3)) { int side = ((sender != value3.Peer0) ? ((sender == value3.Peer1) ? 1 : (-1)) : 0); value3.Rules.Forfeit(side, "conceded"); } } break; } } } catch (Exception ex) { Plugin.Log("Ignored invalid arena match request: " + ex.GetType().Name); } } private static ZDO? Flag(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(id); if (zDO == null || !zDO.IsValid() || !PolePrefabs.IsPole(zDO.GetPrefab())) { return null; } return zDO; } private static bool Within(Vector3 a, Vector3 b, float radius) { //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) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Vector3 val = a - b; return ((Vector3)(ref val)).sqrMagnitude <= radius * radius; } private static bool Busy(long peer) { return matches.Values.Any((ServerMatch m) => !m.Rules.Complete && (m.Peer0 == peer || m.Peer1 == peer)); } internal static bool IsFighterCharacter(ZDOID character) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (character == ZDOID.None || !Plugin.Ready || !Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } if (ZNet.instance.IsServer()) { return players.Values.Any((FighterPulse p) => p.Character == character && Busy(p.Peer)); } if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Character)Player.m_localPlayer).GetZDOID() == character) { return MatchOverlay.LocalMatch != null; } ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(character) : null); if (val == null) { return false; } long owner = val.GetOwner(); return MatchOverlay.Views.Values.Any((MatchView v) => !v.Complete && Time.unscaledTime - v.Seen < 5f && (v.Peer0 == owner || v.Peer1 == owner)); } private static void Start(long sender, ZDOID board) { //IL_002b: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: 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_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Ready || !Plugin.ModEnabled.Value) { Reply(sender, "Arena disabled"); return; } ZDO table = ZDOMan.instance.GetZDO(board); if (table == null || LegacyCompatibility.CanonicalPrefab(table.GetPrefab()) != StringExtensionMethods.GetStableHashCode("ValhallaDuels_RoundTable")) { return; } FighterPulse fighterPulse = players[sender]; if (!fighterPulse.Alive || !Within(fighterPulse.Position, table.GetPosition(), 6f)) { return; } if (matches.TryGetValue(board, out ServerMatch value) && !value.Rules.Complete) { Reply(sender, "Match in progress"); return; } float radius = Plugin.ArenaRadius.Value; ZDOID character; string name; List<FighterPulse> source = players.Values.Where((FighterPulse p) => p.Alive && p.Pvp && Time.unscaledTime - p.Seen < 3f && !Busy(p.Peer) && PeerInfo(p.Peer, out character, out name)).Where(delegate(FighterPulse p) { //IL_0001: 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_001b: 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_003a: Unknown result type (might be due to invalid IL or missing references) ZDO val3 = Flag(p.Flag); return val3 != null && Within(val3.GetPosition(), table.GetPosition(), radius * 2f) && Within(p.Position, val3.GetPosition(), radius); }).ToList(); List<FighterPulse> list = source.Where((FighterPulse p) => LegacyCompatibility.CanonicalPrefab(Flag(p.Flag).GetPrefab()) == StringExtensionMethods.GetStableHashCode("ValhallaDuels_RavenPole")).ToList(); List<FighterPulse> list2 = source.Where((FighterPulse p) => LegacyCompatibility.CanonicalPrefab(Flag(p.Flag).GetPrefab()) == StringExtensionMethods.GetStableHashCode("ValhallaDuels_AxesPole")).ToList(); if (list.Count == 0 || list2.Count == 0) { Reply(sender, "Both teams must have a player."); return; } if (list.Count > 1 || list2.Count > 1) { Reply(sender, "Only one player per team."); return; } FighterPulse first = list[0]; FighterPulse second = list2[0]; if (sender != first.Peer && sender != second.Peer) { Reply(sender, "A fighter must start"); return; } ZDO val = Flag(first.Flag); ZDO val2 = Flag(second.Flag); if (matches.Values.Any((ServerMatch m) => !m.Rules.Complete && (m.Flag0 == first.Flag || m.Flag1 == second.Flag))) { Reply(sender, "Flags already in use"); return; } if (!Within(val.GetPosition(), val2.GetPosition(), radius * 2f)) { Reply(sender, "Move flags closer together"); return; } matches[board] = new ServerMatch { Board = board, Centre = table.GetPosition(), Peer0 = first.Peer, Peer1 = second.Peer, Flag0 = first.Flag, Flag1 = second.Flag, Generation = ++matchSerial, Rules = new MatchRules(first.Name, second.Name, Time.unscaledTime) }; Broadcast(matches[board]); } private static string? Invalid(ServerMatch match, long peer, ZDOID chosen, ZDO flag0, ZDO flag1, float now) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_007f: 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) if (!PeerInfo(peer, out ZDOID _, out string _)) { return "disconnected"; } if (!players.TryGetValue(peer, out FighterPulse value) || now - value.Seen > 15f) { return "connection lost"; } if (value.Flag != chosen) { return "team changed"; } if (value.Alive) { if (!value.Pvp) { return "PvP OFF"; } if (!Within(value.Position, flag0.GetPosition(), Plugin.ArenaRadius.Value) && !Within(value.Position, flag1.GetPosition(), Plugin.ArenaRadius.Value)) { return "left arena"; } } return null; } private static bool Alive(long peer, float now) { if (players.TryGetValue(peer, out FighterPulse value) && now - value.Seen < 2f && value.Alive) { return value.Pvp; } return false; } private static bool Ready(ServerMatch match, int side, ZDO flag, float now) { //IL_004e: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) long num = ((side == 0) ? match.Peer0 : match.Peer1); if (!Alive(num, now)) { return false; } FighterPulse fighterPulse = players[num]; ServerMatch.Arrival arrival = match.Arrivals[side]; if (!fighterPulse.Teleporting && arrival.Ticket == match.Rules.PlacementTicket && arrival.Character == fighterPulse.Character && Within(fighterPulse.Position, arrival.Position, 1.5f)) { return Within(fighterPulse.Position, flag.GetPosition(), 6f); } return false; } private static void TickServer(float now) { //IL_002c: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0257: 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_00b2: Unknown result type (might be due to invalid IL or missing references) ServerMatch[] array = matches.Values.ToArray(); foreach (ServerMatch serverMatch in array) { if (!serverMatch.Rules.Complete) { ZDO val = Flag(serverMatch.Flag0); ZDO val2 = Flag(serverMatch.Flag1); ZDO zDO = ZDOMan.instance.GetZDO(serverMatch.Board); if (!Plugin.Ready || !Plugin.ModEnabled.Value || val == null || val2 == null || zDO == null || !zDO.IsValid()) { serverMatch.Rules.Cancel("arena unavailable"); } else { string text = Invalid(serverMatch, serverMatch.Peer0, serverMatch.Flag0, val, val2, now); string text2 = Invalid(serverMatch, serverMatch.Peer1, serverMatch.Flag1, val, val2, now); if (text != null && text2 != null) { serverMatch.Rules.Cancel("both forfeited"); } else if (text != null) { serverMatch.Rules.Forfeit(0, text); } else if (text2 != null) { serverMatch.Rules.Forfeit(1, text2); } else { bool flag = Ready(serverMatch, 0, val, now); bool flag2 = Ready(serverMatch, 1, val2, now); if (serverMatch.Rules.Phase == MatchPhase.Waiting && (double)now - serverMatch.Rules.WaitingSince > 120.0) { if (!flag && !flag2) { serverMatch.Rules.Cancel("players not ready"); } else { serverMatch.Rules.Forfeit(flag ? 1 : 0, "not ready"); } } if (players.TryGetValue(serverMatch.Peer0, out FighterPulse value) && !value.Alive) { serverMatch.Rules.Death(0, serverMatch.Rules.Epoch, now); } if (players.TryGetValue(serverMatch.Peer1, out FighterPulse value2) && !value2.Alive) { serverMatch.Rules.Death(1, serverMatch.Rules.Epoch, now); } serverMatch.Rules.Tick(now, flag && flag2); } } } if (serverMatch.Rules.Revision != serverMatch.SentRevision || now - serverMatch.LastBroadcast >= 1f) { Broadcast(serverMatch); } if (serverMatch.Rules.Complete) { if (serverMatch.CompletedAt == 0f) { serverMatch.CompletedAt = now; } if (now - serverMatch.CompletedAt > 12f) { matches.Remove(serverMatch.Board); } } } long[] array2 = players.Keys.ToArray(); foreach (long num in array2) { if (!Busy(num) && now - players[num].Seen > 30f) { players.Remove(num); } } } private static void Broadcast(ServerMatch match) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) if (match.Rules.Revision != match.SentRevision && match.Rules.Complete && match.Rules.OutcomeReason.Length > 0) { Plugin.Log("Match " + match.Token + ": " + match.Rules.Phase.ToString() + " (" + match.Rules.OutcomeReason + ")"); } ZPackage val = new ZPackage(); val.Write(1); val.Write(match.Board); val.Write(match.Token); val.Write(match.Generation); val.Write(match.Peer0); val.Write(match.Peer1); val.Write(match.Rules.Name0); val.Write(match.Rules.Name1); val.Write(match.Rules.Score0); val.Write(match.Rules.Score1); val.Write(match.Rules.Epoch); val.Write((int)match.Rules.Phase); val.Write(match.Rules.Revision); val.Write(match.Rules.Notice); val.Write(match.Centre); val.Write(match.Flag0); val.Write(match.Flag1); ZDO? obj = Flag(match.Flag0); val.Write((obj != null) ? obj.GetPosition() : match.Centre); ZDO? obj2 = Flag(match.Flag1); val.Write((obj2 != null) ? obj2.GetPosition() : match.Centre); val.Write(match.Rules.PlacementTicket); val.Write(match.Rules.CanPosition(Time.unscaledTime) && Alive(match.Peer0, Time.unscaledTime) && Alive(match.Peer1, Time.unscaledTime)); long[] array = players.Keys.ToArray(); foreach (long num in array) { if (PeerInfo(num, out ZDOID _, out string _) && (num == match.Peer0 || num == match.Peer1 || Within(players[num].Position, match.Centre, Plugin.ArenaRadius.Value * 2f + 20f))) { registered.InvokeRoutedRPC(num, "ValhallaDuels_MatchOutput_v1", new object[1] { val }); } } match.SentRevision = match.Rules.Revision; match.LastBroadcast = Time.unscaledTime; } private static void Reply(long peer, string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(0); val.Write(message); registered.InvokeRoutedRPC(peer, "ValhallaDuels_MatchOutput_v1", new object[1] { val }); } private static void OnOutput(long sender, ZPackage p) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (registered == null || sender != ServerPeer() || p.Size() > 2048) { return; } try { if (p.ReadInt() == 0) { MatchOverlay.Notify(p.ReadString()); return; } MatchOverlay.Receive(new MatchView { Board = p.ReadZDOID(), Token = p.ReadString(), Generation = p.ReadLong(), Peer0 = p.ReadLong(), Peer1 = p.ReadLong(), Name0 = p.ReadString(), Name1 = p.ReadString(), Score0 = p.ReadInt(), Score1 = p.ReadInt(), Epoch = p.ReadInt(), Phase = (MatchPhase)p.ReadInt(), Revision = p.ReadInt(), Notice = p.ReadString(), Centre = p.ReadVector3(), Flag0 = p.ReadZDOID(), Flag1 = p.ReadZDOID(), FlagPosition0 = p.ReadVector3(), FlagPosition1 = p.ReadVector3(), PlacementTicket = p.ReadInt(), PlaceFighters = p.ReadBool(), Seen = Time.unscaledTime }); } catch (Exception ex) { Plugin.Log("Ignored invalid arena match update: " + ex.GetType().Name); } } internal static bool Shielded(Player player) { MatchView localMatch = MatchOverlay.LocalMatch; if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && ArenaPole.IsProtected(player) && localMatch != null) { if (localMatch.Phase != MatchPhase.Waiting) { return localMatch.Phase == MatchPhase.Countdown; } return true; } return false; } internal static void PrepareFighter(MatchView match, bool changed) { if (!changed || !Object.op_Implicit((Object)(object)ZNet.instance) || (match.Peer0 != ZNet.GetUID() && match.Peer1 != ZNet.GetUID())) { return; } Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && ArenaPole.IsProtected(localPlayer) && (match.Phase == MatchPhase.Countdown || match.Phase == MatchPhase.Fighting)) { string text = match.Token + ":" + match.Epoch + ":" + match.Phase; if (!(text == prepared)) { prepared = text; ((Character)localPlayer).GetSEMan().RemoveStatusEffect(SEMan.s_statusEffectPoison, false); ((Character)localPlayer).GetSEMan().RemoveStatusEffect(SEMan.s_statusEffectBurning, false); ((Character)localPlayer).SetHealth(((Character)localPlayer).GetMaxHealth()); ((Character)localPlayer).AddStamina(((Character)localPlayer).GetMaxStamina()); ((Character)localPlayer).AddEitr(((Character)localPlayer).GetMaxEitr()); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class BetweenRoundNetworkDamagePatch { private static bool Prefix(Character __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { return !MatchNetwork.Shielded(val); } return true; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class BetweenRoundDamagePatch { private static bool Prefix(Character __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { return !MatchNetwork.Shielded(val); } return true; } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] internal static class BetweenRoundAttackPatch { private static bool Prefix(Humanoid __instance, ref bool __result) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null || !MatchNetwork.Shielded(val)) { return true; } __result = false; return false; } } internal sealed class MatchView { internal string Token = ""; internal string Name0 = ""; internal string Name1 = ""; internal string Notice = ""; internal ZDOID Board; internal ZDOID Flag0; internal ZDOID Flag1; internal Vector3 FlagPosition0; internal Vector3 FlagPosition1; internal int PlacementTicket; internal bool PlaceFighters; internal long Peer0; internal long Peer1; internal long Generation; internal int Epoch; internal int Revision; internal int Score0; internal int Score1; internal MatchPhase Phase; internal Vector3 Centre; internal float Seen; internal string Score => TeamNames.Score(Score0, Score1); internal bool Complete { get { if (Phase != MatchPhase.Finished) { return Phase == MatchPhase.Cancelled; } return true; } } } internal static class MatchOverlay { internal static readonly Dictionary<string, MatchView> Views = new Dictionary<string, MatchView>(); private static string alert = ""; private static float alertUntil; private static bool emphasis; private static GUIStyle? large; private static GUIStyle? small; internal static MatchView? LocalMatch { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return null; } long uID = ZNet.GetUID(); foreach (MatchView value in Views.Values) { if (!value.Complete && Time.unscaledTime - value.Seen < 5f && (value.Peer0 == uID || value.Peer1 == uID)) { return value; } } return null; } } internal static void Clear() { Views.Clear(); alert = ""; alertUntil = 0f; } internal static void Prune() { string[] array = Views.Keys.ToArray(); foreach (string key in array) { if (Time.unscaledTime - Views[key].Seen > 20f) { Views.Remove(key); } } } internal static void Alert(string text, float duration = 6f, bool prominent = false) { alert = text; alertUntil = Time.unscaledTime + duration; emphasis = prominent; } internal static void Notify(string text) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } internal static void Receive(MatchView view) { MatchView[] array = Views.Values.Where((MatchView v) => v.Board == view.Board && v.Token != view.Token).ToArray(); foreach (MatchView matchView in array) { if (matchView.Generation >= view.Generation) { return; } Views.Remove(matchView.Token); } if (!Views.TryGetValue(view.Token, out MatchView value) || value.Revision <= view.Revision) { bool flag = value == null || value.Revision != view.Revision; Views[view.Token] = view; MatchView localMatch = LocalMatch; if (flag && (localMatch == null || localMatch.Token == view.Token)) { Alert(view.Notice, (view.Phase == MatchPhase.Fighting) ? 1.5f : ((float)(view.Complete ? 9 : 6)), view.Phase == MatchPhase.Countdown || view.Phase == MatchPhase.Fighting); } MatchNetwork.PrepareFighter(view, flag); } } internal static void Draw() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_005b: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) MatchView matchView = LocalMatch; if (matchView == null && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { float num = float.MaxValue; foreach (MatchView value in Views.Values) { if (!(Time.unscaledTime - value.Seen > 3f)) { Vector3 val = ((Component)Player.m_localPlayer).transform.position - value.Centre; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; matchView = value; } } } } bool flag = !string.IsNullOrWhiteSpace(alert) && Time.unscaledTime < alertUntil; if (flag || matchView != null) { if (large == null) { large = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = (FontStyle)1, wordWrap = true, richText = false, fixedHeight = 0f, fixedWidth = 0f, padding = new RectOffset(0, 0, 0, 0), margin = new RectOffset(0, 0, 0, 0), clipping = (TextClipping)0 }; large.normal.textColor = new Color(1f, 0.87f, 0.55f); small = new GUIStyle(large) { fontSize = 22 }; } large.fontSize = (emphasis ? Mathf.Clamp(Screen.width / 15, 64, 112) : Mathf.Clamp(Screen.width / 38, 24, 48)); large.normal.textColor = ((emphasis && alert == "FIGHT!") ? new Color(0.55f, 1f, 0.35f) : new Color(1f, 0.87f, 0.55f)); float num2 = (float)Screen.height * 0.22f; if (matchView != null) { small.fontSize = Mathf.Clamp(Screen.width / 70, 18, 26); float num3 = DrawPanel(matchView.Score, small, (float)Screen.width * 0.7f, (float)Screen.height * 0.04f, new Color(0f, 0f, 0f, 0.7f)); num2 = Mathf.Max(num2, num3 + 12f); } if (flag) { DrawPanel(alert, large, Mathf.Min((float)Screen.width * 0.84f, (float)(emphasis ? 580 : 1250)), num2, new Color(0.04f, 0.03f, 0.02f, 0.87f)); } } } private static float DrawPanel(string text, GUIStyle style, float width, float top, Color background) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(1f, width - 40f); string[] array = text.Split('\n'); float[] array2 = new float[array.Length]; float num2; while (true) { num2 = 40f; for (int i = 0; i < array.Length; i++) { float num3 = Mathf.Max(style.lineHeight, (float)style.fontSize * 1.5f); array2[i] = Mathf.Ceil(Mathf.Max(num3, style.CalcHeight(new GUIContent(array[i]), num) * 1.25f)) + 10f; num2 += array2[i]; } if (num2 <= Mathf.Min((float)Screen.height * 0.68f, (float)Screen.height - top - 12f) || style.fontSize <= 16) { break; } style.fontSize -= 2; } top = Mathf.Min(top, Mathf.Max(8f, (float)Screen.height - num2 - 12f)); float num4 = ((float)Screen.width - width) / 2f; Color color = GUI.color; GUI.color = background; GUI.DrawTexture(new Rect(num4, top, width, num2), (Texture)(object)Texture2D.whiteTexture); GUI.color = color; float num5 = top + 20f; for (int j = 0; j < array.Length; j++) { GUI.Label(new Rect(num4 + 20f, num5, num, array2[j]), array[j], style); num5 += array2[j]; } return top + num2; } } internal static class MatchPositioning { private static string token = ""; private static int ticket; private static ZDOID character; private static Vector3 destination; private static bool started; private static bool warned; private static float nextAttempt; private static float nextReceipt; internal static void Clear() { //IL_0010: 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) token = ""; ticket = 0; character = ZDOID.None; started = (warned = false); nextAttempt = (nextReceipt = 0f); } internal static bool Holding(Player player) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) MatchView localMatch = MatchOverlay.LocalMatch; if (localMatch == null || PlayerInvalid(player)) { return false; } if (localMatch.Phase != MatchPhase.Countdown) { if (localMatch.Phase == MatchPhase.Waiting && started && token == localMatch.Token && ticket == localMatch.PlacementTicket && character == ((Character)player).GetZDOID() && !((Character)player).IsTeleporting()) { Vector3 val = ((Component)player).transform.position - destination; return ((Vector3)(ref val)).sqrMagnitude <= 2.25f; } return false; } return true; } private static bool PlayerInvalid(Player player) { if (Object.op_Implicit((Object)(object)player) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { return ((Character)player).IsDead(); } return true; } internal static void Update() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) MatchView localMatch = MatchOverlay.LocalMatch; Player localPlayer = Player.m_localPlayer; if (localMatch == null) { Clear(); } else { if (PlayerInvalid(localPlayer) || ((Character)localPlayer).GetHealth() <= 0f || !((Character)localPlayer).IsPVPEnabled() || localMatch.Phase != MatchPhase.Waiting || !localMatch.PlaceFighters) { return; } if (token != localMatch.Token || ticket != localMatch.PlacementTicket || character != ((Character)localPlayer).GetZDOID()) { Clear(); token = localMatch.Token; ticket = localMatch.PlacementTicket; character = ((Character)localPlayer).GetZDOID(); } if (((Character)localPlayer).IsTeleporting()) { return; } float unscaledTime = Time.unscaledTime; if (started) { Vector3 val = ((Component)localPlayer).transform.position - destination; if (((Vector3)(ref val)).sqrMagnitude <= 2.25f) { if (unscaledTime >= nextReceipt) { nextReceipt = unscaledTime + 0.5f; MatchNetwork.Arrived(localMatch, localPlayer, destination); } return; } started = false; } if (unscaledTime < nextAttempt) { return; } nextAttempt = unscaledTime + 1f; ZDOID val2 = ((localMatch.Peer0 == ZNet.GetUID()) ? localMatch.Flag0 : localMatch.Flag1); GameObject val3 = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(val2) : null); ArenaPole arenaPole = (Object.op_Implicit((Object)(object)val3) ? val3.GetComponent<ArenaPole>() : null); if (!Object.op_Implicit((Object)(object)arenaPole) || !arenaPole.Valid || !SafeSpawn.TryFind(arenaPole, out destination, localPlayer)) { if (!warned) { warned = true; MatchOverlay.Notify("Spawn blocked"); } } else { Vector3 val4 = SafeSpawn.Facing(arenaPole); localPlayer.StopDoodadControl(); ((Character)localPlayer).AttachStop(); started = ((Character)localPlayer).TeleportTo(destination, Quaternion.LookRotation(val4), false); } } } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class RoundStartControlsPatch { private static void Prefix(Player __instance, ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool run, ref bool autoRun, ref bool dodge) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (MatchPositioning.Holding(__instance)) { movedir = Vector3.zero; attack = (attackHold = (secondaryAttack = (secondaryAttackHold = (block = (blockHold = false))))); jump = (crouch = (run = (autoRun = (dodge = false)))); } } } internal enum MatchPhase { Waiting, Countdown, Fighting, Settling, Finished, Cancelled } internal sealed class MatchRules { private double deadline; private double restUntil; private int lastCountdown; private bool dead0; private bool dead1; internal MatchPhase Phase { get; private set; } internal int Score0 { get; private set; } internal int Score1 { get; private set; } internal int Epoch { get; private set; } internal int Revision { get; private set; } = 1; internal int Winner { get; private set; } = -1; internal string Notice { get; private set; } = ""; internal string OutcomeReason { get; private set; } = ""; internal string Name0 { get; } internal string Name1 { get; } internal bool Complete { get { if (Phase != MatchPhase.Finished) { return Phase == MatchPhase.Cancelled; } return true; } } internal string Score => TeamNames.Score(Score0, Score1); internal int Round => Score0 + Score1 + 1; internal double WaitingSince { get; private set; } internal int PlacementTicket { get { if (Phase != MatchPhase.Waiting) { return Epoch; } return Epoch + 1; } } internal bool CanPosition(double now) { if (Phase == MatchPhase.Waiting) { return now >= restUntil; } return false; } internal MatchRules(string first, string second, double now) { Name0 = first; Name1 = second; WaitingSince = now; } private void Announce(string text) { Notice = text; Revision++; } internal void Tick(double now, bool bothReady) { if (Complete) { return; } if (Phase == MatchPhase.Waiting && bothReady && now >= restUntil) { Phase = MatchPhase.Countdown; Epoch++; dead0 = (dead1 = false); deadline = now + 1.0; lastCountdown = 3; Announce("3"); } else if (Phase == MatchPhase.Countdown) { if (!bothReady) { Phase = MatchPhase.Waiting; Announce(""); } else if (!(now < deadline)) { deadline = now + 1.0; lastCountdown--; if (lastCountdown == 0) { Phase = MatchPhase.Fighting; Announce("FIGHT!"); } else { Announce(lastCountdown.ToString()); } } } else { if (Phase != MatchPhase.Settling || !(now >= deadline)) { return; } if (dead0 && dead1) { Phase = MatchPhase.Waiting; WaitingSince = now; restUntil = now + 6.0; Announce("Draw"); return; } if (dead0) { Score1++; } else { Score0++; } if (Score0 == 2 || Score1 == 2) { Winner = ((Score0 != 2) ? 1 : 0); Phase = MatchPhase.Finished; Announce(TeamNames.Winner(Winner)); } else { Phase = MatchPhase.Waiting; WaitingSince = now; restUntil = now + 6.0; Announce(Score); } } } internal bool Death(int side, int epoch, double now) { if (epoch != Epoch || (side != 0 && side != 1) || (Phase != MatchPhase.Fighting && Phase != MatchPhase.Settling)) { return false; } if (Phase == MatchPhase.Settling && now > deadline) { return false; } if ((side == 0) ? dead0 : dead1) { return false; } if (side == 0) { dead0 = true; } else { dead1 = true; } if (Phase == MatchPhase.Fighting) { Phase = MatchPhase.Settling; deadline = now + 0.75; } return true; } internal void Forfeit(int side, string reason) { if (!Complete && (side == 0 || side == 1)) { Winner = 1 - side; Phase = MatchPhase.Finished; OutcomeReason = reason; Announce(TeamNames.Winner(Winner)); } } internal void Cancel(string reason) { if (!Complete) { Phase = MatchPhase.Cancelled; OutcomeReason = reason; Announce("Cancelled"); } } } internal static class MatchWorldProtection { private sealed class Stamp { } private static readonly ConditionalWeakTable<Component, Stamp> marked = new ConditionalWeakTable<Component, Stamp>(); private static readonly int stampKey = StringExtensionMethods.GetStableHashCode("ValhallaDuels.matchAttack"); internal static bool Fighter(Character? owner) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (owner is Player) { return MatchNetwork.IsFighterCharacter(owner.GetZDOID()); } return false; } private static ZNetView? EffectView(Component effect) { ZNetView componentInParent = effect.GetComponentInParent<ZNetView>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.IsValid() || Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<Character>())) { return null; } return componentInParent; } internal static bool Capture(Component effect, Character? owner = null) { ZNetView val = EffectView(effect); if (!marked.TryGetValue(effect, out Stamp _) && !WorldDamageScope.Active && !Fighter(owner) && (!Object.op_Implicit((Object)(object)val) || (!val.GetZDO().GetBool(stampKey, false) && !val.GetZDO().GetBool(LegacyCompatibility.PreviousAttackStamp, false)))) { return false; } marked.GetValue(effect, (Component _) => new Stamp()); if (Object.op_Implicit((Object)(object)val) && val.IsOwner()) { val.GetZDO().Set(stampKey, true); } return true; } internal static bool CharacterTarget(Component target) { if (target is Character || Object.op_Implicit((Object)(object)target.GetComponentInParent<Character>())) { return true; } HitArea val = (HitArea)(object)((target is HitArea) ? target : null); if (val != null && Object.op_Implicit((Object)(object)val.m_parentObject)) { return Object.op_Implicit((Object)(object)val.m_parentObject.GetComponent<Character>()); } return false; } } [HarmonyPatch] internal static class MatchWorldDamagePatch { private static IEnumerable<MethodBase> TargetMethods() { Type[] array = new Type[7] { typeof(WearNTear), typeof(Destructible), typeof(TreeBase), typeof(TreeLog), typeof(MineRock), typeof(MineRock5), typeof(HitArea) }; foreach (Type type in array) { yield return AccessTools.Method(type, "Damage", new Type[1] { typeof(HitData) }, (Type[])null); } } private static bool Prefix(Component __instance, HitData __0) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return !WorldDamageScope.Block(MatchWorldProtection.CharacterTarget(__instance), __0 != null && MatchNetwork.IsFighterCharacter(__0.m_attacker)); } } [HarmonyPatch] internal static class MatchAttackScopePatch { internal sealed class State : IDisposable { private readonly Attack attack; private readonly bool harvest; private readonly bool snow; private readonly WorldDamageScope scope; internal State(Attack source, bool protect) { attack = source; harvest = source.m_harvest; snow = source.m_snowShovel; scope = new WorldDamageScope(protect); if (WorldDamageScope.Active) { source.m_harvest = false; source.m_snowShovel = false; } } public void Dispose() { attack.m_harvest = harvest; attack.m_snowShovel = snow; scope.Dispose(); } } private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[4] { "DoMeleeAttack", "DoAreaAttack", "DoNonAttack", "FireProjectileBurst" }; foreach (string text in array) { yield return AccessTools.Method(typeof(Attack), text, (Type[])null, (Type[])null); } } private static void Prefix(Attack __instance, Humanoid ___m_character, out State __state) { __state = new State(__instance, MatchWorldProtection.Fighter((Character?)(object)___m_character)); } private static Exception? Finalizer(Exception? __exception, State? __state) { __state?.Dispose(); return __exception; } } [HarmonyPatch] internal static class MatchEffectAwakePatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Projectile), "Awake", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Aoe), "Awake", (Type[])null, (Type[])null); } private static void Prefix(Component __instance) { MatchWorldProtection.Capture(__instance); } private static void Postfix(Component __instance) { MatchWorldProtection.Capture(__instance); } } [HarmonyPatch] internal static class MatchEffectSetupPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Projectile), "Setup", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Aoe), "Setup", (Type[])null, (Type[])null); } private static void Prefix(Component __instance, Character __0) { MatchWorldProtection.Capture(__instance, __0); } } [HarmonyPatch] internal static class MatchProjectileScopePatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[3] { "OnHit", "DoAOE", "SpawnOnHit" }; foreach (string text in array) { yield return AccessTools.Method(typeof(Projectile), text, (Type[])null, (Type[])null); } } private static void Prefix(Projectile __instance, Character ___m_owner, out WorldDamageScope __state) { __state = new WorldDamageScope(MatchWorldProtection.Capture((Component)(object)__instance, ___m_owner)); } private static Exception? Finalizer(Exception? __exception, WorldDamageScope? __state) { __state?.Dispose(); return __exception; } } [HarmonyPatch] internal static class MatchAoeScopePatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[3] { "OnHit", "CustomFixedUpdate", "Initiate" }; foreach (string text in array) { yield return AccessTools.Method(typeof(Aoe), text, (Type[])null, (Type[])null); } } private static void Prefix(Aoe __instance, Character ___m_owner, out WorldDamageScope __state) { __state = new WorldDamageScope(MatchWorldProtection.Capture((Component)(object)__instance, ___m_owner)); } private static Exception? Finalizer(Exception? __exception, WorldDamageScope? __state) { __state?.Dispose(); return __exception; } } [HarmonyPatch(typeof(TerrainOp), "Awake")] internal static class MatchTerrainOperationPatch { private static bool Prefix(TerrainOp __instance) { if (!WorldDamageScope.Active) { return true; } Object.Destroy((Object)(object)((Component)__instance).gameObject); return false; } } [HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")] internal static class MatchTerrainSpawnPatch { private static bool Prefix(GameObject __1, Character __2, ref GameObject __result) { if (!WorldDamageScope.Active && !MatchWorldProtection.Fighter(__2)) { return true; } if (!Object.op_Implicit((Object)(object)__1.GetComponentInChildren<TerrainModifier>(true)) && !Object.op_Implicit((Object)(object)__1.GetComponentInChildren<TerrainOp>(true))) { return true; } __result = null; return false; } } internal static class MigrationData { internal const string PreviousPluginId = "local.valheim.friendlypvp"; internal const string PreviousRed = "FriendlyPvP_RavenPole"; internal const string PreviousBlue = "FriendlyPvP_AxesPole"; internal const string PreviousTable = "FriendlyPvP_RoundTable"; internal const string PreviousAttackStamp = "FriendlyPvP.matchAttack"; private const string PreviousSelection = "FriendlyPvP.pole."; internal const string SelectionPrefix = "ValhallaDuels.pole."; internal static bool ImportConfig(string oldPath, string newPath) { if (File.Exists(newPath) || !File.Exists(oldPath)) { return false; } File.Copy(oldPath, newPath, overwrite: false); return true; } internal static bool ReadSelection(IDictionary<string, string> data, string world, out string value) { string key = "ValhallaDuels.pole." + world; string key2 = "FriendlyPvP.pole." + world; if (data.TryGetValue(key, out value)) { data.Remove(key2); return true; } if (!data.TryGetValue(key2, out value)) { return false; } data[key] = value; data.Remove(key2); return true; } internal static void ClearSelection(IDictionary<string, string> data, string world) { data.Remove("ValhallaDuels.pole." + world); data.Remove("FriendlyPvP.pole." + world); } } [BepInPlugin("local.valheim.valhalladuels", "Valhalla Duels", "0.3.7")] [BepInDependency("com.jotunn.jotunn", "2.30.2")] [BepInIncompatibility("local.valheim.friendlypvp")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Id = "local.valheim.valhalladuels"; public const string ModVersion = "0.3.7"; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<bool> KeepInventory; internal static ConfigEntry<bool> KeepFood; internal static ConfigEntry<bool> KeepStatistics; internal static Plugin Instance; internal static ConfigEntry<float> ArenaRadius; internal static ConfigEntry<bool> PreventWear; internal static bool Ready; private Harmony? harmony; private float nextStatus; private bool wasProtected; private Player? statusPlayer; private void Awake() { //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown Instance = this; try { if (MigrationData.ImportConfig(Path.Combine(Paths.ConfigPath, "local.valheim.friendlypvp.cfg"), ((BaseUnityPlugin)this).Config.ConfigFilePath)) { ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Imported settings into the Valhalla Duels config."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Config upgrade failed; Valhalla Duels is not active. " + ex)); ((Behaviour)this).enabled = false; return; } ModEnabled = Synced("General", "Enabled", value: true, "Protect ALL deaths only with PvP enabled inside an arena pole's radius."); KeepInventory = Synced("Protection", "KeepInventory", value: true, "Keep carried items and equipment; do not create a tombstone for a protected death."); KeepFood = Synced("Protection", "KeepFood", value: true, "Keep eaten foods with their remaining durations. Does not refill food timers."); KeepStatistics = Synced("Protection", "KeepDeathStatistics", value: true, "Preserve death counters and consecutive days survived for protected deaths."); PreventWear = Synced("Protection", "PreventEquipmentWear", value: true, "Prevent vanilla equipment durability decreases while PvP is on inside an arena."); ArenaRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Arena", "Radius", 30f, new ConfigDescription("Protection radius in metres around each pole (3D distance). Server controlled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); try { RuntimeHelpers.RunClassConstructor(typeof(DeathScope).TypeHandle); RuntimeHelpers.RunClassConstructor(typeof(ArenaRespawn).TypeHandle); harmony = new Harmony("local.valheim.valhalladuels"); harmony.PatchAll(typeof(Plugin).Assembly); Ready = true; PrefabManager.OnVanillaPrefabsAvailable += PolePrefabs.Register; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Valhalla Duels 0.3.7 loaded: PvP ON + arena radius required. Install on server and all clients with Jotunn. Built for Steam 1.0.21 / 26249040."); } catch (Exception ex2) { Ready = false; Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("Valhalla Duels could not initialize; protection is NOT active. " + ex2)); } } private ConfigEntry<bool> Synced(string section, string key, bool value, string description) { //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_0021: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<bool>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } private void Update() { MatchNetwork.Update(); if (Time.unscaledTime < nextStatus) { return; } nextStatus = Time.unscaledTime + 0.5f; Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead()) { if ((Object)(object)localPlayer != (Object)(object)statusPlayer) { statusPlayer = localPlayer; wasProtected = false; } bool flag = ArenaPole.IsProtected(localPlayer); if (flag != wasProtected) { wasProtected = flag; ((Character)localPlayer).Message((MessageType)2, flag ? "Arena protection ON" : "Arena protection OFF", 0, (Sprite)null, false); } } } private void OnGUI() { MatchOverlay.Draw(); } private void OnDestroy() { Ready = false; PrefabManager.OnVanillaPrefabsAvailable -= PolePrefabs.Register; Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } internal static void Log(string message) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } internal static void Error(string message) { ((BaseUnityPlugin)Instance).Logger.LogError((object)message); } } internal sealed class DeathScope { [ThreadStatic] internal static DeathScope? Current; internal readonly Player Player; internal readonly bool Inventory; internal readonly bool Statistics; internal readonly float TimeSinceDeath; internal readonly List<Food>? Foods; internal static readonly FieldRef<Player, float> DeathTimer = AccessTools.FieldRefAccess<Player, float>("m_timeSinceDeath"); internal DeathScope(Player player) { Player = player; Inventory = Plugin.KeepInventory.Value; Statistics = Plugin.KeepStatistics.Value; TimeSinceDeath = DeathTimer.Invoke(player); if (Plugin.KeepFood.Value) { Foods = new List<Food>(player.GetFoods()); } } internal void Restore() { if (Foods != null) { Player.GetFoods().Clear(); Player.GetFoods().AddRange(Foods); } DeathTimer.Invoke(Player) = TimeSinceDeath; } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class DeathPatch { [HarmonyPriority(800)] private static void Prefix(Player __instance, out DeathScope? __state) { __state = DeathScope.Current; DeathScope.Current = null; if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { MatchNetwork.ReportDeath(__instance); ArenaRespawn.Clear(); if (ArenaPole.IsProtected(__instance)) { DeathScope.Current = new DeathScope(__instance); ArenaRespawn.Capture(__instance); Plugin.Log("Protected arena death (PvP enabled): skills preserved; inventory=" + Plugin.KeepInventory.Value + "; food=" + Plugin.KeepFood.Value); } } } [HarmonyPriority(0)] private static void Finalizer(DeathScope? __state) { try { DeathScope.Current?.Restore(); } finally { DeathScope.Current = __state; } } } [HarmonyPatch(typeof(Player), "CreateTombStone")] internal static class TombstonePatch { private static bool Prefix(Player __instance) { if (DeathScope.Current != null && !((Object)(object)DeathScope.Current.Player != (Object)(object)__instance)) { return !DeathScope.Current.Inventory; } return true; } } [HarmonyPatch(typeof(Skills), "OnDeath")] internal static class SkillDrainPatch { private static bool Prefix(Skills __instance) { if (DeathScope.Current != null) {