Decompiled source of Erenshor COOP v1.0.5
ErenshorCoop/ErenshorCoop.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Timers; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ErenshorCoop.Client; using ErenshorCoop.Server; using ErenshorCoop.Shared; using ErenshorCoop.Shared.Packets; using ErenshorCoop.UI; using HarmonyLib; using LiteNetLib; using LiteNetLib.Layers; using LiteNetLib.Utils; using TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ErenshorCoop")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ErenshorCoop")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("060ca869-6710-4c26-a2d8-63572e58569b")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace ErenshorCoop { public class CommandHandler { public static void CreateHooks(Harmony harm) { ErenshorCoopMod.CreatePrefixHook(typeof(TypeText), "CheckCommands", typeof(CommandHandler), "CheckCommands_Prefix"); } public static bool CheckCommands_Prefix(TypeText __instance) { string text = __instance.typed.text; if (string.IsNullOrEmpty(text)) { return true; } if (text.StartsWith("/")) { string[] array = text.Substring(1).Split(new char[1] { ' ' }); string text2 = array[0].ToLower(); int result = 0; switch (text2) { case "host": if (array.Length < 2) { Logging.LogError("Not enough arguments for \"host\". Usage: /host port"); return false; } if (!int.TryParse(array[1], out result)) { Logging.LogError("Could not parse port. (" + array[2] + ")"); } else if (ServerConnectionManager.Instance.StartHost(result)) { ClientConnectionManager.Instance.Connect("localhost", result); } return false; case "connect": { if (array.Length == 1) { ClientConnectionManager.Instance.Connect("localhost", 1234); return false; } if (array.Length < 3) { Logging.LogError("Not enough arguments for \"connect\". Usage: /connect ip port"); return false; } string text3 = array[1]; if (text3 != "localhost" && !IPAddress.TryParse(text3, out IPAddress _)) { Logging.LogError(text3 + " is not a valid IP Address."); return false; } if (!int.TryParse(array[2], out result)) { Logging.LogError("Could not parse port. (" + array[2] + ")"); } else { ClientConnectionManager.Instance.Connect(text3, result); } return false; } case "disconnect": ClientConnectionManager.Instance?.Disconnect(); ServerConnectionManager.Instance?.Disconnect(); return false; } } return true; } } [BepInPlugin("mizuki.coop", "Erenshor Coop", "1.0.5")] public class ErenshorCoopMod : BaseUnityPlugin { public struct PluginData { public string name; public Version version; } public static ConfigEntry<int> someConfig; public static float mobSyncDistance = 40f; public static Action<Scene> OnGameMapLoad; public static Action<Scene> OnGameMenuLoad; public static SceneChange sceneChange; public static ManualLogSource logger; private static Harmony harm; public static Main ModMain; public static List<PluginData> loadedPlugins = new List<PluginData>(); public static Version version; public void Awake() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) version = ((BaseUnityPlugin)this).Info.Metadata.Version; logger = ((BaseUnityPlugin)this).Logger; SceneManager.sceneLoaded += OnSceneLoaded; OnGameMapLoad = (Action<Scene>)Delegate.Combine(OnGameMapLoad, new Action<Scene>(OnGameLoad)); OnGameMenuLoad = (Action<Scene>)Delegate.Combine(OnGameMenuLoad, new Action<Scene>(OnMenuLoad)); GameObject val = new GameObject("Erenshor Coop"); val.transform.SetParent(((Component)this).transform); ClientConfig.Load(((BaseUnityPlugin)this).Config); ServerConfig.Load(((BaseUnityPlugin)this).Config); val.AddComponent<ClientConnectionManager>(); val.AddComponent<ServerConnectionManager>(); val.AddComponent<ClientNPCSyncManager>(); val.AddComponent<SharedNPCSyncManager>(); ModMain = new GameObject("CoopUI").AddComponent<Main>(); ((Component)ModMain).transform.SetParent(val.transform); EnableHooks(); GetLoadedPlugins(); SceneManager.GetActiveScene(); if ((Object)(object)sceneChange == (Object)null) { sceneChange = Object.FindObjectOfType<SceneChange>(); } if ((Object)(object)sceneChange == (Object)null) { return; } if ((Object)(object)sceneChange.Player != (Object)null && (Object)(object)ClientConnectionManager.Instance.LocalPlayer != (Object)null) { PlayerSync component = ((Component)sceneChange.Player).GetComponent<PlayerSync>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } } else if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer == (Object)null) { ClientConnectionManager.Instance.LocalPlayer = ((Component)sceneChange.Player).gameObject.AddComponent<PlayerSync>(); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; harm.UnpatchSelf(); } private void GetLoadedPlugins() { loadedPlugins.Clear(); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { PluginData pluginData = default(PluginData); pluginData.name = value.Metadata.Name; pluginData.version = value.Metadata.Version; PluginData item = pluginData; loadedPlugins.Add(item); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded Mods: {item.name} v{item.version}"); } } private void OnMenuLoad(Scene scene) { if (!((Object)(object)ClientConnectionManager.Instance == (Object)null) && !((Object)(object)ClientConnectionManager.Instance.LocalPlayer == (Object)null) && !((Object)(object)sceneChange.Player == (Object)null)) { Object.Destroy((Object)(object)ClientConnectionManager.Instance.LocalPlayer); ClientConnectionManager.Instance.LocalPlayer = null; } } private void OnGameLoad(Scene scene) { if ((Object)(object)sceneChange == (Object)null) { sceneChange = Object.FindObjectOfType<SceneChange>(); } if (!((Object)(object)sceneChange == (Object)null)) { if ((Object)(object)sceneChange.Player != (Object)null && (Object)(object)ClientConnectionManager.Instance.LocalPlayer == (Object)null) { ClientConnectionManager.Instance.LocalPlayer = ((Component)sceneChange.Player).gameObject.AddComponent<PlayerSync>(); } else if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer == (Object)null) { Logging.LogError("Could not find Player object. Try changing scenes?"); } } } public void Update() { PacketManager.ExtremePoolNoodleAction(); } public void EnableHooks() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown harm = new Harmony("mizuki.coop"); GameHooks.CreateHooks(harm); CommandHandler.CreateHooks(harm); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0030: 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) if (((Scene)(ref scene)).name == "LoadScene" || ((Scene)(ref scene)).name == "Menu") { OnGameMenuLoad?.Invoke(scene); } else { OnGameMapLoad?.Invoke(scene); } } public static void CreatePrefixHook(Type origType, string origName, Type newType, string newName) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown try { HarmonyMethod val = new HarmonyMethod(AccessTools.Method(newType, newName, (Type[])null, (Type[])null)); MethodInfo methodInfo = AccessTools.Method(origType, origName, (Type[])null, (Type[])null); harm.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { } } public static void CreatePostHook(Type origType, string origName, Type newType, string newName) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown try { HarmonyMethod val = new HarmonyMethod(AccessTools.Method(newType, newName, (Type[])null, (Type[])null)); MethodInfo methodInfo = AccessTools.Method(origType, origName, (Type[])null, (Type[])null); harm.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { } } public static void CreatePrefixHook(Type origType, string origName, Type newType, string newName, Type[] paramTypes) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown try { HarmonyMethod val = new HarmonyMethod(AccessTools.Method(newType, newName, (Type[])null, (Type[])null)); MethodInfo methodInfo = AccessTools.Method(origType, origName, paramTypes, (Type[])null); harm.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { } } public static void UnPatchTranspiler(Type origType, string origName, Type newType, string newName) { try { MethodInfo methodInfo = AccessTools.Method(origType, origName, (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(newType, newName, (Type[])null, (Type[])null); harm.Unpatch((MethodBase)methodInfo, methodInfo2); } catch { } } public static void CreateTranspilerHook(Type origType, string origName, Type newType, string newName, Type[] paramTypes) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(origType, origName, paramTypes, (Type[])null); HarmonyMethod val = new HarmonyMethod(AccessTools.Method(newType, newName, (Type[])null, (Type[])null)); harm.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); } catch { } } public static void CreateTranspilerHook(Type origType, string origName, Type newType, string newName) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(origType, origName, (Type[])null, (Type[])null); HarmonyMethod val = new HarmonyMethod(AccessTools.Method(newType, newName, (Type[])null, (Type[])null)); harm.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); } catch { } } public static Class ClassID2Class(byte _class) { return (Class)(_class switch { 0 => GameData.ClassDB.Warrior, 1 => GameData.ClassDB.Druid, 2 => GameData.ClassDB.Duelist, 3 => GameData.ClassDB.Arcanist, _ => null, }); } public static byte Class2ClassID(Class _class) { if ((Object)(object)_class == (Object)(object)GameData.ClassDB.Warrior) { return 0; } if ((Object)(object)_class == (Object)(object)GameData.ClassDB.Druid) { return 1; } if ((Object)(object)_class == (Object)(object)GameData.ClassDB.Duelist) { return 2; } if ((Object)(object)_class == (Object)(object)GameData.ClassDB.Arcanist) { return 3; } return byte.MaxValue; } } public class GameHooks { private static FieldInfo _actualSpawn; private static List<GameObject> fightSpawnList = new List<GameObject>(); private static List<string> fightSpawnListID = new List<string>(); private static FieldInfo _malarothSpawn; private static FieldInfo _chessSpawn; private static bool isMalaroth = false; private static byte chessSpawn = 0; private static bool hasWardOne = false; private static bool hasWardTwo = false; private static bool hasWardThree = false; private static int insertions = 0; public static FieldInfo targ; public static FieldInfo SpellSource; public static FieldInfo xpBonus; public static FieldInfo lastTyped; public static FieldInfo spawnPoint; public static MethodInfo startMethod; public static MethodInfo handleNameTag; public static FieldInfo rotTimer; public static FieldInfo leashing; private static FieldInfo thisZoning; public static FieldInfo hideHair; public static FieldInfo hideHead; public static MethodInfo GetTransformNames; public static FieldInfo animatorController; public static void CreateHooks(Harmony harm) { ErenshorCoopMod.CreatePrefixHook(typeof(Animator), "SetBool", typeof(GameHooks), "SetBool_Prefix", new Type[2] { typeof(string), typeof(bool) }); ErenshorCoopMod.CreatePrefixHook(typeof(Animator), "SetFloat", typeof(GameHooks), "SetFloat_Prefix", new Type[2] { typeof(string), typeof(float) }); ErenshorCoopMod.CreatePrefixHook(typeof(Animator), "SetInteger", typeof(GameHooks), "SetInteger_Prefix", new Type[2] { typeof(string), typeof(int) }); ErenshorCoopMod.CreatePrefixHook(typeof(Animator), "SetTrigger", typeof(GameHooks), "SetTrigger_Prefix", new Type[1] { typeof(string) }); ErenshorCoopMod.CreatePrefixHook(typeof(Animator), "ResetTrigger", typeof(GameHooks), "ResetTrigger_Prefix", new Type[1] { typeof(string) }); ErenshorCoopMod.CreatePrefixHook(typeof(AnimatorOverrideController), "set_Item", typeof(GameHooks), "AnimOverrideSet_Prefix", new Type[2] { typeof(string), typeof(AnimationClip) }); ErenshorCoopMod.CreatePrefixHook(typeof(Zoneline), "OnTriggerEnter", typeof(GameHooks), "ZoneLineOnTriggerEnter_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(NPC), "Update", typeof(GameHooks), "NPCUpdate_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(NPC), "Combat", typeof(GameHooks), "NPCCombat_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(TypeText), "CheckInput", typeof(GameHooks), "CheckInput_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "ReduceHP", typeof(GameHooks), "StatsReduceHP_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "MitigatePhysical", typeof(GameHooks), "StatsMitigatePhysical_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Character), "DamageMe", typeof(GameHooks), "CharacterDamageMe_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Character), "MagicDamageMe", typeof(GameHooks), "MagicDamageMe_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Character), "CheckVsMR", typeof(GameHooks), "CheckVsMR_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerGrouping), "InviteToGroup", typeof(GameHooks), "InviteToGroup_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerGrouping), "DismissMember1", typeof(GameHooks), "DismissMember1_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerGrouping), "DismissMember2", typeof(GameHooks), "DismissMember2_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerGrouping), "DismissMember3", typeof(GameHooks), "DismissMember3_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerTracking), "SpawnMeInGame", typeof(GameHooks), "SpawnMeInGame_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SpellVessel), "CreateSpellChargeEffect", typeof(GameHooks), "ChargeEffect_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SpellVessel), "EndSpell", typeof(GameHooks), "EndSpell_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SpellVessel), "EndSpellNoCD", typeof(GameHooks), "EndSpell_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SpellVessel), "ResolveSpell", typeof(GameHooks), "ResolveSpell_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerMngr), "BringPlayerGroupToZone", typeof(GameHooks), "BringGroup_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(GameData), "AddExperience", typeof(GameHooks), "AddExperience_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "AddStatusEffect", typeof(GameHooks), "AddStatusEffectType1_Prefix", new Type[3] { typeof(Spell), typeof(bool), typeof(int) }); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "AddStatusEffect", typeof(GameHooks), "AddStatusEffectType2_Prefix", new Type[4] { typeof(Spell), typeof(bool), typeof(int), typeof(Character) }); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "AddStatusEffect", typeof(GameHooks), "AddStatusEffectType3_Prefix", new Type[5] { typeof(Spell), typeof(bool), typeof(int), typeof(Character), typeof(float) }); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "RemoveStatusEffect", typeof(GameHooks), "RemoveStatusEffect_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "RemoveAllStatusEffects", typeof(GameHooks), "RemoveAllStatusEffects_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Stats), "RemoveBreakableEffects", typeof(GameHooks), "RemoveBreakableEffects_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(MalarothFeed), "CheckForGamepiece", typeof(GameHooks), "MCheckForGamepiece_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(MalarothFeed), "SpawnPiece", typeof(GameHooks), "MSpawnPiece_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Chessboard), "CheckForGamepiece", typeof(GameHooks), "CCheckForGamepiece_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(Chessboard), "SpawnPiece", typeof(GameHooks), "CSpawnPiece_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SiraetheEvent), "Update", typeof(GameHooks), "SUpdate_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(NPCFightEvent), "FixedUpdate", typeof(GameHooks), "FightFixedUpdate_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(CharmedNPC), "GoAway", typeof(GameHooks), "CharmedGoAway_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SimPlayerMngr), "CollectActiveSimData", typeof(GameHooks), "CollectActiveSimData_Prefix"); ErenshorCoopMod.CreatePrefixHook(typeof(SceneChange), "ChangeScene", typeof(GameHooks), "ChangeScene_Prefix"); ErenshorCoopMod.CreatePostHook(typeof(SpawnPoint), "SpawnNPC", typeof(GameHooks), "SpawnPointSpawnNPC_Post"); ErenshorCoopMod.CreatePostHook(typeof(Character), "DamageMe", typeof(GameHooks), "CharacterDamageMe_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(Character), "MagicDamageMe", typeof(GameHooks), "MagicDamageMe_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(Respawn), "RespawnPlayer", typeof(GameHooks), "RespawnPlayer_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(SimPlayerGrouping), "InviteToGroup", typeof(GameHooks), "InviteToGroup_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(GameManager), "OpenEscMenu", typeof(GameHooks), "OpenEscMenu_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(GameManager), "CloseEscMenu", typeof(GameHooks), "CloseEscMenu_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(GameManager), "ToggleEscapeMenu", typeof(GameHooks), "ToggleEscMenu_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(MalarothFeed), "SpawnPiece", typeof(GameHooks), "MSpawnPiece_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(Chessboard), "SpawnPiece", typeof(GameHooks), "CSpawnPiece_Postfix"); ErenshorCoopMod.CreatePostHook(typeof(SiraetheEvent), "Update", typeof(GameHooks), "SUpdate_Postfix"); try { ErenshorCoopMod.UnPatchTranspiler(typeof(SpellVessel), "ResolveSpell", typeof(GameHooks), "ResolveSpellTranspiler"); } catch { } ErenshorCoopMod.CreateTranspilerHook(typeof(SpellVessel), "ResolveSpell", typeof(GameHooks), "ResolveSpellTranspiler"); if (insertions < 10) { Logging.LogError("There was an issue resolving healing\nPlease Update to the newest mod version or wait\nuntil a new version has been released.\nHealing might not work, continue at your own risk."); } Type typeFromHandle = typeof(ModularParts); hideHair = typeFromHandle.GetField("hideHair", BindingFlags.Instance | BindingFlags.NonPublic); hideHead = typeFromHandle.GetField("hideHead", BindingFlags.Instance | BindingFlags.NonPublic); GetTransformNames = typeFromHandle.GetMethod("GetTransformNames", BindingFlags.Instance | BindingFlags.NonPublic); lastTyped = typeof(TypeText).GetField("lastTyped", BindingFlags.Instance | BindingFlags.NonPublic); Type typeFromHandle2 = typeof(NPC); animatorController = typeFromHandle2.GetField("AnimOverride", BindingFlags.Instance | BindingFlags.NonPublic); spawnPoint = typeFromHandle2.GetField("MySpawnPoint", BindingFlags.Instance | BindingFlags.NonPublic); rotTimer = typeFromHandle2.GetField("rotTimer", BindingFlags.Instance | BindingFlags.NonPublic); startMethod = typeFromHandle2.GetMethod("Start", BindingFlags.Instance | BindingFlags.NonPublic); handleNameTag = typeFromHandle2.GetMethod("HandleNameTag", BindingFlags.Instance | BindingFlags.NonPublic); leashing = typeFromHandle2.GetField("spawnCD", BindingFlags.Instance | BindingFlags.NonPublic); Type typeFromHandle3 = typeof(SpellVessel); targ = typeFromHandle3.GetField("targ", BindingFlags.Instance | BindingFlags.NonPublic); SpellSource = typeFromHandle3.GetField("SpellSource", BindingFlags.Instance | BindingFlags.NonPublic); thisZoning = typeof(Zoneline).GetField("thisZoning", BindingFlags.Instance | BindingFlags.NonPublic); xpBonus = typeof(Stats).GetField("XPBonus", BindingFlags.Instance | BindingFlags.NonPublic); _malarothSpawn = typeof(MalarothFeed).GetField("Spawned", BindingFlags.Instance | BindingFlags.NonPublic); _chessSpawn = typeof(Chessboard).GetField("Spawned", BindingFlags.Instance | BindingFlags.NonPublic); _actualSpawn = typeof(NPCFightEvent).GetField("actualSpawn", BindingFlags.Instance | BindingFlags.NonPublic); } public static bool CollectActiveSimData_Prefix(SimPlayerMngr __instance) { return true; } public static bool ChangeScene_Prefix(SceneChange __instance, string _dest, Vector3 _landing, bool _useSun, float yRot) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if (!ClientConnectionManager.Instance.IsRunning) { return true; } if (ClientConnectionManager.Instance.LocalPlayer.currentScene == _dest) { GameData.SimPlayerGrouping.GroupTargets.Clear(); GameData.SimPlayerGrouping.isPulling = false; GameData.AttackingPlayer.Clear(); GameData.InCombat = false; GameData.GroupMatesInCombat.Clear(); ((Component)GameData.PlayerControl).GetComponent<Fishing>().resetFishing(); GameData.PlayerControl.HuntingMe.Clear(); ((Collider)((Component)__instance.Player).GetComponent<CharacterController>()).enabled = false; GameData.CharmedNPC = null; __instance.SetLandingPos(_landing); ((Component)__instance.Player).transform.position = _landing; ((Collider)((Component)__instance.Player).GetComponent<CharacterController>()).enabled = true; ((Behaviour)((Component)__instance.Player).GetComponent<PlayerControl>()).enabled = true; GameData.usingSun = _useSun; ((Component)__instance.Player).transform.eulerAngles = new Vector3(0f, yRot, 0f); InZoneEvents.ClearNodes(); GameData.Zoning = false; return false; } return true; } public static NetworkedPlayer CreatePlayer(int playerID, Vector3 pos, Quaternion rot) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00c4: 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) List<GameObject> actualSims = GameData.SimMngr.ActualSims; if (actualSims.Count == 0) { Logging.LogError($"Could not create player for {playerID}. No Sim instances."); return null; } GameObject val = actualSims[0]; if ((Object)(object)val == (Object)null) { Logging.LogError($"Could not create player for {playerID}. No Sim."); return null; } GameObject val2 = Object.Instantiate<GameObject>(val.gameObject, pos, rot); val2.SetActive(false); SimPlayer component = val2.GetComponent<SimPlayer>(); if ((Object)(object)component == (Object)null) { Logging.LogError($"Could not create player for {playerID}."); return null; } ((Behaviour)component).enabled = false; NavMeshAgent component2 = val2.GetComponent<NavMeshAgent>(); if ((Object)(object)component2 != (Object)null) { ((Behaviour)component2).enabled = false; } NetworkedPlayer networkedPlayer = val2.AddComponent<NetworkedPlayer>(); networkedPlayer.sim = component; networkedPlayer.pos = pos; networkedPlayer.rot = rot; return networkedPlayer; } public static void CharmedGoAway_Prefix(CharmedNPC __instance) { if (ClientConnectionManager.Instance.IsRunning && GameData.PlayerControl.Myself.MyCharmedNPC.SummonedByPlayer) { ClientConnectionManager.Instance.LocalPlayer.DespawnSummon(); } } public static bool FightFixedUpdate_Prefix(NPCFightEvent __instance) { //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: 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_0303: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) if (!ClientConnectionManager.Instance.IsRunning) { return true; } if (!ClientZoneOwnership.isZoneOwner) { return true; } bool flag = false; if ((Object)(object)__instance.MyNPC.CurrentAggroTarget != (Object)null && __instance.MyStats.Myself.Alive) { if (__instance.PercentagesToSpawn.Count > 0 && (float)__instance.MyStats.CurrentHP / (float)__instance.MyStats.CurrentMaxHP * 100f < __instance.PercentagesToSpawn[0]) { UpdateSocialLog.LogAdd(__instance.PromptOnSpawn, "orange"); __instance.PercentagesToSpawn.RemoveAt(0); int num = 0; foreach (GameObject spawnAdd in __instance.SpawnAdds) { GameObject item = Object.Instantiate<GameObject>(spawnAdd, ((Component)__instance).transform.position + new Vector3((float)Random.Range(-11, 11), 0f, (float)Random.Range(-11, 11)), ((Component)__instance).transform.rotation); fightSpawnList.Add(item); fightSpawnListID.Add($"1,{num}"); num++; } flag = true; } if (__instance.SpawnAddsEveryXSeconds > 0f) { float num2 = (float)_actualSpawn.GetValue(__instance); if (num2 > 0f) { _actualSpawn.SetValue(__instance, num2 - 1f); } else { UpdateSocialLog.LogAdd(__instance.PromptOnSpawn, "orange"); int num3 = 0; foreach (GameObject spawnAdd2 in __instance.SpawnAdds) { GameObject item2 = Object.Instantiate<GameObject>(spawnAdd2, ((Component)__instance).transform.position + new Vector3((float)Random.Range(-11, 11), 0f, (float)Random.Range(-11, 11)), ((Component)__instance).transform.rotation); fightSpawnList.Add(item2); fightSpawnListID.Add($"2,{num3}"); num3++; } _actualSpawn.SetValue(__instance, __instance.SpawnAddsEveryXSeconds * 60f); flag = true; } } } if (__instance.SpawnOnDeath.Count > 0 && !__instance.MyStats.Myself.Alive) { int num4 = 0; foreach (GameObject item4 in __instance.SpawnOnDeath) { Vector3 position = ((Component)__instance).transform.position; Vector3 localScale = ((Component)__instance).transform.localScale; float num5 = 0f - ((Vector3)(ref localScale)).magnitude; localScale = ((Component)__instance).transform.localScale; float num6 = Random.Range(num5, ((Vector3)(ref localScale)).magnitude); localScale = ((Component)__instance).transform.localScale; float num7 = 0f - ((Vector3)(ref localScale)).magnitude; localScale = ((Component)__instance).transform.localScale; GameObject item3 = Object.Instantiate<GameObject>(item4, position + new Vector3(num6, 0f, Random.Range(num7, ((Vector3)(ref localScale)).magnitude)), ((Component)__instance).transform.rotation); fightSpawnList.Add(item3); fightSpawnListID.Add($"3,{num4}"); num4++; } __instance.SpawnOnDeath.Clear(); UpdateSocialLog.LogAdd(__instance.PromptOnSpawn, "orange"); if (__instance.InstantDespawn) { __instance.MyStats.Myself.MyNPC.ExpediteRot(); } flag = true; } if (fightSpawnList.Count > 0) { SharedNPCSyncManager.Instance.ServerSpawnMobs(fightSpawnList, fightSpawnListID, -4, __instance.MyNPC); fightSpawnList.Clear(); fightSpawnListID.Clear(); } return !flag; } public static bool MCheckForGamepiece_Prefix() { if (ClientConnectionManager.Instance.IsRunning && !ClientZoneOwnership.isZoneOwner) { return false; } return true; } public static bool CCheckForGamepiece_Prefix() { if (ClientConnectionManager.Instance.IsRunning && !ClientZoneOwnership.isZoneOwner) { return false; } return true; } public static bool SUpdate_Prefix() { if (ClientConnectionManager.Instance.IsRunning && !ClientZoneOwnership.isZoneOwner) { hasWardOne = false; hasWardTwo = false; hasWardThree = false; return false; } return true; } public static void MSpawnPiece_Prefix(MalarothFeed __instance, GameObject _npc) { if (ClientConnectionManager.Instance.IsRunning) { isMalaroth = (Object)(object)_npc == (Object)(object)__instance.Malaroth; } } public static void CSpawnPiece_Prefix(Chessboard __instance, GameObject _npc) { if (ClientConnectionManager.Instance.IsRunning) { if ((Object)(object)_npc == (Object)(object)__instance.PeonNPC) { chessSpawn = 1; } if ((Object)(object)_npc == (Object)(object)__instance.EmberNPC) { chessSpawn = 2; } if ((Object)(object)_npc == (Object)(object)__instance.BlazeNPC) { chessSpawn = 3; } if ((Object)(object)_npc == (Object)(object)__instance.MonarchNPC) { chessSpawn = 4; } if ((Object)(object)_npc == (Object)(object)__instance.KingsmanNPC) { chessSpawn = 5; } if ((Object)(object)_npc == (Object)(object)__instance.CandlekeeperNPC) { chessSpawn = 6; } if ((Object)(object)_npc == (Object)(object)__instance.FacelessDuel) { chessSpawn = 7; } if ((Object)(object)_npc == (Object)(object)__instance.FacelessArc) { chessSpawn = 8; } if ((Object)(object)_npc == (Object)(object)__instance.FacelessPal) { chessSpawn = 9; } if ((Object)(object)_npc == (Object)(object)__instance.FacelessDru) { chessSpawn = 10; } } } public static void MSpawnPiece_Postfix(MalarothFeed __instance, GameObject _npc) { //IL_003f: 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) if (ClientConnectionManager.Instance.IsRunning) { object? value = _malarothSpawn.GetValue(__instance); Character val = (Character)((value is Character) ? value : null); if ((Object)(object)val != (Object)null) { SharedNPCSyncManager.Instance.ServerSpawnMob(((Component)val).gameObject, -1, 0, isMalaroth, ((Component)val).transform.position, ((Component)val).transform.rotation); } } } public static void CSpawnPiece_Postfix(Chessboard __instance, GameObject _npc) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (ClientConnectionManager.Instance.IsRunning) { object? value = _chessSpawn.GetValue(__instance); Character val = (Character)((value is Character) ? value : null); if ((Object)(object)val != (Object)null) { SharedNPCSyncManager.Instance.ServerSpawnMob(((Component)val).gameObject, -2, chessSpawn, isRare: false, ((Component)val).transform.position, ((Component)val).transform.rotation); } } } public static void SUpdate_Postfix(SiraetheEvent __instance) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_012b: Unknown result type (might be due to invalid IL or missing references) if (ClientConnectionManager.Instance.IsRunning && ClientZoneOwnership.isZoneOwner) { if ((Object)(object)__instance.WardOne != (Object)null && !hasWardOne) { SharedNPCSyncManager.Instance.ServerSpawnMob(__instance.WardOne, -3, 1, isRare: false, __instance.WardOne.transform.position, __instance.WardOne.transform.rotation); hasWardOne = true; } else if ((Object)(object)__instance.WardOne == (Object)null && hasWardOne) { hasWardOne = false; } if ((Object)(object)__instance.WardTwo != (Object)null && !hasWardTwo) { SharedNPCSyncManager.Instance.ServerSpawnMob(__instance.WardTwo, -3, 2, isRare: false, __instance.WardTwo.transform.position, __instance.WardTwo.transform.rotation); hasWardTwo = true; } else if ((Object)(object)__instance.WardTwo == (Object)null && hasWardTwo) { hasWardTwo = false; } if ((Object)(object)__instance.WardThree != (Object)null && !hasWardThree) { SharedNPCSyncManager.Instance.ServerSpawnMob(__instance.WardThree, -3, 3, isRare: false, __instance.WardThree.transform.position, __instance.WardThree.transform.rotation); hasWardThree = true; } else if ((Object)(object)__instance.WardThree == (Object)null && hasWardThree) { hasWardThree = false; } } } public static IEnumerable<CodeInstruction> ResolveSpellTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Expected O, but got Unknown //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Expected O, but got Unknown //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Expected O, but got Unknown //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Expected O, but got Unknown //IL_0569: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Expected O, but got Unknown //IL_0594: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Expected O, but got Unknown //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Expected O, but got Unknown //IL_05dd: Unknown result type (might be due to invalid IL or missing references) //IL_05e7: Expected O, but got Unknown //IL_05f5: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Expected O, but got Unknown //IL_0613: Unknown result type (might be due to invalid IL or missing references) //IL_061d: Expected O, but got Unknown //IL_062b: Unknown result type (might be due to invalid IL or missing references) //IL_0635: Expected O, but got Unknown //IL_0656: Unknown result type (might be due to invalid IL or missing references) //IL_0660: Expected O, but got Unknown //IL_066e: Unknown result type (might be due to invalid IL or missing references) //IL_0678: Expected O, but got Unknown //IL_0686: Unknown result type (might be due to invalid IL or missing references) //IL_0690: Expected O, but got Unknown //IL_06b7: Unknown result type (might be due to invalid IL or missing references) //IL_06c1: Expected O, but got Unknown List<CodeInstruction> codes2 = new List<CodeInstruction>(instructions); Label item = default(Label); Label item2 = default(Label); for (int j = 0; j < codes2.Count; j++) { if (codes2[j].opcode == OpCodes.Switch && codes2[j].operand is Label[] array) { item = array[6]; item2 = array[7]; } codes2[j].labels.Contains(item); codes2[j].labels.Contains(item2); bool flag = codes2[j].operand is FieldInfo; FieldInfo fieldInfo = codes2[j].operand as FieldInfo; if (j - 7 >= 0 && codes2[j].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentHP" && fieldInfo.DeclaringType == typeof(Stats) && codes2[j - 7].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes2[j - 7].operand).LocalIndex == 18) { int num = j + 1; codes2.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "targ"))); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldloc_S, (object)16)); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldloc_S, (object)17)); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "SpellSource"))); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); codes2.Insert(num++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); MethodInfo methodInfo = AccessTools.Method(typeof(GameHooks), "SyncHealing", (Type[])null, (Type[])null); codes2.Insert(num++, new CodeInstruction(OpCodes.Call, (object)methodInfo)); insertions++; j = num - 1; } if (codes2.Count >= j + 1 && codes2[j].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentHP" && fieldInfo.DeclaringType == typeof(Stats) && codes2[j + 1].opcode == OpCodes.Ldsfld) { FieldInfo fieldInfo2 = codes2[j + 1].operand as FieldInfo; if (fieldInfo2 != null && fieldInfo2.Name == "GroupMember1" && fieldInfo2.DeclaringType == typeof(GameData)) { InsertSyncHealingCalls(codes2, ref j, j + 1, fieldInfo2.Name); } if (fieldInfo2 != null && fieldInfo2.Name == "GroupMember2" && fieldInfo2.DeclaringType == typeof(GameData)) { InsertSyncHealingCalls(codes2, ref j, j + 1, fieldInfo2.Name); } if (fieldInfo2 != null && fieldInfo2.Name == "GroupMember3" && fieldInfo2.DeclaringType == typeof(GameData)) { InsertSyncHealingCalls(codes2, ref j, j + 1, fieldInfo2.Name); } } if (codes2.Count >= j + 4 && codes2[j].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentHP" && fieldInfo.DeclaringType == typeof(Stats) && codes2[j + 4].opcode == OpCodes.Ldfld) { FieldInfo fieldInfo3 = codes2[j + 4].operand as FieldInfo; if (fieldInfo3 != null && fieldInfo3.Name == "MyCharmedNPC") { _ = fieldInfo3.DeclaringType == typeof(Character); } } if (codes2.Count >= j + 1 && codes2[j].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentHP" && fieldInfo.DeclaringType == typeof(Stats) && codes2[j + 1].opcode == OpCodes.Ldloc_S) { int num2 = j + 1; codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldloc_S, (object)22)); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Character), "MyStats"))); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldloc_S, (object)17)); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "SpellSource"))); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldc_I4_1, (object)null)); codes2.Insert(num2++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); MethodInfo methodInfo2 = AccessTools.Method(typeof(GameHooks), "SyncHealing", (Type[])null, (Type[])null); codes2.Insert(num2++, new CodeInstruction(OpCodes.Call, (object)methodInfo2)); insertions++; j = num2 - 1; } DoMPCalls(ref codes2, ref j); } return codes2.AsEnumerable(); static void InsertSyncHealingCalls(List<CodeInstruction> codes, ref int i, int insertAt, string groupMemberName) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(GameData), groupMemberName))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SimPlayerTracking), "MyStats"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldloc_S, (object)17)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "SpellSource"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldc_I4_1, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); MethodInfo methodInfo3 = AccessTools.Method(typeof(GameHooks), "SyncHealing", (Type[])null, (Type[])null); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Call, (object)methodInfo3)); i = insertAt - 1; insertions++; } } private static void DoMPCalls(ref List<CodeInstruction> codes, ref int i) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Expected O, but got Unknown //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Expected O, but got Unknown //IL_0580: Unknown result type (might be due to invalid IL or missing references) //IL_058a: Expected O, but got Unknown //IL_059f: Unknown result type (might be due to invalid IL or missing references) //IL_05a9: Expected O, but got Unknown //IL_05cb: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Expected O, but got Unknown //IL_05e4: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Expected O, but got Unknown //IL_0610: Unknown result type (might be due to invalid IL or missing references) //IL_061a: Expected O, but got Unknown //IL_063c: Unknown result type (might be due to invalid IL or missing references) //IL_0646: Expected O, but got Unknown //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_0663: Expected O, but got Unknown //IL_0672: Unknown result type (might be due to invalid IL or missing references) //IL_067c: Expected O, but got Unknown //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Expected O, but got Unknown //IL_06b7: Unknown result type (might be due to invalid IL or missing references) //IL_06c1: Expected O, but got Unknown //IL_06d0: Unknown result type (might be due to invalid IL or missing references) //IL_06da: Expected O, but got Unknown //IL_0702: Unknown result type (might be due to invalid IL or missing references) //IL_070c: Expected O, but got Unknown bool flag = codes[i].operand is FieldInfo; FieldInfo fieldInfo = codes[i].operand as FieldInfo; if (codes.Count >= i + 3 && codes[i].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentMana" && fieldInfo.DeclaringType == typeof(Stats)) { FieldInfo fieldInfo2 = codes[i + 3].operand as FieldInfo; if (fieldInfo2 != null && fieldInfo2.DeclaringType == typeof(Spell) && fieldInfo2.Name == "GroupEffect") { int num = i + 1; codes.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "targ"))); codes.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Spell), "Mana"))); codes.Insert(num++, new CodeInstruction(OpCodes.Ldstr, (object)"")); codes.Insert(num++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "SpellSource"))); codes.Insert(num++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); codes.Insert(num++, new CodeInstruction(OpCodes.Ldc_I4_1, (object)null)); MethodInfo methodInfo = AccessTools.Method(typeof(GameHooks), "SyncHealing", (Type[])null, (Type[])null); codes.Insert(num++, new CodeInstruction(OpCodes.Call, (object)methodInfo)); insertions++; i = num - 1; } } if (codes.Count >= i + 1 && codes[i].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentMana" && fieldInfo.DeclaringType == typeof(Stats) && codes[i + 1].opcode == OpCodes.Ldsfld) { FieldInfo fieldInfo3 = codes[i + 1].operand as FieldInfo; if (fieldInfo3 != null && fieldInfo3.Name == "GroupMember1" && fieldInfo3.DeclaringType == typeof(GameData)) { InsertSyncHealingCalls(codes, ref i, i + 1, fieldInfo3.Name); } if (fieldInfo3 != null && fieldInfo3.Name == "GroupMember2" && fieldInfo3.DeclaringType == typeof(GameData)) { InsertSyncHealingCalls(codes, ref i, i + 1, fieldInfo3.Name); } if (fieldInfo3 != null && fieldInfo3.Name == "GroupMember3" && fieldInfo3.DeclaringType == typeof(GameData)) { InsertSyncHealingCalls(codes, ref i, i + 1, fieldInfo3.Name); } } if (codes.Count >= i + 4 && codes[i].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentMana" && fieldInfo.DeclaringType == typeof(Stats) && codes[i + 4].opcode == OpCodes.Ldfld) { FieldInfo fieldInfo4 = codes[i + 4].operand as FieldInfo; if (fieldInfo4 != null && fieldInfo4.Name == "MyCharmedNPC") { _ = fieldInfo4.DeclaringType == typeof(Character); } } if (codes.Count >= i + 1 && codes[i].opcode == OpCodes.Stfld && flag && fieldInfo.Name == "CurrentMana" && fieldInfo.DeclaringType == typeof(Stats) && codes[i + 1].opcode == OpCodes.Ldloc_S) { int num2 = i + 1; codes.Insert(num2++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldloc_S, (object)23)); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Character), "MyStats"))); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Spell), "Mana"))); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldstr, (object)"")); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "SpellSource"))); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); codes.Insert(num2++, new CodeInstruction(OpCodes.Ldc_I4_1, (object)null)); MethodInfo methodInfo2 = AccessTools.Method(typeof(GameHooks), "SyncHealing", (Type[])null, (Type[])null); codes.Insert(num2++, new CodeInstruction(OpCodes.Call, (object)methodInfo2)); insertions++; i = num2 - 1; } static void InsertSyncHealingCalls(List<CodeInstruction> codes, ref int i, int insertAt, string groupMemberName) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(GameData), groupMemberName))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SimPlayerTracking), "MyStats"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "spell"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Spell), "Mana"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldstr, (object)"")); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SpellVessel), "SpellSource"))); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldc_I4_0, (object)null)); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Ldc_I4_1, (object)null)); MethodInfo methodInfo3 = AccessTools.Method(typeof(GameHooks), "SyncHealing", (Type[])null, (Type[])null); codes.Insert(insertAt++, new CodeInstruction(OpCodes.Call, (object)methodInfo3)); i = insertAt - 1; insertions++; } } public static void SyncHealing(Spell spell, Stats target, int amount, string text, CastSpell caster, bool calc, bool isMP) { if (!ClientConnectionManager.Instance.IsRunning) { return; } var (flag, flag2, num) = GetEntityIDByCharacter(caster.MyChar); if (num == -1) { Logging.Log("no caster? " + ((Object)caster).name); return; } if (!flag && ((flag2 && !ServerConnectionManager.Instance.IsRunning) || (!flag2 && !ClientZoneOwnership.isZoneOwner))) { Logging.Log($"er {flag} {flag2} {num}"); return; } if (flag && num != ClientConnectionManager.Instance.LocalPlayerID) { Logging.Log("er NoLocalPlayer"); return; } if (amount == 0 && !isMP) { amount = spell.HP + caster.MyChar.MyStats.CharacterClass.WisBenefit / 100 * caster.MyChar.MyStats.GetCurrentWis(); } var (flag3, flag4, num2) = GetEntityIDByCharacter(target.Myself); if (num2 == -1) { Logging.Log($"no target {flag3} {flag4} {num2} {((Object)target).name}"); return; } bool isCrit = !isMP && text.Contains("CRITICAL"); HealingData healingData = default(HealingData); healingData.amount = amount; healingData.isCrit = isCrit; healingData.isMP = isMP; healingData.targetID = num2; healingData.targetIsNPC = !flag3 && !flag4; healingData.targetIsSim = flag4; HealingData hd = healingData; if (!flag) { ((NPCSync)SharedNPCSyncManager.Instance.GetEntityFromID(num, flag2)).SendHeal(hd); } else { ClientConnectionManager.Instance.LocalPlayer.SendHeal(hd); } } public static void OpenEscMenu_Postfix() { Main.isGameMenuOpen = true; if ((Object)(object)Main.connectUI != (Object)null) { Main.connectUI.SetActive(true); } } public static void CloseEscMenu_Postfix() { Main.isGameMenuOpen = false; if ((Object)(object)Main.connectUI != (Object)null) { Main.connectUI.SetActive(false); } } public static void ToggleEscMenu_Postfix(GameManager __instance) { Main.isGameMenuOpen = __instance.EscapeMenu.activeSelf; if ((Object)(object)Main.connectUI != (Object)null) { Main.connectUI.SetActive(Main.isGameMenuOpen); } } public static bool AddExperience_Prefix(int xp, bool useMod) { if (!ClientConnectionManager.Instance.IsRunning) { return true; } if (Grouping.currentGroup.groupList == null || Grouping.currentGroup.groupList.Count <= 1) { return true; } if (Grouping.currentGroup.groupList.Count > 1) { if (Grouping.IsLocalLeader()) { float num = (float)xpBonus.GetValue(GameData.PlayerStats); if (!ServerConnectionManager.Instance.IsRunning) { PacketManager.GetOrCreatePacket<GroupPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.GROUP).AddPacketData(GroupDataType.EXPERIENCE, "xp", xp).SetData("xpBonus", num) .SetData("useMod", useMod); } else { Grouping.ServerHandleXP(ClientConnectionManager.Instance.LocalPlayerID, xp, useMod, num); } return false; } return false; } return true; } public static bool BringGroup_Prefix(SimPlayerMngr __instance) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_0107: 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_0126: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) if (!ClientConnectionManager.Instance.IsRunning) { return true; } if (!ServerConnectionManager.Instance.IsRunning) { return false; } Scene activeScene; if (GameData.GroupMember1 != null && GameData.GroupMember1.simIndex >= 0) { __instance.ActiveSimInstances.Add(GameData.GroupMember1.SpawnMeInGame(((Component)GameData.PlayerControl).transform.position + new Vector3((float)Random.Range(-1, 1), 0f, (float)Random.Range(-1, 1)))); GameData.GroupMember1.MyAvatar.InGroup = true; GameData.GroupMember1.isPuller = false; GameData.GroupMember1.Caution = false; SimPlayerTracking groupMember = GameData.GroupMember1; activeScene = SceneManager.GetActiveScene(); groupMember.CurScene = ((Scene)(ref activeScene)).name; List<string> simsInZones = __instance.SimsInZones; int simIndex = GameData.GroupMember1.simIndex; activeScene = SceneManager.GetActiveScene(); simsInZones[simIndex] = ((Scene)(ref activeScene)).name; } if (GameData.GroupMember2 != null && GameData.GroupMember2.simIndex >= 0) { __instance.ActiveSimInstances.Add(GameData.GroupMember2.SpawnMeInGame(((Component)GameData.PlayerControl).transform.position + new Vector3((float)Random.Range(-1, 1), 0f, (float)Random.Range(-1, 1)))); GameData.GroupMember2.MyAvatar.InGroup = true; GameData.GroupMember2.isPuller = false; GameData.GroupMember2.Caution = false; SimPlayerTracking groupMember2 = GameData.GroupMember2; activeScene = SceneManager.GetActiveScene(); groupMember2.CurScene = ((Scene)(ref activeScene)).name; List<string> simsInZones2 = __instance.SimsInZones; int simIndex2 = GameData.GroupMember2.simIndex; activeScene = SceneManager.GetActiveScene(); simsInZones2[simIndex2] = ((Scene)(ref activeScene)).name; } if (GameData.GroupMember3 != null && GameData.GroupMember3.simIndex >= 0) { __instance.ActiveSimInstances.Add(GameData.GroupMember3.SpawnMeInGame(((Component)GameData.PlayerControl).transform.position + new Vector3((float)Random.Range(-1, 1), 0f, (float)Random.Range(-1, 1)))); GameData.GroupMember3.MyAvatar.InGroup = true; GameData.GroupMember3.isPuller = false; GameData.GroupMember3.Caution = false; SimPlayerTracking groupMember3 = GameData.GroupMember3; activeScene = SceneManager.GetActiveScene(); groupMember3.CurScene = ((Scene)(ref activeScene)).name; List<string> simsInZones3 = __instance.SimsInZones; int simIndex3 = GameData.GroupMember3.simIndex; activeScene = SceneManager.GetActiveScene(); simsInZones3[simIndex3] = ((Scene)(ref activeScene)).name; } return false; } public static void ResolveSpell_Prefix(SpellVessel __instance) { //IL_001c: 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_012d: Expected O, but got Unknown if (!ClientConnectionManager.Instance.IsRunning) { return; } bool flag = true; short num = -1; Character myChar = ((CastSpell)SpellSource.GetValue(__instance)).MyChar; EntityType entityType = EntityType.ENEMY; if ((Object)(object)myChar != (Object)(object)ClientConnectionManager.Instance.LocalPlayer.character) { if (!ServerConnectionManager.Instance.IsRunning) { return; } foreach (KeyValuePair<short, NPCSync> mob in SharedNPCSyncManager.Instance.mobs) { if ((Object)(object)mob.Value.character == (Object)(object)myChar) { flag = false; num = mob.Key; entityType = mob.Value.type; break; } } foreach (KeyValuePair<short, NPCSync> sim in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim.Value.character == (Object)(object)myChar) { flag = false; num = sim.Key; entityType = sim.Value.type; break; } } if (flag) { return; } } Stats val = (Stats)targ.GetValue(__instance); bool targetIsNPC = false; short num2 = -1; bool targetIsSim = false; if (!ClientZoneOwnership.isZoneOwner) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value.character.MyStats == (Object)(object)val) { targetIsNPC = true; num2 = networkedMob.Key; break; } } } else { foreach (KeyValuePair<short, NPCSync> mob2 in SharedNPCSyncManager.Instance.mobs) { if ((Object)(object)mob2.Value.character.MyStats == (Object)(object)val) { targetIsNPC = true; num2 = mob2.Key; break; } } foreach (KeyValuePair<short, NPCSync> sim2 in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim2.Value.character.MyStats == (Object)(object)val) { targetIsNPC = true; num2 = sim2.Key; targetIsSim = true; break; } } } if (num2 == -1) { foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value.sim.MyStats == (Object)(object)val) { num2 = player.Key; break; } } if (num2 == -1 && (Object)(object)val == (Object)(object)ClientConnectionManager.Instance.LocalPlayer.stats) { num2 = ClientConnectionManager.Instance.LocalPlayerID; } } if (num2 == -1) { Logging.Log("no valid target? " + ((Object)val).name); } else if (!flag) { EntityActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<EntityActionPacket>(num, PacketType.ENTITY_ACTION); orCreatePacket.dataTypes.Add(ActionType.SPELL_EFFECT); orCreatePacket.spellID = ((BaseScriptableObject)__instance.spell).Id; orCreatePacket.targetID = num2; orCreatePacket.targetIsNPC = targetIsNPC; orCreatePacket.targetIsSim = targetIsSim; orCreatePacket.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); if (ServerConnectionManager.Instance.IsRunning && SharedNPCSyncManager.Instance.sims.ContainsKey(num)) { entityType = EntityType.SIM; } orCreatePacket.entityType = entityType; } else { PlayerActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket2.dataTypes.Add(ActionType.SPELL_EFFECT); orCreatePacket2.spellID = ((BaseScriptableObject)__instance.spell).Id; orCreatePacket2.targetID = num2; orCreatePacket2.targetIsNPC = targetIsNPC; orCreatePacket2.targetIsSim = targetIsSim; } } public static void EndSpell_Prefix(SpellVessel __instance) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Invalid comparison between Unknown and I4 //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Invalid comparison between Unknown and I4 if (!ClientConnectionManager.Instance.IsRunning) { return; } bool flag = true; short num = -1; Character myChar = ((CastSpell)SpellSource.GetValue(__instance)).MyChar; EntityType entityType = EntityType.ENEMY; if ((Object)(object)myChar != (Object)(object)ClientConnectionManager.Instance.LocalPlayer.character) { if (!ClientZoneOwnership.isZoneOwner) { return; } foreach (KeyValuePair<short, NPCSync> mob in SharedNPCSyncManager.Instance.mobs) { if ((Object)(object)mob.Value.character == (Object)(object)myChar) { flag = false; num = mob.Key; entityType = mob.Value.type; break; } } foreach (KeyValuePair<short, NPCSync> sim in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim.Value.character == (Object)(object)myChar) { flag = false; num = sim.Key; entityType = sim.Value.type; break; } } if (flag) { return; } } if (flag) { PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION).dataTypes.Add(ActionType.SPELL_END); if ((int)__instance.spell.Type == 7 && (Object)(object)myChar.MyCharmedNPC != (Object)null) { ClientConnectionManager.Instance.LocalPlayer.CreateSummon(__instance.spell, ((Component)myChar.MyCharmedNPC).gameObject); } return; } EntityActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<EntityActionPacket>(num, PacketType.ENTITY_ACTION); orCreatePacket.dataTypes.Add(ActionType.SPELL_END); orCreatePacket.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); if (ServerConnectionManager.Instance.IsRunning && SharedNPCSyncManager.Instance.sims.ContainsKey(num)) { entityType = EntityType.SIM; } if ((int)__instance.spell.Type == 7 && (Object)(object)myChar.MyCharmedNPC != (Object)null) { GetEntityByCharacter(myChar).CreateSummon(__instance.spell, ((Component)myChar.MyCharmedNPC).gameObject); } orCreatePacket.entityType = entityType; } public static void ChargeEffect_Prefix(SpellVessel __instance, Spell _spell, Transform _caster, Stats _target, CastSpell _source, float _castTime, bool _useMana, bool _resonate) { if (!ClientConnectionManager.Instance.IsRunning) { return; } bool flag = true; short num = -1; Character myChar = _source.MyChar; EntityType entityType = EntityType.ENEMY; if ((Object)(object)myChar != (Object)(object)ClientConnectionManager.Instance.LocalPlayer.character) { if (!ClientZoneOwnership.isZoneOwner) { return; } foreach (KeyValuePair<short, NPCSync> mob in SharedNPCSyncManager.Instance.mobs) { if ((Object)(object)mob.Value.character == (Object)(object)myChar) { flag = false; num = mob.Key; entityType = mob.Value.type; break; } } foreach (KeyValuePair<short, NPCSync> sim in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim.Value.character == (Object)(object)myChar) { flag = false; num = sim.Key; entityType = sim.Value.type; break; } } if (flag) { return; } } if (flag) { PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.SPELL_CHARGE); orCreatePacket.SpellChargeFXIndex = _spell.SpellChargeFXIndex; return; } EntityActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<EntityActionPacket>(num, PacketType.ENTITY_ACTION); orCreatePacket2.dataTypes.Add(ActionType.SPELL_CHARGE); orCreatePacket2.SpellChargeFXIndex = _spell.SpellChargeFXIndex; orCreatePacket2.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); if (ServerConnectionManager.Instance.IsRunning && SharedNPCSyncManager.Instance.sims.ContainsKey(num)) { entityType = EntityType.SIM; } orCreatePacket2.entityType = entityType; } public static bool SpawnMeInGame_Prefix(SimPlayerTracking __instance) { if (__instance.simIndex < 0) { return false; } return true; } public static bool DismissMember1_Prefix(SimPlayerGrouping __instance) { if (ClientConnectionManager.Instance.IsRunning && GameData.GroupMember1 != null && (Object)(object)GameData.GroupMember1.MyAvatar != (Object)null && GameData.GroupMember1.simIndex < 0) { int num = Math.Abs(GameData.GroupMember1.simIndex) - 1; Entity playerFromID = ClientConnectionManager.Instance.GetPlayerFromID((short)num); if ((Object)(object)playerFromID != (Object)null && (Object)(object)((NetworkedPlayer)playerFromID).sim.MyStats == (Object)(object)GameData.GroupMember1.MyStats) { Grouping.RemoveFromGroup((short)num); return false; } } if (ServerConnectionManager.Instance.IsRunning && GameData.GroupMember1 != null && (Object)(object)GameData.GroupMember1.MyAvatar != (Object)null && GameData.GroupMember1.simIndex >= 0) { NPCSync component = ((Component)GameData.GroupMember1.MyAvatar).GetComponent<NPCSync>(); if ((Object)(object)component != (Object)null) { SharedNPCSyncManager.Instance.ServerRemoveSim(component.entityID); Grouping.RemoveSim(GameData.GroupMember1); } } return true; } public static bool DismissMember2_Prefix(SimPlayerGrouping __instance) { if (ClientConnectionManager.Instance.IsRunning && GameData.GroupMember2 != null && (Object)(object)GameData.GroupMember2.MyAvatar != (Object)null && GameData.GroupMember2.simIndex < 0) { int num = Math.Abs(GameData.GroupMember2.simIndex) - 1; Entity playerFromID = ClientConnectionManager.Instance.GetPlayerFromID((short)num); if ((Object)(object)playerFromID != (Object)null && (Object)(object)((NetworkedPlayer)playerFromID).sim.MyStats == (Object)(object)GameData.GroupMember2.MyStats) { Grouping.RemoveFromGroup((short)num); return false; } } if (ServerConnectionManager.Instance.IsRunning && GameData.GroupMember2 != null && (Object)(object)GameData.GroupMember2.MyAvatar != (Object)null && GameData.GroupMember2.simIndex >= 0) { NPCSync component = ((Component)GameData.GroupMember2.MyAvatar).GetComponent<NPCSync>(); if ((Object)(object)component != (Object)null) { SharedNPCSyncManager.Instance.ServerRemoveSim(component.entityID); Grouping.RemoveSim(GameData.GroupMember2); } } return true; } public static bool DismissMember3_Prefix(SimPlayerGrouping __instance) { if (ClientConnectionManager.Instance.IsRunning && GameData.GroupMember3 != null && (Object)(object)GameData.GroupMember3.MyAvatar != (Object)null && GameData.GroupMember3.simIndex < 0) { int num = Math.Abs(GameData.GroupMember3.simIndex) - 1; Entity playerFromID = ClientConnectionManager.Instance.GetPlayerFromID((short)num); if ((Object)(object)playerFromID != (Object)null && (Object)(object)((NetworkedPlayer)playerFromID).sim.MyStats == (Object)(object)GameData.GroupMember3.MyStats) { Grouping.RemoveFromGroup((short)num); return false; } } if (ServerConnectionManager.Instance.IsRunning && GameData.GroupMember3 != null && (Object)(object)GameData.GroupMember3.MyAvatar != (Object)null && GameData.GroupMember3.simIndex >= 0) { NPCSync component = ((Component)GameData.GroupMember3.MyAvatar).GetComponent<NPCSync>(); if ((Object)(object)component != (Object)null) { SharedNPCSyncManager.Instance.ServerRemoveSim(component.entityID); Grouping.RemoveSim(GameData.GroupMember3); } } return true; } public static void InviteToGroup_Postfix(SimPlayerGrouping __instance) { if (ServerConnectionManager.Instance.IsRunning) { if (GameData.GroupMember1 != null && GameData.GroupMember1.simIndex >= 0) { Grouping.InviteSim(GameData.GroupMember1); } if (GameData.GroupMember2 != null && GameData.GroupMember2.simIndex >= 0) { Grouping.InviteSim(GameData.GroupMember2); } if (GameData.GroupMember3 != null && GameData.GroupMember3.simIndex >= 0) { Grouping.InviteSim(GameData.GroupMember3); } } } public static bool InviteToGroup_Prefix(SimPlayerGrouping __instance) { if (ClientConnectionManager.Instance.IsRunning) { Character currentTarget = GameData.PlayerControl.CurrentTarget; NetworkedPlayer networkedPlayer = null; if ((Object)(object)currentTarget != (Object)null && (Object)(object)(networkedPlayer = ((Component)currentTarget).GetComponent<NetworkedPlayer>()) != (Object)null) { if (!GameData.PlayerControl.Myself.Alive) { return true; } Grouping.InvitePlayer(networkedPlayer); return false; } if ((Object)(object)currentTarget != (Object)null && !ServerConnectionManager.Instance.IsRunning) { Logging.LogGameMessage("[Grouping] Only the host can invite sims."); return false; } } return true; } public static void RespawnPlayer_Postfix() { if (ClientConnectionManager.Instance.IsRunning) { PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION).dataTypes.Add(ActionType.REVIVE); } } public static bool MiscGenPopup_Prefix(int _dmg, bool _crit, DamageType _type, Transform _tar) { //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) if (ClientConnectionManager.Instance.IsRunning) { Debug.Log((object)$"{_dmg} {_crit} {_type} {_tar.position}"); } return true; } private static (bool, bool, short) GetEntityIDByCharacter(Character _char) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value.character == (Object)(object)_char) { return (false, false, networkedMob.Value.entityID); } } foreach (KeyValuePair<short, NetworkedNPC> networkedSim in ClientNPCSyncManager.Instance.NetworkedSims) { if ((Object)(object)networkedSim.Value.character == (Object)(object)_char) { return (false, true, networkedSim.Value.entityID); } } foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value.character == (Object)(object)_char) { return (true, false, player.Value.entityID); } } if (ServerConnectionManager.Instance.IsRunning) { foreach (KeyValuePair<short, NPCSync> sim in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim.Value.character == (Object)(object)_char) { return (false, true, sim.Value.entityID); } } } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.character == (Object)(object)_char) { return (true, false, ClientConnectionManager.Instance.LocalPlayerID); } return (false, false, -1); } public static Entity GetEntityByCharacter(Character _char) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value.character == (Object)(object)_char) { return networkedMob.Value; } } foreach (KeyValuePair<short, NetworkedNPC> networkedSim in ClientNPCSyncManager.Instance.NetworkedSims) { if ((Object)(object)networkedSim.Value.character == (Object)(object)_char) { return networkedSim.Value; } } foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value.character == (Object)(object)_char) { return player.Value; } } if (ServerConnectionManager.Instance.IsRunning) { foreach (KeyValuePair<short, NPCSync> sim in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim.Value.character == (Object)(object)_char) { return sim.Value; } } } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.character == (Object)(object)_char) { return ClientConnectionManager.Instance.LocalPlayer; } return null; } private static (bool, bool, short) GetEntityIDByStats(Stats _char) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value.character.MyStats == (Object)(object)_char) { return (false, false, networkedMob.Value.entityID); } } foreach (KeyValuePair<short, NetworkedNPC> networkedSim in ClientNPCSyncManager.Instance.NetworkedSims) { if ((Object)(object)networkedSim.Value.character.MyStats == (Object)(object)_char) { return (false, true, networkedSim.Value.entityID); } } foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value.character.MyStats == (Object)(object)_char) { return (true, false, player.Value.entityID); } } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.character.MyStats == (Object)(object)_char) { return (true, false, ClientConnectionManager.Instance.LocalPlayerID); } return (false, false, -1); } private static Entity GetEntityByStats(Stats _char) { if (!ClientZoneOwnership.isZoneOwner) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value.character.MyStats == (Object)(object)_char) { return networkedMob.Value; } } foreach (KeyValuePair<short, NetworkedNPC> networkedSim in ClientNPCSyncManager.Instance.NetworkedSims) { if ((Object)(object)networkedSim.Value.character.MyStats == (Object)(object)_char) { return networkedSim.Value; } } } else { foreach (KeyValuePair<short, NPCSync> mob in SharedNPCSyncManager.Instance.mobs) { if ((Object)(object)mob.Value.character.MyStats == (Object)(object)_char) { return mob.Value; } } foreach (KeyValuePair<short, NPCSync> sim in SharedNPCSyncManager.Instance.sims) { if ((Object)(object)sim.Value.character.MyStats == (Object)(object)_char) { return sim.Value; } } } foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value.character.MyStats == (Object)(object)_char) { return player.Value; } } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.character.MyStats == (Object)(object)_char) { return ClientConnectionManager.Instance.LocalPlayer; } return null; } public static void AddStatusEffectType1_Prefix(Stats __instance, Spell spell, bool _fromPlayer, int _dmgBonus) { if (ClientConnectionManager.Instance.IsRunning && (Object)(object)ClientConnectionManager.Instance.LocalPlayer.stats == (Object)(object)__instance && !Variables.DontCheckEffectCharacters.Contains(ClientConnectionManager.Instance.LocalPlayer)) { string id = ((BaseScriptableObject)spell).Id; PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket.effectData = new StatusEffectData { spellID = id, damageBonus = _dmgBonus, targetID = -1, duration = -1f }; if (id == "83280423440") { Logging.Log("StatusEffectData 1:\n- spellID: " + orCreatePacket.effectData.spellID + "\n" + $"- damageBonus: {orCreatePacket.effectData.damageBonus}\n" + $"- attackerIsPlayer: {orCreatePacket.effectData.casterType}\n" + $"- attackerID: {orCreatePacket.effectData.casterID}\n" + $"- duration: {orCreatePacket.effectData.duration}\n"); } } } public static void AddStatusEffectType2_Prefix(Stats __instance, Spell spell, bool _fromPlayer, int _dmgBonus, Character _specificCaster) { if (!ClientConnectionManager.Instance.IsRunning) { return; } Entity entityByStats = GetEntityByStats(__instance); Entity entityByCharacter = GetEntityByCharacter(_specificCaster); if ((Object)(object)entityByStats == (Object)null || (Object)(object)entityByCharacter == (Object)null || Variables.DontCheckEffectCharacters.Contains(entityByStats)) { return; } if ((Object)(object)entityByStats == (Object)(object)ClientConnectionManager.Instance.LocalPlayer && (Object)(object)entityByCharacter == (Object)(object)ClientConnectionManager.Instance.LocalPlayer) { string id = ((BaseScriptableObject)spell).Id; PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket.effectData = new StatusEffectData { spellID = id, damageBonus = _dmgBonus, casterType = EntityType.PLAYER, targetID = -2, duration = -1f }; if (id == "83280423440") { Logging.Log("StatusEffectData 2:\n- spellID: " + orCreatePacket.effectData.spellID + "\n" + $"- damageBonus: {orCreatePacket.effectData.damageBonus}\n" + $"- attackerIsPlayer: {orCreatePacket.effectData.casterType}\n" + $"- attackerID: {orCreatePacket.effectData.casterID}\n" + $"- duration: {orCreatePacket.effectData.duration}\n"); } } else if ((Object)(object)entityByCharacter == (Object)(object)ClientConnectionManager.Instance.LocalPlayer) { string id2 = ((BaseScriptableObject)spell).Id; PlayerActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket2.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket2.effectData = new StatusEffectData { spellID = id2, damageBonus = _dmgBonus, casterType = EntityType.PLAYER, casterID = entityByCharacter.entityID, duration = -1f, targetID = entityByStats.entityID, targetType = entityByStats.type }; } else if (ClientZoneOwnership.isZoneOwner) { string id3 = ((BaseScriptableObject)spell).Id; EntityActionPacket orCreatePacket3 = PacketManager.GetOrCreatePacket<EntityActionPacket>(entityByCharacter.entityID, PacketType.ENTITY_ACTION); orCreatePacket3.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket3.effectData = new StatusEffectData { spellID = id3, damageBonus = _dmgBonus, casterType = entityByCharacter.type, casterID = entityByCharacter.entityID, duration = -1f, targetID = entityByStats.entityID, targetType = entityByStats.type }; orCreatePacket3.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); } } public static void AddStatusEffectType3_Prefix(Stats __instance, Spell spell, bool _fromPlayer, int _dmgBonus, Character _specificCaster, float _duration) { if (!ClientConnectionManager.Instance.IsRunning) { return; } Entity entityByStats = GetEntityByStats(__instance); Entity entityByCharacter = GetEntityByCharacter(_specificCaster); if ((Object)(object)entityByStats == (Object)null || (Object)(object)entityByCharacter == (Object)null || Variables.DontCheckEffectCharacters.Contains(entityByStats)) { return; } if ((Object)(object)entityByStats == (Object)(object)ClientConnectionManager.Instance.LocalPlayer && (Object)(object)entityByCharacter == (Object)(object)ClientConnectionManager.Instance.LocalPlayer) { string id = ((BaseScriptableObject)spell).Id; PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket.effectData = new StatusEffectData { spellID = id, damageBonus = _dmgBonus, casterType = EntityType.PLAYER, targetID = -3, duration = _duration }; if (id == "83280423440") { Logging.Log("StatusEffectData 3:\n- spellID: " + orCreatePacket.effectData.spellID + "\n" + $"- damageBonus: {orCreatePacket.effectData.damageBonus}\n" + $"- attackerIsPlayer: {orCreatePacket.effectData.casterType}\n" + $"- attackerID: {orCreatePacket.effectData.casterID}\n" + $"- duration: {orCreatePacket.effectData.duration}\n"); } } else if ((Object)(object)entityByCharacter == (Object)(object)ClientConnectionManager.Instance.LocalPlayer) { string id2 = ((BaseScriptableObject)spell).Id; PlayerActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket2.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket2.effectData = new StatusEffectData { spellID = id2, damageBonus = _dmgBonus, casterType = EntityType.PLAYER, casterID = entityByCharacter.entityID, duration = _duration, targetID = entityByStats.entityID, targetType = entityByStats.type }; } else if (ClientZoneOwnership.isZoneOwner) { string id3 = ((BaseScriptableObject)spell).Id; EntityActionPacket orCreatePacket3 = PacketManager.GetOrCreatePacket<EntityActionPacket>(entityByCharacter.entityID, PacketType.ENTITY_ACTION); orCreatePacket3.dataTypes.Add(ActionType.STATUS_EFFECT_APPLY); orCreatePacket3.effectData = new StatusEffectData { spellID = id3, damageBonus = _dmgBonus, casterType = entityByCharacter.type, casterID = entityByCharacter.entityID, duration = _duration, targetID = entityByStats.entityID, targetType = entityByStats.type }; orCreatePacket3.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); } } public static void RemoveStatusEffect_Prefix(Stats __instance, int index) { if (!ClientConnectionManager.Instance.IsRunning) { return; } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.stats == (Object)(object)__instance) { PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.STATUS_EFFECT_REMOVE); orCreatePacket.statusID = index; } else if (ClientZoneOwnership.isZoneOwner) { Entity entityByStats = GetEntityByStats(__instance); if (!((Object)(object)entityByStats == (Object)null)) { EntityActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<EntityActionPacket>(entityByStats.entityID, PacketType.ENTITY_ACTION); orCreatePacket2.dataTypes.Add(ActionType.STATUS_EFFECT_REMOVE); orCreatePacket2.statusID = index; orCreatePacket2.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); } } } public static void RemoveAllStatusEffects_Prefix(Stats __instance) { if (!ClientConnectionManager.Instance.IsRunning) { return; } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.stats == (Object)(object)__instance) { PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.STATUS_EFFECT_REMOVE); orCreatePacket.RemoveAllStatus = true; } else if (ClientZoneOwnership.isZoneOwner) { Entity entityByStats = GetEntityByStats(__instance); if (!((Object)(object)entityByStats == (Object)null)) { EntityActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<EntityActionPacket>(entityByStats.entityID, PacketType.ENTITY_ACTION); orCreatePacket2.dataTypes.Add(ActionType.STATUS_EFFECT_REMOVE); orCreatePacket2.RemoveAllStatus = true; orCreatePacket2.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); } } } public static void RemoveBreakableEffects_Prefix(Stats __instance) { if (!ClientConnectionManager.Instance.IsRunning) { return; } if ((Object)(object)ClientConnectionManager.Instance.LocalPlayer.stats == (Object)(object)__instance) { PlayerActionPacket orCreatePacket = PacketManager.GetOrCreatePacket<PlayerActionPacket>(ClientConnectionManager.Instance.LocalPlayerID, PacketType.PLAYER_ACTION); orCreatePacket.dataTypes.Add(ActionType.STATUS_EFFECT_REMOVE); orCreatePacket.RemoveBreakable = true; } else if (ClientZoneOwnership.isZoneOwner) { Entity entityByStats = GetEntityByStats(__instance); if (!((Object)(object)entityByStats == (Object)null)) { EntityActionPacket orCreatePacket2 = PacketManager.GetOrCreatePacket<EntityActionPacket>(entityByStats.entityID, PacketType.ENTITY_ACTION); orCreatePacket2.dataTypes.Add(ActionType.STATUS_EFFECT_REMOVE); orCreatePacket2.RemoveBreakable = true; orCreatePacket2.targetPlayerIDs = SharedNPCSyncManager.Instance.GetPlayerSendList(); } } } public static bool StatsMitigatePhysical_Prefix(Stats __instance, ref int __result, int _incomingDmg) { Character component = ((Component)__instance).gameObject.GetComponent<Character>(); if ((Object)(object)component == (Object)null) { return true; } if (Variables.DontCalculateDamageMitigationCharacters.Contains(component)) { __result = _incomingDmg; return false; } return true; } public static bool StatsReduceHP_Prefix(Stats __instance, ref bool __result, int _dmg, DamageType _dmgType) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) if (!ClientZoneOwnership.isZoneOwner && ClientConnectionManager.Instance.IsRunning) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value.character.MyStats == (Object)(object)__instance) { GameData.Misc.GenPopup(_dmg, false, _dmgType, ((Component)__instance).transform); __result = __instance.CurrentHP <= 0; return false; } } foreach (KeyValuePair<short, NetworkedNPC> networkedSim in ClientNPCSyncManager.Instance.NetworkedSims) { if ((Object)(object)networkedSim.Value.character.MyStats == (Object)(object)__instance) { GameData.Misc.GenPopup(_dmg, false, _dmgType, ((Component)__instance).transform); __result = __instance.CurrentHP <= 0; return false; } } foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value.character.MyStats == (Object)(object)__instance) { GameData.Misc.GenPopup(_dmg, false, _dmgType, ((Component)__instance).transform); __result = __instance.CurrentHP <= 0; return false; } } } return true; } public static bool CheckVsMR_Prefix(Character __instance, ref float __result) { if (Variables.DontCalculateDamageMitigationCharacters.Contains(__instance)) { __result = 0f; return false; } return true; } private static void SyncDamage(Character attackedChar, int __result, DamageType _dmgType, Character _attacker, bool _animEffect, float resistMod) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) NPCSync component = ((Component)attackedChar).GetComponent<NPCSync>(); PlayerSync component2 = ((Component)attackedChar).GetComponent<PlayerSync>(); NetworkedPlayer component3 = ((Component)attackedChar).GetComponent<NetworkedPlayer>(); NetworkedNPC component4 = ((Component)attackedChar).GetComponent<NetworkedNPC>(); if ((Object)(object)_attacker == (Object)null) { Logging.LogError("no attacker"); return; } NPCSync component5 = ((Component)_attacker).GetComponent<NPCSync>(); bool flag = (Object)(object)component != (Object)null; bool flag2 = (Object)(object)component2 != (Object)null; bool flag3 = (Object)(object)component3 != (Object)null; bool flag4 = (Object)(object)component4 != (Object)null; if ((Object)(object)component5 != (Object)null && (flag || flag2 || flag3 || flag4)) { if (flag) { component5.SendAttack(__result, component.entityID, attackerNPC: true, _dmgType, _animEffect, resistMod); } else if (flag3) { component5.SendAttack(__result, component3.playerID, attackerNPC: false, _dmgType, _animEffect, resistMod); } else if (flag2) { component5.SendAttack(__result, ClientConnectionManager.Instance.LocalPlayerID, attackerNPC: false, _dmgType, _animEffect, resistMod); } else if (flag4) { component5.SendAttack(__result, component4.entityID, attackerNPC: true, _dmgType, _animEffect, resistMod); } } } private static void SyncDamageClient(Character attackedChar, int damage, DamageType _dmgType, Character _attacker, bool _animEffect, float resistMod) { //IL_0164: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_attacker == (Object)null) { return; } NetworkedNPC component = ((Component)attackedChar).GetComponent<NetworkedNPC>(); NetworkedPlayer component2 = ((Component)attackedChar).GetComponent<NetworkedPlayer>(); NPCSync component3 = ((Component)attackedChar).GetComponent<NPCSync>(); bool flag = (Object)(object)component != (Object)null; bool flag2 = (Object)(object)component2 != (Object)null; bool flag3 = (Object)(object)component3 != (Object)null; if (!flag && !flag2 && !flag3) { return; } short num = -1; bool attackedIsNPC = false; if (flag) { foreach (KeyValuePair<short, NetworkedNPC> networkedMob in ClientNPCSyncManager.Instance.NetworkedMobs) { if ((Object)(object)networkedMob.Value == (Object)(object)component) { num = networkedMob.Key; attackedIsNPC = true; break; } } } else if (flag2) { foreach (KeyValuePair<short, NetworkedPlayer> player in ClientConnectionManager.Instance.Players) { if ((Object)(object)player.Value == (Object)(object)component2) { num = player.Key; break; } } } else if (flag3) { foreach (KeyValuePair<short, NPCSync> mob in SharedNPCSyncManager.Instance.mobs) { if ((Object)(object)mob.Value == (Object)(object)component3) { num = mob.Key; attackedIsNPC = true; break; } } } if (num != -1) { ClientConnectionManager.Instance.LocalPlayer.SendDamageAttack(damage, num, attackedIsNPC, _dmgType, _animEffect, resistMod); } } publ
ErenshorCoop/LiteNetLib.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using LiteNetLib.Layers; using LiteNetLib.Utils; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")] [assembly: AssemblyCompany("Ruslan Pyrch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright 2024 Ruslan Pyrch")] [assembly: AssemblyDescription("Lite reliable UDP library for .NET, Mono, and .NET Core")] [assembly: AssemblyFileVersion("1.3.1")] [assembly: AssemblyInformationalVersion("1.0.0+f57b9eafe72b924681a371d671af911478b6ab88")] [assembly: AssemblyProduct("LiteNetLib")] [assembly: AssemblyTitle("LiteNetLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/RevenantX/LiteNetLib")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.1.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } } namespace LiteNetLib { internal abstract class BaseChannel { protected readonly NetPeer Peer; protected readonly Queue<NetPacket> OutgoingQueue = new Queue<NetPacket>(64); private int _isAddedToPeerChannelSendQueue; public int PacketsInQueue => OutgoingQueue.Count; protected BaseChannel(NetPeer peer) { Peer = peer; } public void AddToQueue(NetPacket packet) { lock (OutgoingQueue) { OutgoingQueue.Enqueue(packet); } AddToPeerChannelSendQueue(); } protected void AddToPeerChannelSendQueue() { if (Interlocked.CompareExchange(ref _isAddedToPeerChannelSendQueue, 1, 0) == 0) { Peer.AddToReliableChannelSendQueue(this); } } public bool SendAndCheckQueue() { bool num = SendNextPackets(); if (!num) { Interlocked.Exchange(ref _isAddedToPeerChannelSendQueue, 0); } return num; } protected abstract bool SendNextPackets(); public abstract bool ProcessPacket(NetPacket packet); } internal enum ConnectionRequestResult { None, Accept, Reject, RejectForce } public class ConnectionRequest { private readonly NetManager _listener; private int _used; internal NetConnectRequestPacket InternalPacket; public readonly IPEndPoint RemoteEndPoint; public NetDataReader Data => InternalPacket.Data; internal ConnectionRequestResult Result { get; private set; } internal void UpdateRequest(NetConnectRequestPacket connectRequest) { if (connectRequest.ConnectionTime >= InternalPacket.ConnectionTime && (connectRequest.ConnectionTime != InternalPacket.ConnectionTime || connectRequest.ConnectionNumber != InternalPacket.ConnectionNumber)) { InternalPacket = connectRequest; } } private bool TryActivate() { return Interlocked.CompareExchange(ref _used, 1, 0) == 0; } internal ConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket, NetManager listener) { InternalPacket = requestPacket; RemoteEndPoint = remoteEndPoint; _listener = listener; } public NetPeer AcceptIfKey(string key) { if (!TryActivate()) { return null; } try { if (Data.GetString() == key) { Result = ConnectionRequestResult.Accept; } } catch { NetDebug.WriteError("[AC] Invalid incoming data"); } if (Result == ConnectionRequestResult.Accept) { return _listener.OnConnectionSolved(this, null, 0, 0); } Result = ConnectionRequestResult.Reject; _listener.OnConnectionSolved(this, null, 0, 0); return null; } public NetPeer Accept() { if (!TryActivate()) { return null; } Result = ConnectionRequestResult.Accept; return _listener.OnConnectionSolved(this, null, 0, 0); } public void Reject(byte[] rejectData, int start, int length, bool force) { if (TryActivate()) { Result = (force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject); _listener.OnConnectionSolved(this, rejectData, start, length); } } public void Reject(byte[] rejectData, int start, int length) { Reject(rejectData, start, length, force: false); } public void RejectForce(byte[] rejectData, int start, int length) { Reject(rejectData, start, length, force: true); } public void RejectForce() { Reject(null, 0, 0, force: true); } public void RejectForce(byte[] rejectData) { Reject(rejectData, 0, rejectData.Length, force: true); } public void RejectForce(NetDataWriter rejectData) { Reject(rejectData.Data, 0, rejectData.Length, force: true); } public void Reject() { Reject(null, 0, 0, force: false); } public void Reject(byte[] rejectData) { Reject(rejectData, 0, rejectData.Length, force: false); } public void Reject(NetDataWriter rejectData) { Reject(rejectData.Data, 0, rejectData.Length, force: false); } } public enum UnconnectedMessageType { BasicMessage, Broadcast } public enum DisconnectReason { ConnectionFailed, Timeout, HostUnreachable, NetworkUnreachable, RemoteConnectionClose, DisconnectPeerCalled, ConnectionRejected, InvalidProtocol, UnknownHost, Reconnect, PeerToPeerConnection, PeerNotFound } public struct DisconnectInfo { public DisconnectReason Reason; public SocketError SocketErrorCode; public NetPacketReader AdditionalData; } public interface INetEventListener { void OnPeerConnected(NetPeer peer); void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); void OnNetworkError(IPEndPoint endPoint, SocketError socketError); void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod); void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); void OnNetworkLatencyUpdate(NetPeer peer, int latency); void OnConnectionRequest(ConnectionRequest request); } public interface IDeliveryEventListener { void OnMessageDelivered(NetPeer peer, object userData); } public interface INtpEventListener { void OnNtpResponse(NtpPacket packet); } public interface IPeerAddressChangedListener { void OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress); } public class EventBasedNetListener : INetEventListener, IDeliveryEventListener, INtpEventListener, IPeerAddressChangedListener { public delegate void OnPeerConnected(NetPeer peer); public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError); public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod); public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency); public delegate void OnConnectionRequest(ConnectionRequest request); public delegate void OnDeliveryEvent(NetPeer peer, object userData); public delegate void OnNtpResponseEvent(NtpPacket packet); public delegate void OnPeerAddressChangedEvent(NetPeer peer, IPEndPoint previousAddress); public event OnPeerConnected PeerConnectedEvent; public event OnPeerDisconnected PeerDisconnectedEvent; public event OnNetworkError NetworkErrorEvent; public event OnNetworkReceive NetworkReceiveEvent; public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent; public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent; public event OnConnectionRequest ConnectionRequestEvent; public event OnDeliveryEvent DeliveryEvent; public event OnNtpResponseEvent NtpResponseEvent; public event OnPeerAddressChangedEvent PeerAddressChangedEvent; public void ClearPeerConnectedEvent() { this.PeerConnectedEvent = null; } public void ClearPeerDisconnectedEvent() { this.PeerDisconnectedEvent = null; } public void ClearNetworkErrorEvent() { this.NetworkErrorEvent = null; } public void ClearNetworkReceiveEvent() { this.NetworkReceiveEvent = null; } public void ClearNetworkReceiveUnconnectedEvent() { this.NetworkReceiveUnconnectedEvent = null; } public void ClearNetworkLatencyUpdateEvent() { this.NetworkLatencyUpdateEvent = null; } public void ClearConnectionRequestEvent() { this.ConnectionRequestEvent = null; } public void ClearDeliveryEvent() { this.DeliveryEvent = null; } public void ClearNtpResponseEvent() { this.NtpResponseEvent = null; } public void ClearPeerAddressChangedEvent() { this.PeerAddressChangedEvent = null; } void INetEventListener.OnPeerConnected(NetPeer peer) { if (this.PeerConnectedEvent != null) { this.PeerConnectedEvent(peer); } } void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) { if (this.PeerDisconnectedEvent != null) { this.PeerDisconnectedEvent(peer, disconnectInfo); } } void INetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode) { if (this.NetworkErrorEvent != null) { this.NetworkErrorEvent(endPoint, socketErrorCode); } } void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod) { if (this.NetworkReceiveEvent != null) { this.NetworkReceiveEvent(peer, reader, channelNumber, deliveryMethod); } } void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType) { if (this.NetworkReceiveUnconnectedEvent != null) { this.NetworkReceiveUnconnectedEvent(remoteEndPoint, reader, messageType); } } void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency) { if (this.NetworkLatencyUpdateEvent != null) { this.NetworkLatencyUpdateEvent(peer, latency); } } void INetEventListener.OnConnectionRequest(ConnectionRequest request) { if (this.ConnectionRequestEvent != null) { this.ConnectionRequestEvent(request); } } void IDeliveryEventListener.OnMessageDelivered(NetPeer peer, object userData) { if (this.DeliveryEvent != null) { this.DeliveryEvent(peer, userData); } } void INtpEventListener.OnNtpResponse(NtpPacket packet) { if (this.NtpResponseEvent != null) { this.NtpResponseEvent(packet); } } void IPeerAddressChangedListener.OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress) { if (this.PeerAddressChangedEvent != null) { this.PeerAddressChangedEvent(peer, previousAddress); } } } internal sealed class NetConnectRequestPacket { public const int HeaderSize = 18; public readonly long ConnectionTime; public byte ConnectionNumber; public readonly byte[] TargetAddress; public readonly NetDataReader Data; public readonly int PeerId; private NetConnectRequestPacket(long connectionTime, byte connectionNumber, int localId, byte[] targetAddress, NetDataReader data) { ConnectionTime = connectionTime; ConnectionNumber = connectionNumber; TargetAddress = targetAddress; Data = data; PeerId = localId; } public static int GetProtocolId(NetPacket packet) { return BitConverter.ToInt32(packet.RawData, 1); } public static NetConnectRequestPacket FromData(NetPacket packet) { if (packet.ConnectionNumber >= 4) { return null; } long connectionTime = BitConverter.ToInt64(packet.RawData, 5); int localId = BitConverter.ToInt32(packet.RawData, 13); int num = packet.RawData[17]; if (num != 16 && num != 28) { return null; } byte[] array = new byte[num]; Buffer.BlockCopy(packet.RawData, 18, array, 0, num); NetDataReader netDataReader = new NetDataReader(null, 0, 0); if (packet.Size > 18 + num) { netDataReader.SetSource(packet.RawData, 18 + num, packet.Size); } return new NetConnectRequestPacket(connectionTime, packet.ConnectionNumber, localId, array, netDataReader); } public static NetPacket Make(NetDataWriter connectData, SocketAddress addressBytes, long connectTime, int localId) { NetPacket netPacket = new NetPacket(PacketProperty.ConnectRequest, connectData.Length + addressBytes.Size); FastBitConverter.GetBytes(netPacket.RawData, 1, 13); FastBitConverter.GetBytes(netPacket.RawData, 5, connectTime); FastBitConverter.GetBytes(netPacket.RawData, 13, localId); netPacket.RawData[17] = (byte)addressBytes.Size; for (int i = 0; i < addressBytes.Size; i++) { netPacket.RawData[18 + i] = addressBytes[i]; } Buffer.BlockCopy(connectData.Data, 0, netPacket.RawData, 18 + addressBytes.Size, connectData.Length); return netPacket; } } internal sealed class NetConnectAcceptPacket { public const int Size = 15; public readonly long ConnectionTime; public readonly byte ConnectionNumber; public readonly int PeerId; public readonly bool PeerNetworkChanged; private NetConnectAcceptPacket(long connectionTime, byte connectionNumber, int peerId, bool peerNetworkChanged) { ConnectionTime = connectionTime; ConnectionNumber = connectionNumber; PeerId = peerId; PeerNetworkChanged = peerNetworkChanged; } public static NetConnectAcceptPacket FromData(NetPacket packet) { if (packet.Size != 15) { return null; } long connectionTime = BitConverter.ToInt64(packet.RawData, 1); byte b = packet.RawData[9]; if (b >= 4) { return null; } byte b2 = packet.RawData[10]; if (b2 > 1) { return null; } int num = BitConverter.ToInt32(packet.RawData, 11); if (num < 0) { return null; } return new NetConnectAcceptPacket(connectionTime, b, num, b2 == 1); } public static NetPacket Make(long connectTime, byte connectNum, int localPeerId) { NetPacket netPacket = new NetPacket(PacketProperty.ConnectAccept, 0); FastBitConverter.GetBytes(netPacket.RawData, 1, connectTime); netPacket.RawData[9] = connectNum; FastBitConverter.GetBytes(netPacket.RawData, 11, localPeerId); return netPacket; } public static NetPacket MakeNetworkChanged(NetPeer peer) { NetPacket netPacket = new NetPacket(PacketProperty.PeerNotFound, 14); FastBitConverter.GetBytes(netPacket.RawData, 1, peer.ConnectTime); netPacket.RawData[9] = peer.ConnectionNum; netPacket.RawData[10] = 1; FastBitConverter.GetBytes(netPacket.RawData, 11, peer.RemoteId); return netPacket; } } internal static class NativeSocket { private static class WinSock { private const string LibName = "ws2_32.dll"; [DllImport("ws2_32.dll", SetLastError = true)] public static extern int recvfrom(IntPtr socketHandle, [In][Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize); [DllImport("ws2_32.dll", SetLastError = true)] internal unsafe static extern int sendto(IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } private static class UnixSock { private const string LibName = "libc"; [DllImport("libc", SetLastError = true)] public static extern int recvfrom(IntPtr socketHandle, [In][Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize); [DllImport("libc", SetLastError = true)] internal unsafe static extern int sendto(IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } public static readonly bool IsSupported; public static readonly bool UnixMode; public const int IPv4AddrSize = 16; public const int IPv6AddrSize = 28; public const int AF_INET = 2; public const int AF_INET6 = 10; private static readonly Dictionary<int, SocketError> NativeErrorToSocketError; static NativeSocket() { IsSupported = false; UnixMode = false; NativeErrorToSocketError = new Dictionary<int, SocketError> { { 13, SocketError.AccessDenied }, { 98, SocketError.AddressAlreadyInUse }, { 99, SocketError.AddressNotAvailable }, { 97, SocketError.AddressFamilyNotSupported }, { 11, SocketError.WouldBlock }, { 114, SocketError.AlreadyInProgress }, { 9, SocketError.OperationAborted }, { 125, SocketError.OperationAborted }, { 103, SocketError.ConnectionAborted }, { 111, SocketError.ConnectionRefused }, { 104, SocketError.ConnectionReset }, { 89, SocketError.DestinationAddressRequired }, { 14, SocketError.Fault }, { 112, SocketError.HostDown }, { 6, SocketError.HostNotFound }, { 113, SocketError.HostUnreachable }, { 115, SocketError.InProgress }, { 4, SocketError.Interrupted }, { 22, SocketError.InvalidArgument }, { 106, SocketError.IsConnected }, { 24, SocketError.TooManyOpenSockets }, { 90, SocketError.MessageSize }, { 100, SocketError.NetworkDown }, { 102, SocketError.NetworkReset }, { 101, SocketError.NetworkUnreachable }, { 23, SocketError.TooManyOpenSockets }, { 105, SocketError.NoBufferSpaceAvailable }, { 61, SocketError.NoData }, { 2, SocketError.AddressNotAvailable }, { 92, SocketError.ProtocolOption }, { 107, SocketError.NotConnected }, { 88, SocketError.NotSocket }, { 3440, SocketError.OperationNotSupported }, { 1, SocketError.AccessDenied }, { 32, SocketError.Shutdown }, { 96, SocketError.ProtocolFamilyNotSupported }, { 93, SocketError.ProtocolNotSupported }, { 91, SocketError.ProtocolType }, { 94, SocketError.SocketNotSupported }, { 108, SocketError.Disconnecting }, { 110, SocketError.TimedOut }, { 0, SocketError.Success } }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { IsSupported = true; UnixMode = true; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { IsSupported = true; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int RecvFrom(IntPtr socketHandle, byte[] pinnedBuffer, int len, byte[] socketAddress, ref int socketAddressSize) { if (!UnixMode) { return WinSock.recvfrom(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, ref socketAddressSize); } return UnixSock.recvfrom(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, ref socketAddressSize); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static int SendTo(IntPtr socketHandle, byte* pinnedBuffer, int len, byte[] socketAddress, int socketAddressSize) { if (!UnixMode) { return WinSock.sendto(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, socketAddressSize); } return UnixSock.sendto(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, socketAddressSize); } public static SocketError GetSocketError() { int lastWin32Error = Marshal.GetLastWin32Error(); if (UnixMode) { if (!NativeErrorToSocketError.TryGetValue(lastWin32Error, out var value)) { return SocketError.SocketError; } return value; } return (SocketError)lastWin32Error; } public static SocketException GetSocketException() { int lastWin32Error = Marshal.GetLastWin32Error(); if (UnixMode) { if (!NativeErrorToSocketError.TryGetValue(lastWin32Error, out var value)) { return new SocketException(-1); } return new SocketException((int)value); } return new SocketException(lastWin32Error); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short GetNativeAddressFamily(IPEndPoint remoteEndPoint) { if (!UnixMode) { return (short)remoteEndPoint.AddressFamily; } return (short)((remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) ? 2 : 10); } } public enum NatAddressType { Internal, External } public interface INatPunchListener { void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token); void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token); } public class EventBasedNatPunchListener : INatPunchListener { public delegate void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token); public delegate void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token); public event OnNatIntroductionRequest NatIntroductionRequest; public event OnNatIntroductionSuccess NatIntroductionSuccess; void INatPunchListener.OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token) { if (this.NatIntroductionRequest != null) { this.NatIntroductionRequest(localEndPoint, remoteEndPoint, token); } } void INatPunchListener.OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token) { if (this.NatIntroductionSuccess != null) { this.NatIntroductionSuccess(targetEndPoint, type, token); } } } public sealed class NatPunchModule { private struct RequestEventData { public IPEndPoint LocalEndPoint; public IPEndPoint RemoteEndPoint; public string Token; } private struct SuccessEventData { public IPEndPoint TargetEndPoint; public NatAddressType Type; public string Token; } private class NatIntroduceRequestPacket { public IPEndPoint Internal { [Preserve] get; [Preserve] set; } public string Token { [Preserve] get; [Preserve] set; } } private class NatIntroduceResponsePacket { public IPEndPoint Internal { [Preserve] get; [Preserve] set; } public IPEndPoint External { [Preserve] get; [Preserve] set; } public string Token { [Preserve] get; [Preserve] set; } } private class NatPunchPacket { public string Token { [Preserve] get; [Preserve] set; } public bool IsExternal { [Preserve] get; [Preserve] set; } } private readonly NetManager _socket; private readonly ConcurrentQueue<RequestEventData> _requestEvents = new ConcurrentQueue<RequestEventData>(); private readonly ConcurrentQueue<SuccessEventData> _successEvents = new ConcurrentQueue<SuccessEventData>(); private readonly NetDataReader _cacheReader = new NetDataReader(); private readonly NetDataWriter _cacheWriter = new NetDataWriter(); private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(256); private INatPunchListener _natPunchListener; public const int MaxTokenLength = 256; public bool UnsyncedEvents; internal NatPunchModule(NetManager socket) { _socket = socket; _netPacketProcessor.SubscribeReusable<NatIntroduceResponsePacket>(OnNatIntroductionResponse); _netPacketProcessor.SubscribeReusable<NatIntroduceRequestPacket, IPEndPoint>(OnNatIntroductionRequest); _netPacketProcessor.SubscribeReusable<NatPunchPacket, IPEndPoint>(OnNatPunch); } internal void ProcessMessage(IPEndPoint senderEndPoint, NetPacket packet) { lock (_cacheReader) { _cacheReader.SetSource(packet.RawData, 1, packet.Size); _netPacketProcessor.ReadAllPackets(_cacheReader, senderEndPoint); } } public void Init(INatPunchListener listener) { _natPunchListener = listener; } private void Send<T>(T packet, IPEndPoint target) where T : class, new() { _cacheWriter.Reset(); _cacheWriter.Put((byte)16); _netPacketProcessor.Write(_cacheWriter, packet); _socket.SendRaw(_cacheWriter.Data, 0, _cacheWriter.Length, target); } public void NatIntroduce(IPEndPoint hostInternal, IPEndPoint hostExternal, IPEndPoint clientInternal, IPEndPoint clientExternal, string additionalInfo) { NatIntroduceResponsePacket natIntroduceResponsePacket = new NatIntroduceResponsePacket { Token = additionalInfo }; natIntroduceResponsePacket.Internal = hostInternal; natIntroduceResponsePacket.External = hostExternal; Send(natIntroduceResponsePacket, clientExternal); natIntroduceResponsePacket.Internal = clientInternal; natIntroduceResponsePacket.External = clientExternal; Send(natIntroduceResponsePacket, hostExternal); } public void PollEvents() { if (!UnsyncedEvents && _natPunchListener != null && (!_successEvents.IsEmpty || !_requestEvents.IsEmpty)) { SuccessEventData result; while (_successEvents.TryDequeue(out result)) { _natPunchListener.OnNatIntroductionSuccess(result.TargetEndPoint, result.Type, result.Token); } RequestEventData result2; while (_requestEvents.TryDequeue(out result2)) { _natPunchListener.OnNatIntroductionRequest(result2.LocalEndPoint, result2.RemoteEndPoint, result2.Token); } } } public void SendNatIntroduceRequest(string host, int port, string additionalInfo) { SendNatIntroduceRequest(NetUtils.MakeEndPoint(host, port), additionalInfo); } public void SendNatIntroduceRequest(IPEndPoint masterServerEndPoint, string additionalInfo) { string localIp = NetUtils.GetLocalIp(LocalAddrType.IPv4); if (string.IsNullOrEmpty(localIp) || masterServerEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { localIp = NetUtils.GetLocalIp(LocalAddrType.IPv6); } Send(new NatIntroduceRequestPacket { Internal = NetUtils.MakeEndPoint(localIp, _socket.LocalPort), Token = additionalInfo }, masterServerEndPoint); } private void OnNatIntroductionRequest(NatIntroduceRequestPacket req, IPEndPoint senderEndPoint) { if (UnsyncedEvents) { _natPunchListener.OnNatIntroductionRequest(req.Internal, senderEndPoint, req.Token); return; } _requestEvents.Enqueue(new RequestEventData { LocalEndPoint = req.Internal, RemoteEndPoint = senderEndPoint, Token = req.Token }); } private void OnNatIntroductionResponse(NatIntroduceResponsePacket req) { NatPunchPacket natPunchPacket = new NatPunchPacket { Token = req.Token }; Send(natPunchPacket, req.Internal); _socket.Ttl = 2; _socket.SendRaw(new byte[1] { 17 }, 0, 1, req.External); _socket.Ttl = 255; natPunchPacket.IsExternal = true; Send(natPunchPacket, req.External); } private void OnNatPunch(NatPunchPacket req, IPEndPoint senderEndPoint) { if (UnsyncedEvents) { _natPunchListener.OnNatIntroductionSuccess(senderEndPoint, req.IsExternal ? NatAddressType.External : NatAddressType.Internal, req.Token); return; } _successEvents.Enqueue(new SuccessEventData { TargetEndPoint = senderEndPoint, Type = (req.IsExternal ? NatAddressType.External : NatAddressType.Internal), Token = req.Token }); } } public enum DeliveryMethod : byte { Unreliable = 4, ReliableUnordered = 0, Sequenced = 1, ReliableOrdered = 2, ReliableSequenced = 3 } public static class NetConstants { public const int DefaultWindowSize = 64; public const int SocketBufferSize = 1048576; public const int SocketTTL = 255; public const int HeaderSize = 1; public const int ChanneledHeaderSize = 4; public const int FragmentHeaderSize = 6; public const int FragmentedHeaderTotalSize = 10; public const ushort MaxSequence = 32768; public const ushort HalfMaxSequence = 16384; internal const int ProtocolId = 13; internal const int MaxUdpHeaderSize = 68; internal const int ChannelTypeCount = 4; internal static readonly int[] PossibleMtu = new int[6] { 1024, 1164, 1392, 1404, 1424, 1432 }; public static readonly int InitialMtu = PossibleMtu[0]; public static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; public static readonly int MaxUnreliableDataSize = MaxPacketSize - 1; public const byte MaxConnectionNumber = 4; } public class InvalidPacketException : ArgumentException { public InvalidPacketException(string message) : base(message) { } } public class TooBigPacketException : InvalidPacketException { public TooBigPacketException(string message) : base(message) { } } public enum NetLogLevel { Warning, Error, Trace, Info } public interface INetLogger { void WriteNet(NetLogLevel level, string str, params object[] args); } public static class NetDebug { public static INetLogger Logger = null; private static readonly object DebugLogLock = new object(); private static void WriteLogic(NetLogLevel logLevel, string str, params object[] args) { lock (DebugLogLock) { if (Logger == null) { Console.WriteLine(str, args); } else { Logger.WriteNet(logLevel, str, args); } } } [Conditional("DEBUG_MESSAGES")] internal static void Write(string str) { WriteLogic(NetLogLevel.Trace, str); } [Conditional("DEBUG_MESSAGES")] internal static void Write(NetLogLevel level, string str) { WriteLogic(level, str); } [Conditional("DEBUG_MESSAGES")] [Conditional("DEBUG")] internal static void WriteForce(string str) { WriteLogic(NetLogLevel.Trace, str); } [Conditional("DEBUG_MESSAGES")] [Conditional("DEBUG")] internal static void WriteForce(NetLogLevel level, string str) { WriteLogic(level, str); } internal static void WriteError(string str) { WriteLogic(NetLogLevel.Error, str); } } public sealed class NetPacketReader : NetDataReader { private NetPacket _packet; private readonly NetManager _manager; private readonly NetEvent _evt; internal NetPacketReader(NetManager manager, NetEvent evt) { _manager = manager; _evt = evt; } internal void SetSource(NetPacket packet, int headerSize) { if (packet != null) { _packet = packet; SetSource(packet.RawData, headerSize, packet.Size); } } internal void RecycleInternal() { Clear(); if (_packet != null) { _manager.PoolRecycle(_packet); } _packet = null; _manager.RecycleEvent(_evt); } public void Recycle() { if (!_manager.AutoRecycle) { RecycleInternal(); } } } internal sealed class NetEvent { public enum EType { Connect, Disconnect, Receive, ReceiveUnconnected, Error, ConnectionLatencyUpdated, Broadcast, ConnectionRequest, MessageDelivered, PeerAddressChanged } public NetEvent Next; public EType Type; public NetPeer Peer; public IPEndPoint RemoteEndPoint; public object UserData; public int Latency; public SocketError ErrorCode; public DisconnectReason DisconnectReason; public ConnectionRequest ConnectionRequest; public DeliveryMethod DeliveryMethod; public byte ChannelNumber; public readonly NetPacketReader DataReader; public NetEvent(NetManager manager) { DataReader = new NetPacketReader(manager, this); } } public class NetManager : IEnumerable<NetPeer>, IEnumerable { public struct NetPeerEnumerator : IEnumerator<NetPeer>, IDisposable, IEnumerator { private readonly NetPeer _initialPeer; private NetPeer _p; public NetPeer Current => _p; object IEnumerator.Current => _p; public NetPeerEnumerator(NetPeer p) { _initialPeer = p; _p = null; } public void Dispose() { } public bool MoveNext() { _p = ((_p == null) ? _initialPeer : _p.NextPeer); return _p != null; } public void Reset() { throw new NotSupportedException(); } } private struct IncomingData { public NetPacket Data; public IPEndPoint EndPoint; public DateTime TimeWhenGet; } private struct Slot { internal int HashCode; internal int Next; internal NetPeer Value; } private readonly List<IncomingData> _pingSimulationList = new List<IncomingData>(); private readonly Random _randomGenerator = new Random(); private const int MinLatencyThreshold = 5; private Thread _logicThread; private bool _manualMode; private readonly AutoResetEvent _updateTriggerEvent = new AutoResetEvent(initialState: true); private NetEvent _pendingEventHead; private NetEvent _pendingEventTail; private NetEvent _netEventPoolHead; private readonly INetEventListener _netEventListener; private readonly IDeliveryEventListener _deliveryEventListener; private readonly INtpEventListener _ntpEventListener; private readonly IPeerAddressChangedListener _peerAddressChangedListener; private readonly Dictionary<IPEndPoint, ConnectionRequest> _requestsDict = new Dictionary<IPEndPoint, ConnectionRequest>(); private readonly ConcurrentDictionary<IPEndPoint, NtpRequest> _ntpRequests = new ConcurrentDictionary<IPEndPoint, NtpRequest>(); private long _connectedPeersCount; private readonly List<NetPeer> _connectedPeerListCache = new List<NetPeer>(); private readonly PacketLayerBase _extraPacketLayer; private int _lastPeerId; private ConcurrentQueue<int> _peerIds = new ConcurrentQueue<int>(); private byte _channelsCount = 1; private readonly object _eventLock = new object(); private bool _dropPacket; public bool UnconnectedMessagesEnabled; public bool NatPunchEnabled; public int UpdateTime = 15; public int PingInterval = 1000; public int DisconnectTimeout = 5000; public bool SimulatePacketLoss; public bool SimulateLatency; public int SimulationPacketLossChance = 10; public int SimulationMinLatency = 30; public int SimulationMaxLatency = 100; public bool UnsyncedEvents; public bool UnsyncedReceiveEvent; public bool UnsyncedDeliveryEvent; public bool BroadcastReceiveEnabled; public int ReconnectDelay = 500; public int MaxConnectAttempts = 10; public bool ReuseAddress; public bool DontRoute; public readonly NetStatistics Statistics = new NetStatistics(); public bool EnableStatistics; public readonly NatPunchModule NatPunchModule; public bool AutoRecycle; public bool IPv6Enabled = true; public int MtuOverride; public bool MtuDiscovery; public bool UseNativeSockets; public bool DisconnectOnUnreachable; public bool AllowPeerAddressChange; private const int MaxPrimeArrayLength = 2147483587; private const int HashPrime = 101; private const int Lower31BitMask = int.MaxValue; private static readonly int[] Primes; private int[] _buckets; private Slot[] _slots; private int _count; private int _lastIndex; private int _freeList = -1; private NetPeer[] _peersArray = new NetPeer[32]; private readonly ReaderWriterLockSlim _peersLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); private volatile NetPeer _headPeer; private NetPacket _poolHead; private int _poolCount; private readonly object _poolLock = new object(); public int PacketPoolSize = 1000; private const int ReceivePollingTime = 500000; private Socket _udpSocketv4; private Socket _udpSocketv6; private Thread _receiveThread; private IPEndPoint _bufferEndPointv4; private IPEndPoint _bufferEndPointv6; private const int SioUdpConnreset = -1744830452; private static readonly IPAddress MulticastAddressV6; public static readonly bool IPv6Support; internal bool NotConnected; public bool IsRunning { get; private set; } public int LocalPort { get; private set; } public NetPeer FirstPeer => _headPeer; public byte ChannelsCount { get { return _channelsCount; } set { if (value < 1 || value > 64) { throw new ArgumentException("Channels count must be between 1 and 64"); } _channelsCount = value; } } public List<NetPeer> ConnectedPeerList { get { GetPeersNonAlloc(_connectedPeerListCache, ConnectionState.Connected); return _connectedPeerListCache; } } public int ConnectedPeersCount => (int)Interlocked.Read(ref _connectedPeersCount); public int ExtraPacketSizeForLayer => _extraPacketLayer?.ExtraPacketSizeForLayer ?? 0; public int PoolCount => _poolCount; public short Ttl { get { return _udpSocketv4.Ttl; } internal set { _udpSocketv4.Ttl = value; } } public NetManager(INetEventListener listener, PacketLayerBase extraPacketLayer = null) { _netEventListener = listener; _deliveryEventListener = listener as IDeliveryEventListener; _ntpEventListener = listener as INtpEventListener; _peerAddressChangedListener = listener as IPeerAddressChangedListener; NatPunchModule = new NatPunchModule(this); _extraPacketLayer = extraPacketLayer; } internal void ConnectionLatencyUpdated(NetPeer fromPeer, int latency) { CreateEvent(NetEvent.EType.ConnectionLatencyUpdated, fromPeer, null, SocketError.Success, latency, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } internal void MessageDelivered(NetPeer fromPeer, object userData) { if (_deliveryEventListener != null) { CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, null, userData); } } internal void DisconnectPeerForce(NetPeer peer, DisconnectReason reason, SocketError socketErrorCode, NetPacket eventData) { DisconnectPeer(peer, reason, socketErrorCode, force: true, null, 0, 0, eventData); } private void DisconnectPeer(NetPeer peer, DisconnectReason reason, SocketError socketErrorCode, bool force, byte[] data, int start, int count, NetPacket eventData) { switch (peer.Shutdown(data, start, count, force)) { case ShutdownResult.None: return; case ShutdownResult.WasConnected: Interlocked.Decrement(ref _connectedPeersCount); break; } CreateEvent(NetEvent.EType.Disconnect, peer, null, socketErrorCode, 0, reason, null, DeliveryMethod.Unreliable, 0, eventData); } private void CreateEvent(NetEvent.EType type, NetPeer peer = null, IPEndPoint remoteEndPoint = null, SocketError errorCode = SocketError.Success, int latency = 0, DisconnectReason disconnectReason = DisconnectReason.ConnectionFailed, ConnectionRequest connectionRequest = null, DeliveryMethod deliveryMethod = DeliveryMethod.Unreliable, byte channelNumber = 0, NetPacket readerSource = null, object userData = null) { bool flag = UnsyncedEvents; switch (type) { case NetEvent.EType.Connect: Interlocked.Increment(ref _connectedPeersCount); break; case NetEvent.EType.MessageDelivered: flag = UnsyncedDeliveryEvent; break; } NetEvent netEvent; lock (_eventLock) { netEvent = _netEventPoolHead; if (netEvent == null) { netEvent = new NetEvent(this); } else { _netEventPoolHead = netEvent.Next; } } netEvent.Next = null; netEvent.Type = type; netEvent.DataReader.SetSource(readerSource, readerSource?.GetHeaderSize() ?? 0); netEvent.Peer = peer; netEvent.RemoteEndPoint = remoteEndPoint; netEvent.Latency = latency; netEvent.ErrorCode = errorCode; netEvent.DisconnectReason = disconnectReason; netEvent.ConnectionRequest = connectionRequest; netEvent.DeliveryMethod = deliveryMethod; netEvent.ChannelNumber = channelNumber; netEvent.UserData = userData; if (flag || _manualMode) { ProcessEvent(netEvent); return; } lock (_eventLock) { if (_pendingEventTail == null) { _pendingEventHead = netEvent; } else { _pendingEventTail.Next = netEvent; } _pendingEventTail = netEvent; } } private void ProcessEvent(NetEvent evt) { bool isNull = evt.DataReader.IsNull; switch (evt.Type) { case NetEvent.EType.Connect: _netEventListener.OnPeerConnected(evt.Peer); break; case NetEvent.EType.Disconnect: { DisconnectInfo disconnectInfo = default(DisconnectInfo); disconnectInfo.Reason = evt.DisconnectReason; disconnectInfo.AdditionalData = evt.DataReader; disconnectInfo.SocketErrorCode = evt.ErrorCode; DisconnectInfo disconnectInfo2 = disconnectInfo; _netEventListener.OnPeerDisconnected(evt.Peer, disconnectInfo2); break; } case NetEvent.EType.Receive: _netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader, evt.ChannelNumber, evt.DeliveryMethod); break; case NetEvent.EType.ReceiveUnconnected: _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.BasicMessage); break; case NetEvent.EType.Broadcast: _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.Broadcast); break; case NetEvent.EType.Error: _netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.ErrorCode); break; case NetEvent.EType.ConnectionLatencyUpdated: _netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.Latency); break; case NetEvent.EType.ConnectionRequest: _netEventListener.OnConnectionRequest(evt.ConnectionRequest); break; case NetEvent.EType.MessageDelivered: _deliveryEventListener.OnMessageDelivered(evt.Peer, evt.UserData); break; case NetEvent.EType.PeerAddressChanged: { _peersLock.EnterUpgradeableReadLock(); IPEndPoint iPEndPoint = null; if (ContainsPeer(evt.Peer)) { _peersLock.EnterWriteLock(); RemovePeerFromSet(evt.Peer); iPEndPoint = new IPEndPoint(evt.Peer.Address, evt.Peer.Port); evt.Peer.FinishEndPointChange(evt.RemoteEndPoint); AddPeerToSet(evt.Peer); _peersLock.ExitWriteLock(); } _peersLock.ExitUpgradeableReadLock(); if (iPEndPoint != null && _peerAddressChangedListener != null) { _peerAddressChangedListener.OnPeerAddressChanged(evt.Peer, iPEndPoint); } break; } } if (isNull) { RecycleEvent(evt); } else if (AutoRecycle) { evt.DataReader.RecycleInternal(); } } internal void RecycleEvent(NetEvent evt) { evt.Peer = null; evt.ErrorCode = SocketError.Success; evt.RemoteEndPoint = null; evt.ConnectionRequest = null; lock (_eventLock) { evt.Next = _netEventPoolHead; _netEventPoolHead = evt; } } private void UpdateLogic() { List<NetPeer> list = new List<NetPeer>(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (IsRunning) { try { float num = (float)((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0); num = ((num <= 0f) ? 0.001f : num); stopwatch.Restart(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > (float)DisconnectTimeout) { list.Add(netPeer); } else { netPeer.Update(num); } } if (list.Count > 0) { _peersLock.EnterWriteLock(); for (int i = 0; i < list.Count; i++) { RemovePeer(list[i], enableWriteLock: false); } _peersLock.ExitWriteLock(); list.Clear(); } ProcessNtpRequests(num); int num2 = UpdateTime - (int)stopwatch.ElapsedMilliseconds; if (num2 > 0) { _updateTriggerEvent.WaitOne(num2); } } catch (ThreadAbortException) { return; } catch (Exception ex2) { NetDebug.WriteError("[NM] LogicThread error: " + ex2); } } stopwatch.Stop(); } [Conditional("DEBUG")] private void ProcessDelayedPackets() { if (!SimulateLatency) { return; } DateTime utcNow = DateTime.UtcNow; lock (_pingSimulationList) { for (int i = 0; i < _pingSimulationList.Count; i++) { IncomingData incomingData = _pingSimulationList[i]; if (incomingData.TimeWhenGet <= utcNow) { HandleMessageReceived(incomingData.Data, incomingData.EndPoint); _pingSimulationList.RemoveAt(i); i--; } } } } private void ProcessNtpRequests(float elapsedMilliseconds) { List<IPEndPoint> list = null; foreach (KeyValuePair<IPEndPoint, NtpRequest> ntpRequest in _ntpRequests) { ntpRequest.Value.Send(_udpSocketv4, elapsedMilliseconds); if (ntpRequest.Value.NeedToKill) { if (list == null) { list = new List<IPEndPoint>(); } list.Add(ntpRequest.Key); } } if (list == null) { return; } foreach (IPEndPoint item in list) { _ntpRequests.TryRemove(item, out var _); } } public void ManualUpdate(float elapsedMilliseconds) { if (!_manualMode) { return; } for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > (float)DisconnectTimeout) { RemovePeer(netPeer, enableWriteLock: false); } else { netPeer.Update(elapsedMilliseconds); } } ProcessNtpRequests(elapsedMilliseconds); } internal NetPeer OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length) { NetPeer actualValue = null; if (request.Result == ConnectionRequestResult.RejectForce) { if (rejectData != null && length > 0) { NetPacket netPacket = PoolGetWithProperty(PacketProperty.Disconnect, length); netPacket.ConnectionNumber = request.InternalPacket.ConnectionNumber; FastBitConverter.GetBytes(netPacket.RawData, 1, request.InternalPacket.ConnectionTime); if (netPacket.Size >= NetConstants.PossibleMtu[0]) { NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU!"); } else { Buffer.BlockCopy(rejectData, start, netPacket.RawData, 9, length); } SendRawAndRecycle(netPacket, request.RemoteEndPoint); } lock (_requestsDict) { _requestsDict.Remove(request.RemoteEndPoint); } } else { lock (_requestsDict) { if (!TryGetPeer(request.RemoteEndPoint, out actualValue)) { if (request.Result == ConnectionRequestResult.Reject) { actualValue = new NetPeer(this, request.RemoteEndPoint, GetNextPeerId()); actualValue.Reject(request.InternalPacket, rejectData, start, length); AddPeer(actualValue); } else { actualValue = new NetPeer(this, request, GetNextPeerId()); AddPeer(actualValue); CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } } _requestsDict.Remove(request.RemoteEndPoint); } } return actualValue; } private int GetNextPeerId() { if (!_peerIds.TryDequeue(out var result)) { return _lastPeerId++; } return result; } private void ProcessConnectRequest(IPEndPoint remoteEndPoint, NetPeer netPeer, NetConnectRequestPacket connRequest) { if (netPeer != null) { ConnectRequestResult connectRequestResult = netPeer.ProcessConnectRequest(connRequest); switch (connectRequestResult) { default: return; case ConnectRequestResult.Reconnection: DisconnectPeerForce(netPeer, DisconnectReason.Reconnect, SocketError.Success, null); RemovePeer(netPeer, enableWriteLock: true); break; case ConnectRequestResult.NewConnection: RemovePeer(netPeer, enableWriteLock: true); break; case ConnectRequestResult.P2PLose: DisconnectPeerForce(netPeer, DisconnectReason.PeerToPeerConnection, SocketError.Success, null); RemovePeer(netPeer, enableWriteLock: true); break; } if (connectRequestResult != ConnectRequestResult.P2PLose) { connRequest.ConnectionNumber = (byte)((netPeer.ConnectionNum + 1) % 4); } } ConnectionRequest value; lock (_requestsDict) { if (_requestsDict.TryGetValue(remoteEndPoint, out value)) { value.UpdateRequest(connRequest); return; } value = new ConnectionRequest(remoteEndPoint, connRequest, this); _requestsDict.Add(remoteEndPoint, value); } CreateEvent(NetEvent.EType.ConnectionRequest, null, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, value, DeliveryMethod.Unreliable, 0); } private void OnMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) { if (packet.Size == 0) { PoolRecycle(packet); return; } _dropPacket = false; if (!_dropPacket) { HandleMessageReceived(packet, remoteEndPoint); } } [Conditional("DEBUG")] private void HandleSimulateLatency(NetPacket packet, IPEndPoint remoteEndPoint) { if (!SimulateLatency) { return; } int num = _randomGenerator.Next(SimulationMinLatency, SimulationMaxLatency); if (num > 5) { lock (_pingSimulationList) { _pingSimulationList.Add(new IncomingData { Data = packet, EndPoint = remoteEndPoint, TimeWhenGet = DateTime.UtcNow.AddMilliseconds(num) }); } _dropPacket = true; } } [Conditional("DEBUG")] private void HandleSimulatePacketLoss() { if (SimulatePacketLoss && _randomGenerator.NextDouble() * 100.0 < (double)SimulationPacketLossChance) { _dropPacket = true; } } private void HandleMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) { int size = packet.Size; if (EnableStatistics) { Statistics.IncrementPacketsReceived(); Statistics.AddBytesReceived(size); } if (_ntpRequests.Count > 0 && _ntpRequests.TryGetValue(remoteEndPoint, out var _)) { if (packet.Size >= 48) { byte[] array = new byte[packet.Size]; Buffer.BlockCopy(packet.RawData, 0, array, 0, packet.Size); NtpPacket ntpPacket = NtpPacket.FromServerResponse(array, DateTime.UtcNow); try { ntpPacket.ValidateReply(); } catch (InvalidOperationException) { ntpPacket = null; } if (ntpPacket != null) { _ntpRequests.TryRemove(remoteEndPoint, out var _); _ntpEventListener?.OnNtpResponse(ntpPacket); } } return; } if (_extraPacketLayer != null) { _extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref packet.Size); if (packet.Size == 0) { return; } } if (!packet.Verify()) { NetDebug.WriteError("[NM] DataReceived: bad!"); PoolRecycle(packet); return; } switch (packet.Property) { case PacketProperty.ConnectRequest: if (NetConnectRequestPacket.GetProtocolId(packet) != 13) { SendRawAndRecycle(PoolGetWithProperty(PacketProperty.InvalidProtocol), remoteEndPoint); return; } break; case PacketProperty.Broadcast: if (BroadcastReceiveEnabled) { CreateEvent(NetEvent.EType.Broadcast, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet); } return; case PacketProperty.UnconnectedMessage: if (UnconnectedMessagesEnabled) { CreateEvent(NetEvent.EType.ReceiveUnconnected, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet); } return; case PacketProperty.NatMessage: if (NatPunchEnabled) { NatPunchModule.ProcessMessage(remoteEndPoint, packet); } return; } NetPeer actualValue = remoteEndPoint as NetPeer; bool flag = actualValue != null || TryGetPeer(remoteEndPoint, out actualValue); if (flag && EnableStatistics) { actualValue.Statistics.IncrementPacketsReceived(); actualValue.Statistics.AddBytesReceived(size); } switch (packet.Property) { case PacketProperty.ConnectRequest: { NetConnectRequestPacket netConnectRequestPacket = NetConnectRequestPacket.FromData(packet); if (netConnectRequestPacket != null) { ProcessConnectRequest(remoteEndPoint, actualValue, netConnectRequestPacket); } break; } case PacketProperty.PeerNotFound: if (flag) { if (actualValue.ConnectionState == ConnectionState.Connected) { if (packet.Size == 1) { actualValue.ResetMtu(); SendRaw(NetConnectAcceptPacket.MakeNetworkChanged(actualValue), remoteEndPoint); } else if (packet.Size == 2 && packet.RawData[1] == 1) { DisconnectPeerForce(actualValue, DisconnectReason.PeerNotFound, SocketError.Success, null); } } } else { if (packet.Size <= 1) { break; } bool flag2 = false; if (AllowPeerAddressChange) { NetConnectAcceptPacket netConnectAcceptPacket = NetConnectAcceptPacket.FromData(packet); if (netConnectAcceptPacket != null && netConnectAcceptPacket.PeerNetworkChanged && netConnectAcceptPacket.PeerId < _peersArray.Length) { _peersLock.EnterUpgradeableReadLock(); NetPeer netPeer = _peersArray[netConnectAcceptPacket.PeerId]; _peersLock.ExitUpgradeableReadLock(); if (netPeer != null && netPeer.ConnectTime == netConnectAcceptPacket.ConnectionTime && netPeer.ConnectionNum == netConnectAcceptPacket.ConnectionNumber) { if (netPeer.ConnectionState == ConnectionState.Connected) { netPeer.InitiateEndPointChange(); CreateEvent(NetEvent.EType.PeerAddressChanged, netPeer, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } flag2 = true; } } } PoolRecycle(packet); if (!flag2) { NetPacket netPacket = PoolGetWithProperty(PacketProperty.PeerNotFound, 1); netPacket.RawData[1] = 1; SendRawAndRecycle(netPacket, remoteEndPoint); } } break; case PacketProperty.InvalidProtocol: if (flag && actualValue.ConnectionState == ConnectionState.Outgoing) { DisconnectPeerForce(actualValue, DisconnectReason.InvalidProtocol, SocketError.Success, null); } break; case PacketProperty.Disconnect: if (flag) { DisconnectResult disconnectResult = actualValue.ProcessDisconnect(packet); if (disconnectResult == DisconnectResult.None) { PoolRecycle(packet); break; } DisconnectPeerForce(actualValue, (disconnectResult == DisconnectResult.Disconnect) ? DisconnectReason.RemoteConnectionClose : DisconnectReason.ConnectionRejected, SocketError.Success, packet); } else { PoolRecycle(packet); } SendRawAndRecycle(PoolGetWithProperty(PacketProperty.ShutdownOk), remoteEndPoint); break; case PacketProperty.ConnectAccept: if (flag) { NetConnectAcceptPacket netConnectAcceptPacket2 = NetConnectAcceptPacket.FromData(packet); if (netConnectAcceptPacket2 != null && actualValue.ProcessConnectAccept(netConnectAcceptPacket2)) { CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); } } break; default: if (flag) { actualValue.ProcessPacket(packet); } else { SendRawAndRecycle(PoolGetWithProperty(PacketProperty.PeerNotFound), remoteEndPoint); } break; } } internal void CreateReceiveEvent(NetPacket packet, DeliveryMethod method, byte channelNumber, int headerSize, NetPeer fromPeer) { if (UnsyncedEvents || UnsyncedReceiveEvent || _manualMode) { NetEvent netEvent; lock (_eventLock) { netEvent = _netEventPoolHead; if (netEvent == null) { netEvent = new NetEvent(this); } else { _netEventPoolHead = netEvent.Next; } } netEvent.Next = null; netEvent.Type = NetEvent.EType.Receive; netEvent.DataReader.SetSource(packet, headerSize); netEvent.Peer = fromPeer; netEvent.DeliveryMethod = method; netEvent.ChannelNumber = channelNumber; ProcessEvent(netEvent); return; } lock (_eventLock) { NetEvent netEvent = _netEventPoolHead; if (netEvent == null) { netEvent = new NetEvent(this); } else { _netEventPoolHead = netEvent.Next; } netEvent.Next = null; netEvent.Type = NetEvent.EType.Receive; netEvent.DataReader.SetSource(packet, headerSize); netEvent.Peer = fromPeer; netEvent.DeliveryMethod = method; netEvent.ChannelNumber = channelNumber; if (_pendingEventTail == null) { _pendingEventHead = netEvent; } else { _pendingEventTail.Next = netEvent; } _pendingEventTail = netEvent; } } public void SendToAll(NetDataWriter writer, DeliveryMethod options) { SendToAll(writer.Data, 0, writer.Length, options); } public void SendToAll(byte[] data, DeliveryMethod options) { SendToAll(data, 0, data.Length, options); } public void SendToAll(byte[] data, int start, int length, DeliveryMethod options) { SendToAll(data, start, length, 0, options); } public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options) { SendToAll(writer.Data, 0, writer.Length, channelNumber, options); } public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options) { SendToAll(data, 0, data.Length, channelNumber, options); } public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options) { try { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { netPeer.Send(data, start, length, channelNumber, options); } } finally { _peersLock.ExitReadLock(); } } public void SendToAll(NetDataWriter writer, DeliveryMethod options, NetPeer excludePeer) { SendToAll(writer.Data, 0, writer.Length, 0, options, excludePeer); } public void SendToAll(byte[] data, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, 0, data.Length, 0, options, excludePeer); } public void SendToAll(byte[] data, int start, int length, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, start, length, 0, options, excludePeer); } public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { SendToAll(writer.Data, 0, writer.Length, channelNumber, options, excludePeer); } public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { SendToAll(data, 0, data.Length, channelNumber, options, excludePeer); } public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) { try { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if (netPeer != excludePeer) { netPeer.Send(data, start, length, channelNumber, options); } } } finally { _peersLock.ExitReadLock(); } } public bool Start() { return Start(0); } public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port) { return Start(addressIPv4, addressIPv6, port, manualMode: false); } public bool Start(string addressIPv4, string addressIPv6, int port) { IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4); IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6); return Start(addressIPv7, addressIPv8, port); } public bool Start(int port) { return Start(IPAddress.Any, IPAddress.IPv6Any, port); } public bool StartInManualMode(IPAddress addressIPv4, IPAddress addressIPv6, int port) { return Start(addressIPv4, addressIPv6, port, manualMode: true); } public bool StartInManualMode(string addressIPv4, string addressIPv6, int port) { IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4); IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6); return StartInManualMode(addressIPv7, addressIPv8, port); } public bool StartInManualMode(int port) { return StartInManualMode(IPAddress.Any, IPAddress.IPv6Any, port); } public bool SendUnconnectedMessage(byte[] message, IPEndPoint remoteEndPoint) { return SendUnconnectedMessage(message, 0, message.Length, remoteEndPoint); } public bool SendUnconnectedMessage(NetDataWriter writer, string address, int port) { IPEndPoint remoteEndPoint = NetUtils.MakeEndPoint(address, port); return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint); } public bool SendUnconnectedMessage(NetDataWriter writer, IPEndPoint remoteEndPoint) { return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint); } public bool SendUnconnectedMessage(byte[] message, int start, int length, IPEndPoint remoteEndPoint) { NetPacket packet = PoolGetWithData(PacketProperty.UnconnectedMessage, message, start, length); return SendRawAndRecycle(packet, remoteEndPoint) > 0; } public void TriggerUpdate() { _updateTriggerEvent.Set(); } public void PollEvents(int maxProcessedEvents = 0) { if (_manualMode) { if (_udpSocketv4 != null) { ManualReceive(_udpSocketv4, _bufferEndPointv4, maxProcessedEvents); } if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4) { ManualReceive(_udpSocketv6, _bufferEndPointv6, maxProcessedEvents); } } else { if (UnsyncedEvents) { return; } NetEvent netEvent; lock (_eventLock) { netEvent = _pendingEventHead; _pendingEventHead = null; _pendingEventTail = null; } int num = 0; while (netEvent != null) { NetEvent next = netEvent.Next; ProcessEvent(netEvent); netEvent = next; num++; if (num == maxProcessedEvents) { break; } } } } public NetPeer Connect(string address, int port, string key) { return Connect(address, port, NetDataWriter.FromString(key)); } public NetPeer Connect(string address, int port, NetDataWriter connectionData) { IPEndPoint target; try { target = NetUtils.MakeEndPoint(address, port); } catch { CreateEvent(NetEvent.EType.Disconnect, null, null, SocketError.Success, 0, DisconnectReason.UnknownHost, null, DeliveryMethod.Unreliable, 0); return null; } return Connect(target, connectionData); } public NetPeer Connect(IPEndPoint target, string key) { return Connect(target, NetDataWriter.FromString(key)); } public NetPeer Connect(IPEndPoint target, NetDataWriter connectionData) { if (!IsRunning) { throw new InvalidOperationException("Client is not running"); } lock (_requestsDict) { if (_requestsDict.ContainsKey(target)) { return null; } byte connectNum = 0; if (TryGetPeer(target, out var actualValue)) { ConnectionState connectionState = actualValue.ConnectionState; if (connectionState == ConnectionState.Outgoing || connectionState == ConnectionState.Connected) { return actualValue; } connectNum = (byte)((actualValue.ConnectionNum + 1) % 4); RemovePeer(actualValue, enableWriteLock: true); } actualValue = new NetPeer(this, target, GetNextPeerId(), connectNum, connectionData); AddPeer(actualValue); return actualValue; } } public void Stop() { Stop(sendDisconnectMessages: true); } public void Stop(bool sendDisconnectMessages) { if (IsRunning) { for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { netPeer.Shutdown(null, 0, 0, !sendDisconnectMessages); } CloseSocket(); _updateTriggerEvent.Set(); if (!_manualMode) { _logicThread.Join(); _logicThread = null; } ClearPeerSet(); _peerIds = new ConcurrentQueue<int>(); _lastPeerId = 0; _connectedPeersCount = 0L; _pendingEventHead = null; _pendingEventTail = null; } } [Conditional("DEBUG")] private void ClearPingSimulationList() { lock (_pingSimulationList) { _pingSimulationList.Clear(); } } public int GetPeersCount(ConnectionState peerState) { int num = 0; _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if ((netPeer.ConnectionState & peerState) != 0) { num++; } } _peersLock.ExitReadLock(); return num; } public void GetPeersNonAlloc(List<NetPeer> peers, ConnectionState peerState) { peers.Clear(); _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { if ((netPeer.ConnectionState & peerState) != 0) { peers.Add(netPeer); } } _peersLock.ExitReadLock(); } public void DisconnectAll() { DisconnectAll(null, 0, 0); } public void DisconnectAll(byte[] data, int start, int count) { _peersLock.EnterReadLock(); for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) { DisconnectPeer(netPeer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null); } _peersLock.ExitReadLock(); } public void DisconnectPeerForce(NetPeer peer) { DisconnectPeerForce(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, null); } public void DisconnectPeer(NetPeer peer) { DisconnectPeer(peer, null, 0, 0); } public void DisconnectPeer(NetPeer peer, byte[] data) { DisconnectPeer(peer, data, 0, data.Length); } public void DisconnectPeer(NetPeer peer, NetDataWriter writer) { DisconnectPeer(peer, writer.Data, 0, writer.Length); } public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count) { DisconnectPeer(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null); } public void CreateNtpRequest(IPEndPoint endPoint) { _ntpRequests.TryAdd(endPoint, new NtpRequest(endPoint)); } public void CreateNtpRequest(string ntpServerAddress, int port) { IPEndPoint iPEndPoint = NetUtils.MakeEndPoint(ntpServerAddress, port); _ntpRequests.TryAdd(iPEndPoint, new NtpRequest(iPEndPoint)); } public void CreateNtpRequest(string ntpServerAddress) { IPEndPoint iPEndPoint = NetUtils.MakeEndPoint(ntpServerAddress, 123); _ntpRequests.TryAdd(iPEndPoint, new NtpRequest(iPEndPoint)); } public NetPeerEnumerator GetEnumerator() { return new NetPeerEnumerator(_headPeer); } IEnumerator<NetPeer> IEnumerable<NetPeer>.GetEnumerator() { return new NetPeerEnumerator(_headPeer); } IEnumerator IEnumerable.GetEnumerator() { return new NetPeerEnumerator(_headPeer); } private static int HashSetGetPrime(int min) { int[] primes = Primes; foreach (int num in primes) { if (num >= min) { return num; } } for (int j = min | 1; j < int.MaxValue; j += 2) { if (IsPrime(j) && (j - 1) % 101 != 0) { return j; } } return min; static bool IsPrime(int candidate) { if (((uint)candidate & (true ? 1u : 0u)) != 0) { int num2 = (int)Math.Sqrt(candidate); for (int k = 3; k <= num2; k += 2) { if (candidate % k == 0) { return false; } } return true; } return candidate == 2; } } private void ClearPeerSet() { _peersLock.EnterWriteLock(); _headPeer = null; if (_lastIndex > 0) { Array.Clear(_slots, 0, _lastIndex); Array.Clear(_buckets, 0, _buckets.Length); _lastIndex = 0; _count = 0; _freeList = -1; } _peersArray = new NetPeer[32]; _peersLock.ExitWriteLock(); } private bool ContainsPeer(NetPeer item) { if (item == null) { NetDebug.WriteError($"Contains peer null: {item}"); return false; } if (_buckets != null) { int num = item.GetHashCode() & 0x7FFFFFFF; for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next) { if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(item)) { return true; } } } return false; } public NetPeer GetPeerById(int id) { if (id < 0 || id >= _peersArray.Length) { return null; } return _peersArray[id]; } public bool TryGetPeerById(int id, out NetPeer peer) { peer = GetPeerById(id); return peer != null; } private void AddPeer(NetPeer peer) { if (peer == null) { NetDebug.WriteError($"Add peer null: {peer}"); return; } _peersLock.EnterWriteLock(); if (_headPeer != null) { peer.NextPeer = _headPeer; _headPeer.PrevPeer = peer; } _headPeer = peer; AddPeerToSet(peer); if (peer.Id >= _peersArray.Length) { int num = _peersArray.Length * 2; while (peer.Id >= num) { num *= 2; } Array.Resize(ref _peersArray, num); } _peersArray[peer.Id] = peer; _peersLock.ExitWriteLock(); } private void RemovePeer(NetPeer peer, bool enableWriteLock) { if (enableWriteLock) { _peersLock.EnterWriteLock(); } if (!RemovePeerFromSet(peer)) { if (enableWriteLock) { _peersLock.ExitWriteLock(); } return; } if (peer == _headPeer) { _headPeer = peer.NextPeer; } if (peer.PrevPeer != null) { peer.PrevPeer.NextPeer = peer.NextPeer; } if (peer.NextPeer != null) { peer.NextPeer.PrevPeer = peer.PrevPeer; } peer.PrevPeer = null; _peersArray[peer.Id] = null; _peerIds.Enqueue(peer.Id); if (enableWriteLock) { _peersLock.ExitWriteLock(); } } private bool RemovePeerFromSet(NetPeer peer) { if (_buckets == null || peer == null) { return false; } int num = peer.GetHashCode() & 0x7FFFFFFF; int num2 = num % _buckets.Length; int num3 = -1; for (int num4 = _buckets[num2] - 1; num4 >= 0; num4 = _slots[num4].Next) { if (_slots[num4].HashCode == num && _slots[num4].Value.Equals(peer)) { if (num3 < 0) { _buckets[num2] = _slots[num4].Next + 1; } else { _slots[num3].Next = _slots[num4].Next; } _slots[num4].HashCode = -1; _slots[num4].Value = null; _slots[num4].Next = _freeList; _count--; if (_count == 0) { _lastIndex = 0; _freeList = -1; } else { _freeList = num4; } return true; } num3 = num4; } return false; } private bool TryGetPeer(IPEndPoint endPoint, out NetPeer actualValue) { if (_buckets != null) { int num = endPoint.GetHashCode() & 0x7FFFFFFF; _peersLock.EnterReadLock(); for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next) { if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(endPoint)) { actualValue = _slots[num2].Value; _peersLock.ExitReadLock(); return true; } } _peersLock.ExitReadLock(); } actualValue = null; return false; } private bool TryGetPeer(SocketAddress saddr, out NetPeer actualValue) { if (_buckets != null) { int num = saddr.GetHashCode() & 0x7FFFFFFF; _peersLock.EnterReadLock(); for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next) { if (_slots[num2].HashCode == num && _slots[num2].Value.Serialize().Equals(saddr)) { actualValue = _slots[num2].Value; _peersLock.ExitReadLock(); return true; } } _peersLock.ExitReadLock(); } actualValue = null; return false; } private bool AddPeerToSet(NetPeer value) { if (_buckets == null) { int num = HashSetGetPrime(0); _buckets = new int[num]; _slots = new Slot[num]; } int num2 = value.GetHashCode() & 0x7FFFFFFF; int num3 = num2 % _buckets.Length; for (int num4 = _buckets[num2 % _buckets.Length] - 1; num4 >= 0; num4 = _slots[num4].Next) { if (_slots[num4].HashCode == num2 && _slots[num4].Value.Equals(value)) { return false; } } int num5; if (_freeList >= 0) { num5 = _freeList; _freeList = _slots[num5].Next; } else { if (_lastIndex == _slots.Length) { int num6 = 2 * _count; num6 = (((uint)num6 > 2147483587u && 2147483587 > _count) ? 2147483587 : HashSetGetPrime(num6)); Slot[] array = new Slot[num6]; Array.Copy(_slots, 0, array, 0, _lastIndex); _buckets = new int[num6]; for (int i = 0; i < _lastIndex; i++) { int num7 = array[i].HashCode % num6; array[i].Next = _buckets[num7] - 1; _buckets[num7] = i + 1; } _slots = array; num3 = num2 % _buckets.Length; } num5 = _lastIndex; _lastIndex++; } _slots[num5].HashCode = num2; _slots[num5].Value = value; _slots[num5].Next = _buckets[num3] - 1; _buckets[num3] = num5 + 1; _count++; return true; } private NetPacket PoolGetWithData(PacketProperty property, byte[] data, int start, int length) { int headerSize = NetPacket.GetHeaderSize(property); NetPacket netPacket = PoolGetPacket(length + headerSize); netPacket.Property = property; Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length); return netPacket; } private NetPacket PoolGetWithProperty(PacketProperty property, int size) { NetPacket netPacket = PoolGetPacket(size + NetPacket.GetHeaderSize(property)); netPacket.Property = property; return netPacket; } private NetPacket PoolGetWithProperty(PacketProperty property) { NetPacket netPacket = PoolGetPacket(NetPacket.GetHeaderSize(property)); netPacket.Property = property; return netPacket; } internal NetPacket PoolGetPacket(int size) { if (size > NetConstants.MaxPacketSize) { return new NetPacket(size); } NetPacket poolHead; lock (_poolLock) { poolHead = _poolHead; if (poolHead == null) { return new NetPacket(size); } _poolHead = _poolHead.Next; _poolCount--; } poolHead.Size = size; if (poolHead.RawData.Length < size) { poolHead.RawData = new byte[size]; } return poolHead; } internal void PoolRecycle(NetPacket packet) { if (packet.RawData.Length > NetConstants.MaxPacketSize || _poolCount >= PacketPoolSize) { return; } packet.RawData[0] = 0; lock (_poolLock) { packet.Next = _poolHead; _poolHead = packet; _poolCount++; } } static NetManager() { Primes = new int[72] { 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 }; MulticastAddressV6 = IPAddress.Parse("ff02::1"); IPv6Support = Socket.OSSupportsIPv6; } private bool ProcessError(SocketException ex) { switch (ex.SocketErrorCode) { case SocketError.NotConnected: NotConnected = true; return true; case SocketError.OperationAborted: case SocketError.Interrupted: case SocketError.NotSocket: return true; default: NetDebug.WriteError($"[R]Error code: {(int)ex.SocketErrorCode} - {ex}"); CreateEvent(NetEvent.EType.Error, null, null, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); break; case SocketError.WouldBlock: case SocketError.MessageSize: case SocketError.NetworkReset: case SocketError.ConnectionReset: case SocketError.TimedOut: break; } return false; } private void ManualReceive(Socket socket, EndPoint bufferEndPoint, int maxReceive) { try { int num = 0; while (socket.Available > 0) { ReceiveFrom(socket, ref bufferEndPoint); num++; if (num == maxReceive) { break; } } } catch (SocketException ex) { ProcessError(ex); } catch (ObjectDisposedException) { } catch (Exception ex3) { NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex3); } } private void NativeReceiveLogic() { IntPtr handle = _udpSocketv4.Handle; IntPtr s2 = _udpSocketv6?.Handle ?? IntPtr.Zero; byte[] address2 = new byte[16]; byte[] address3 = new byte[28]; IPEndPoint tempEndPoint = new IPEndPoint(IPAddress.Any, 0); List<Socket> list = new List<Socket>(2); Socket udpSocketv = _udpSocketv4; Socket udpSocketv2 = _udpSocketv6; NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize); while (IsRunning) { try { if (udpSocketv2 == null) { if (!NativeReceiveFrom(handle, address2)) { break; } continue; } bool flag = false; if (udpSocketv.Available != 0 || list.Contains(udpSocketv)) { if (!NativeReceiveFrom(handle, address2)) { break; } flag = true; } if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2)) { if (!NativeReceiveFrom(s2, address3)) { break; } flag = true; } list.Clear(); if (!flag) { list.Add(udpSocketv); list.Add(udpSocketv2); Socket.Select(list, null, null, 500000); } } catch (SocketException ex) { if (ProcessError(ex)) { break; } } catch (ObjectDisposedException) { break; } catch (ThreadAbortException) { break; } catch (Exception ex4) { NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4); } } bool NativeReceiveFrom(IntPtr s, byte[] address) { int socketAddressSize = address.Length; packet.Size = NativeSocket.RecvFrom(s, packet.RawData, NetConstants.MaxPacketSize, address, ref socketAddressSize); if (packet.Size == 0) { return true; } if (packet.Size == -1) { return !ProcessError(new SocketException((int)NativeSocket.GetSocketError())); } short num = (short)((address[1] << 8) | address[0]); tempEndPoint.Port = (ushort)((address[2] << 8) | address[3]); if ((NativeSocket.UnixMode && num == 10) || (!NativeSocket.UnixMode && num == 23)) { uint num2 = (uint)((address[27] << 24) + (address[26] << 16) + (address[25] << 8) + address[24]); byte[] array = new byte[16]; Buffer.BlockCopy(address, 8, array, 0, 16); tempEndPoint.Address = new IPAddress(array, num2); } else { long newAddress = (uint)((address[4] & 0xFF) | ((address[5] << 8) & 0xFF00) | ((address[6] << 16) & 0xFF0000) | (address[7] << 24)); tempEndPoint.Address = new IPAddress(newAddress); } if (TryGetPeer(tempEndPoint, out var actualValue)) { OnMessageReceived(packet, actualValue); } else { OnMessageReceived(packet, tempEndPoint); tempEndPoint = new IPEndPoint(IPAddress.Any, 0); } packet = PoolGetPacket(NetConstants.MaxPacketSize); return true; } } private void ReceiveFrom(Socket s, ref EndPoint bufferEndPoint) { NetPacket netPacket = PoolGetPacket(NetConstants.MaxPacketSize); netPacket.Size = s.ReceiveFrom(netPacket.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, ref bufferEndPoint); OnMessageReceived(netPacket, (IPEndPoint)bufferEndPoint); } private void ReceiveLogic() { EndPoint bufferEndPoint = new IPEndPoint(IPAddress.Any, 0); EndPoint bufferEndPoint2 = new IPEndPoint(IPAddress.IPv6Any, 0); List<Socket> list = new List<Socket>(2); Socket udpSocketv = _udpSocketv4; Socket udpSocketv2 = _udpSocketv6; while (IsRunning) { try { if (udpSocketv2 == null) { if (udpSocketv.Available != 0 || udpSocketv.Poll(500000, SelectMode.SelectRead)) { ReceiveFrom(udpSocketv, ref bufferEndPoint); } continue; } bool flag = false; if (udpSocketv.Available != 0 || list.Contains(udpSocketv)) { ReceiveFrom(udpSocketv, ref bufferEndPoint); flag = true; } if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2)) { ReceiveFrom(udpSocketv2, ref bufferEndPoint2); flag = true; } list.Clear(); if (!flag) { list.Add(udpSocketv); list.Add(udpSocketv2); Socket.Select(list, null, null, 500000); } } catch (SocketException ex) { if (ProcessError(ex)) { break; } } catch (ObjectDisposedException) { break; } catch (ThreadAbortException) { break; } catch (Exception ex4) { NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4); } } } public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool manualMode) { if (IsRunning && !NotConnected) { return false; } NotConnected = false; _manualMode = manualMode; UseNativeSockets = UseNativeSockets && NativeSocket.IsSupported; _udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port))) { return false; } LocalPort = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port; IsRunning = true; if (_manualMode) { _bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0); } if (IPv6Support && IPv6Enabled) { _udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort))) { if (_manualMode) { _bufferEndPointv6 = new IPEndPoint(IPAddress.IPv6Any, 0); } } else { _udpSocketv6 = null; } } if (!manualMode) { ThreadStart start = ReceiveLogic; if (UseNativeSockets) { start = NativeReceiveLogic; } _receiveThread = new Thread(start) { Name = $"ReceiveThread({LocalPort})", IsBackground = true }; _receiveThread.Start(); if (_logicThread == null) { _logicThread = new Thread(UpdateLogic) { Name = "LogicThread", IsBackground = true }; _logicThread.Start(); } } return true; } private bool BindSocket(Socket socket, IPEndPoint ep) { socket.ReceiveTimeout = 500; socket.SendTimeout = 500; socket.ReceiveBufferSize = 1048576; socket.SendBufferSize = 1048576; socket.Blocking = true; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { try { socket.IOControl(-1744830452, new byte[1], null); } catch { } } try { socket.ExclusiveAddressUse = !ReuseAddress; socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ReuseAddress); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, DontRoute); } catch { } if (ep.AddressFamily == AddressFamily.InterNetwork) { Ttl = 255; try { socket.EnableBroadcast = true; } catch (SocketException ex) { NetDebug.WriteError($"[B]Broadcast error: {ex.SocketErrorCode}"); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { try { socket.DontFragment = true; } catch (SocketException ex2) { NetDebug.WriteError($"[B]DontFragment error: {ex2.SocketErrorCode}"); } } } try { socket.Bind(ep); if (ep.AddressFamily == AddressFamily.InterNetworkV6) { try { socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(MulticastAddressV6)); } catch (Exception) { } } } catch (SocketException ex4) { switch (ex4.SocketErrorCode) { case SocketError.AddressAlreadyInUse: if (socket.AddressFamily == AddressFamily.InterNetworkV6) { try { socket.DualMode = false; socket.Bind(ep); } catch (SocketException ex5) { NetDebug.WriteError($"[B]Bind exception: {ex5}, errorCode: {ex5.SocketErrorCode}"); return false; } return true; } break; case SocketError.AddressFamilyNotSupported: return true; } NetDebug.WriteError($"[B]Bind exception: {ex4}, errorCode: {ex4.SocketErrorCode}"); return false; } return true; } internal int SendRawAndRecycle(NetPacket packet, IPEndPoint remoteEndPoint) { int result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); PoolRecycle(packet); return result; } internal int SendRaw(NetPacket packet, IPEndPoint remoteEndPoint) { return SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); } internal unsafe int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEndPoint) { if (!IsRunning) { return 0; } NetPacket netPacket = null; if (_extraPacketLayer != null) { netPacket = PoolGetPacket(length + _extraPacketLayer.ExtraPacketSizeForLayer); Buffer.BlockCopy(message, start, netPacket.RawData, 0, length); start = 0; _extraPacketLayer.ProcessOutBoundPacket(ref remoteEndPoint, ref netPacket.RawData, ref start, ref length); message = netPacket.RawData; } Socket socket = _udpSocketv4; if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support) { socket = _udpSocketv6; if (socket == null) { return 0; } } int num; try { if (UseNativeSockets && remoteEndPoint is NetPeer netPeer) { fixed (byte* pinnedBuffer = &message[start]) { num = NativeSocket.SendTo(socket.Handle, pinnedBuffer, length, netPeer.NativeAddress, netPeer.NativeAddress.Length); } if (num == -1) { throw NativeSocket.GetSocketException(); } } else { num = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint); } } catch (SocketException ex) { switch (ex.SocketErrorCode) { case SocketError.Interrupted: case SocketError.NoBufferSpaceAvailable: return 0; case SocketError.MessageSize: return 0; case SocketError.NetworkUnreachable: case SocketError.HostUnreachable: if (DisconnectOnUnreachable && remoteEndPoint is NetPeer peer) { DisconnectPeerForce(peer, (ex.SocketErrorCode == SocketError.HostUnreachable) ? DisconnectReason.HostUnreachable : DisconnectReason.NetworkUnreachable, ex.SocketErrorCode, null); } CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); return -1; case SocketError.Shutdown: CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0); return -1; default: NetDebug.WriteError($"[S] {ex}"); return -1; } } catch (Exception arg) { NetDebug.WriteError($"[S] {arg}"); return 0; } finally { if (netPacket != null) { PoolRecycle(netPacket); } } if (num <= 0) { return 0; } if (EnableStatistics) { Statistics.IncrementPacketsSent(); Statistics.AddBytesSent(length); } return num; } public bool SendBroadcast(NetDataWriter writer, int port) { return SendBroadcast(writer.Data, 0, writer.Length, port); } public bool SendBroadcast(byte[] data, int port) { return SendBroadcast(data, 0, data.Length, port); } public bool SendBroadcast(byte[] data, int start, int length, int port) { if (!IsRunning) { return false; } NetPacket netPacket; if (_extraPacketLayer != null) { int headerSize = NetPacket.GetHeaderSize(PacketProperty.Broadcast); netPacket = PoolGetPacket(headerSize + length + _extraPacketLayer.ExtraPacketSizeForLayer); netPacket.Property = PacketProperty.Broadcast; Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length); int offset = 0; int length2 = length + headerSize; IPEndPoint endPoint = null; _extraPacketLayer.ProcessOutBoundPacket(ref endPoint, ref netPacket.RawData, ref offset, ref length2); } else { netPacket = PoolGetWithData(PacketProperty.Broadcast, data, start, length); } bool flag = false; bool flag2 = false; try { flag = _udpSocketv4.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port)) > 0; if (_udpSocketv6 != null) { flag2 = _udpSocketv6.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(MulticastAddressV6, port)) > 0; } } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.HostUnreachable) { return flag; } NetDebug.WriteError($"[S][MCAST] {ex}"); return flag; } catch (Exception arg) { NetDebug.WriteError($"[S][MCAST] {arg}"); return flag; } finally { PoolRecycle(netPacket); } return flag || flag2; } private void CloseSocket() { IsRunning = false; _udpSocketv4?.Close(); _udpSocketv6?.Close(); _udpSocketv4 = null; _udpSocketv6 = null; if (_receiveThread != null && _receiveThread != Thread.CurrentThread) { _receiveThread.Join(); } _receiveThread = null; } } internal enum PacketProperty : byte { Unreliable, Channeled, Ack, Ping, Pong, ConnectRequest, ConnectAccept, Disconnect, UnconnectedMessage, MtuCheck, MtuOk, Broadcast, Merged, ShutdownOk, PeerNotFound, InvalidProtocol, NatMessage, Empty } internal sealed class NetPacket { private static readonly int PropertiesCount; private static readonly int[] HeaderSizes; public byte[] RawData; public int Size; public object UserData; public NetPacket Next; public PacketProperty Property { get { return (PacketProperty)(RawData[0] & 0x1Fu); } set { RawData[0] = (byte)((RawData[0] & 0xE0u) | (uint)value); } } public byte ConnectionNumber { get { return (byte)((RawData[0] & 0x60) >> 5); } set { RawData[0] = (byte)((RawData[0] & 0x9Fu) | (uint)(value << 5)); } } public ushort Sequence { get { return BitConverter.ToUInt16(RawData, 1); } set { FastBitConverter.GetBytes(RawData, 1, value); } } public bool IsFragmented => (RawData[0] & 0x80) != 0; public byte ChannelId { get { return RawData[3]; } set { RawData[3] = value; } } public ushort FragmentId { get { return BitConverter.ToUInt16(RawData, 4); } set { FastBitConverter.GetBytes(RawData, 4, value); } } public ushort FragmentPart { get { return BitConverter.ToUInt16(RawData, 6); } set { FastBitConverter.GetBytes(RawData, 6, value); } } public ushort FragmentsTotal { get { return BitConverter.ToUInt16(RawData, 8); } set { FastBitConverter.GetBytes(RawData, 8, value); } } static NetPacket() { PropertiesCount = Enum.GetValues(typeof(PacketProperty)).Length; HeaderSizes = NetUtils.AllocatePinnedUninitializedArray<int>(PropertiesCount); for (int i = 0; i < HeaderSizes.Length; i++) { switch ((PacketProperty)(byte)i) { case PacketProperty.Channeled: case PacketProperty.Ack: HeaderSizes[i] = 4; break; case PacketProperty.Ping: HeaderSizes[i] = 3; break; case PacketProperty.ConnectRequest: HeaderSizes[i] = 18; break; case PacketProperty.ConnectAccept: HeaderSizes[i] = 15; break; case PacketProperty.Disconnect: HeaderSizes[i] = 9; break; case PacketProperty.Pong: HeaderSizes[i] = 11; break; default: HeaderSizes[i] = 1; break; } } } public void MarkFragmented() { RawData[0] |= 128; } public NetPacket(int size) { RawData = new byte[size]; Size = size; } public NetPacket(PacketProperty property, int size) { size += GetHeaderSize(property); RawData = new byte[size]; Property = property; Size = size; } public static int GetHeaderSize(PacketProperty property) { return HeaderSizes[(uint)property]; } public int GetHeaderSize() { return HeaderSizes[RawData[0] & 0x1F]; } public bool Verify() { byte b = (byte)(RawData[0] & 0x1Fu); if (b >= PropertiesCount) { return false; } int num = HeaderSizes[b]; bool flag = (RawData[0] & 0x80) != 0; if (Size >= num) { if (flag) { return Size >= num + 6; } return true; } return false; } } [Flags] public enum ConnectionState : byte { Outgoing = 2, Connected = 4, ShutdownRequested = 8, Disconnected = 0x10, EndPointChange = 0x20, Any = 0x2E } internal enum ConnectRequestResult { None, P2PLose, Reconnection, NewConnection } internal enum DisconnectResult { None, Reject, Disconnect } internal enum ShutdownResult { None, Success, WasConnected } public class NetPeer : IPEndPoint { private class IncomingFragments { public NetPacket[] Fragments; public int ReceivedCount; public int TotalSize; public byte ChannelId; } private int _rtt; private int _avgRtt; private int _rttCount; private double _resendDelay = 27.0; private float _pingSendTimer; private float _rttResetTimer; private readonly Stopwatch _pingTimer = new Stopwatch(); private volatile float _timeSinceLastPacket; private long _remoteDelta; private readonly object _shutdownLock = new object(); internal volatile NetPeer NextPeer; internal NetPeer PrevPeer; private NetPacket[] _unreliableSecondQueue; private NetPacket[] _unreliableChannel; private int _unreliablePendingCount; private readonly object _unreliableChannelLock = new object(); private readonly ConcurrentQueue<BaseChannel> _channelSendQueue; private readonly BaseChannel[] _channels; private int _mtu; private int _mtuIdx; private bool _finishMtu; private float _mtuCheckTimer; private int _mtuCheckAttempts; private const int MtuCheckDelay = 1000; private const int MaxMtuCheckAttempts = 4; private readonly object _mtuMutex = new object(); private int _fragmentId; private readonly Dictionary<ushort, IncomingFragments> _holdedFragments; private readonly Dictionary<ushort, ushort> _deliveredFragments; private readonly NetPacket _mergeData; private int _mergePos; private int _mergeCount; private int _connectAttempts; private float _connectTimer; private long _connectTime; private byte _connectNum; private ConnectionState _connectionState; private NetPacket _shutdownPacket; private const int ShutdownDelay = 300; private float _shutdownTimer; private readonly NetPacket _pingPacket; private readonly NetPacket _pongPacket; private readonly NetPacket _connectRequestPacket; private readonly NetPacket _connectAcceptPacket; public readonly NetManager NetManager; public readonly int Id; public object Tag; public readonly NetStatistics Statistics; private SocketAddress _cachedSocketAddr; private int _cachedHashCode; internal byte[] NativeAddress; internal byte ConnectionNum { get { return _connectNum; } private set { _connectNum = value; _mergeData.ConnectionNumber = value; _pingPacket.ConnectionNumber = value; _pongPacket.ConnectionNumber = value; } } public ConnectionState ConnectionState => _connectionState; internal long ConnectTime => _connectTime; public int RemoteId { get; private set; } public int Ping => _avgRtt / 2; public int RoundTripTime => _avgRtt; public int Mtu => _mtu; public long RemoteTimeDelta => _remoteDelta; public DateTime RemoteUtcTime => new DateTime(DateTime.UtcNow.Ticks + _remoteDelta); public float TimeSinceLastPacket => _timeSinceLastPacket; internal double ResendDelay => _resendDelay; public override SocketAddress Serialize() { return _cachedSocketAddr; } public override int GetHashCode() { return _cachedHashCode; } internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) : base(remoteEndPoint.Address, remoteEndPoint.Port) { Id = id; Statistics = new NetStatistics(); NetManager = netManager; _cachedSocketAddr = base.Serialize(); if (NetManager.UseNativeSockets) { NativeAddress = new byte[_cachedSocketAddr.Size]; for (int i = 0; i < _cachedSocketAddr.Size; i++) { NativeAddress[i] = _cachedSocketAddr[i]; } } _cachedHashCode = base.GetHashCode(); ResetMtu(); _connectionState = ConnectionState.Connected; _mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize); _pongPacket = new NetPacket(PacketProperty.Pong, 0); _pingPacket = new NetPacket(PacketProperty.Ping, 0) { Sequence = 1 }; _unreliableSecondQueue = new NetPacket[8]; _unreliableChannel = new NetPacket[8]; _holdedFragments = new Dictionary<ushort, IncomingFragments>(); _deliveredFragments = new Dictionary<ushort, ushort>(); _channels = new BaseChannel[netManager.ChannelsCount * 4]; _channelSendQueue = new ConcurrentQueue<BaseChannel>(); } internal void InitiateEndPointChange() { ResetMtu(); _connectionState = ConnectionState.EndPointChange; } internal void FinishEndPointChange(IPEndPoint newEndPoint) { if (_connectionState != ConnectionState.EndPointChange) { return; } _connectionState = ConnectionState.Connected; base.Address = newEndPoint.Address; base.Port = newEndPoint.Port; if (NetManager.UseNativeSockets) { NativeAddress = new byte[_cachedSocketAddr.Size]; for (int i = 0; i < _cachedSocketAddr.Size; i++) { NativeAddress[i] = _cachedSocketAddr[i]; } } _cachedSocketAddr = base.Serialize(); _cachedHashCode = base.GetHashCode(); } internal void ResetMtu() { _finishMtu = !NetManager.MtuDiscovery; if (NetManager.MtuOverride > 0) { OverrideMtu(NetManager.MtuOverride); } else { SetMtu(0); } } private void SetMtu(int mtuIdx) { _mtuIdx = mtuIdx; _mtu = NetConstants.PossibleMtu[mtuIdx] - NetManager.ExtraPacketSizeForLayer; } private void OverrideMtu(int mtuValue) { _mtu = mtuValue; _finishMtu = true; } public int GetPacketsCountInReliableQueue(byte channelNumber, bool ordered) { int num = channelNumber * 4 + (ordered ? 2 : 0); BaseChannel baseChannel = _channels[num]; if (baseChannel == null) { return 0; } return ((ReliableChannel)baseChannel).PacketsInQueue; } public PooledPacket CreatePacketFromPool(DeliveryMethod deliveryMethod, byte channelNumber) { int mtu = _mtu; NetPacket netPacket = NetManager.PoolGetPacket(mtu); if (deliveryMethod == DeliveryMethod.Unreliable) { netPacket.Property = PacketProperty.Unreliable; return new PooledPacket(netPacket, mtu, 0); } netPacket.Property = PacketProperty.Channeled; return new PooledPacket(netPacket, mtu, (byte)((uint)(channelNumber * 4) + (uint)deliveryMethod)); } public void SendPooledPacket(PooledPacket packet, int userDataSize) { if (_connectionState == ConnectionState.Connected) { packet._packet.Size = packet.UserDataOffset + userDataSize; if (packet._packet.Property == PacketProperty.Channeled) { CreateChannel(packet._channelNumber).AddToQueue(packet._packet); } else { EnqueueUnreliable(packet._packet); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EnqueueUnreliable(NetPacket packet) { lock (_unreliableChannelLock) { if (_unreliablePendingCount == _unreliableChannel.Length) { Array.Resize(ref _unreliableChannel, _unreliablePendingCount * 2); } _unreliableChannel[_unreliablePendingCount++] = packet; } } private BaseChannel CreateChannel(byte idx) { BaseChannel baseChannel = _channels[idx]; if (baseChannel != null) { return baseChannel; } switch ((DeliveryMethod)(byte)(idx % 4)) { case DeliveryMethod.ReliableUnordered: baseChannel = new ReliableChannel(this, ordered: false, idx); break; case DeliveryMethod.Sequenced: baseChannel = new SequencedChannel(this, reliable: false, idx); break; case DeliveryMethod.ReliableOrdered: baseChannel = new ReliableChannel(this, ordered: true, idx); break; case DeliveryMethod.ReliableSequenced: baseChannel = new SequencedChannel(this, reliable: true, idx); break; } Ba