From 5d281c9fb2ed80b3828c70200a67ae906871ed84 Mon Sep 17 00:00:00 2001 From: Bob Da Ross <52760019+BobDaRoss@users.noreply.github.com> Date: Mon, 13 Sep 2021 23:00:18 -0500 Subject: [PATCH 1/5] Removed cheap timer hack --- SeamlessClient.cs | 52 ++++++++++++------------------- SeamlessTransfer/PingServer.cs | 5 --- SeamlessTransfer/SwitchServers.cs | 3 +- Utilities/Patches.cs | 26 ++++++++++++++-- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/SeamlessClient.cs b/SeamlessClient.cs index 1e616cd..6a5b996 100644 --- a/SeamlessClient.cs +++ b/SeamlessClient.cs @@ -18,6 +18,7 @@ using System.Text; using System.Threading.Tasks; using System.Timers; using System.Windows.Forms; +using VRage.Game.ModAPI; using VRage.Input; using VRage.Plugins; using VRage.Utils; @@ -124,51 +125,31 @@ namespace SeamlessClientPlugin { Patches.GetPatches(); TryShow("Running Seamless Client Plugin v[" + Version + "]"); - PingTimer.Elapsed += PingTimer_Elapsed; - PingTimer.Start(); + // PingTimer.Elapsed += PingTimer_Elapsed; + // PingTimer.Start(); + + + + } + public void Update() { if (MyAPIGateway.Multiplayer == null) return; + if (!Initilized) { TryShow("Initilizing Communications!"); RunInitilizations(); } - - - - //OnNewPlayerRequest - //throw new NotImplementedException(); } - - - private void PingTimer_Elapsed(object sender, ElapsedEventArgs e) - { - // Terrible way to make sure server knows we are running seamless client - try - { - - - ClientMessage PingServer = new ClientMessage(ClientMessageType.FirstJoin); - MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetID, Utilities.Utility.Serialize(PingServer)); - } - catch (Exception ex) - { - //TryShow(ex.ToString()); - } - } - - - - public static void RunInitilizations() { MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(SeamlessClientNetID, MessageHandler); @@ -189,12 +170,17 @@ namespace SeamlessClientPlugin try { ClientMessage Recieved = Utilities.Utility.Deserialize(obj2); - if (Recieved.MessageType == ClientMessageType.TransferServer) + + if(Recieved.MessageType == ClientMessageType.FirstJoin) { + //Server sent a first join message! Send a reply back so the server knows what version we are on + ClientMessage PingServer = new ClientMessage(ClientMessageType.FirstJoin); + MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetID, Utilities.Utility.Serialize(PingServer)); + } + else if (Recieved.MessageType == ClientMessageType.TransferServer) + { + //Server sent a transfer message! Begin transfer via seamless Transfer TransferMessage = Recieved.GetTransferData(); - - - ServerPing.StartServerPing(TransferMessage); } } @@ -213,6 +199,8 @@ namespace SeamlessClientPlugin MyLog.Default?.WriteLineAndConsole($"SeamlessClient: {message}"); } + + public void Dispose() { DisposeInitilizations(); diff --git a/SeamlessTransfer/PingServer.cs b/SeamlessTransfer/PingServer.cs index 5ec2162..218e9ea 100644 --- a/SeamlessTransfer/PingServer.cs +++ b/SeamlessTransfer/PingServer.cs @@ -42,11 +42,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer SwitchServers Switcher = new SwitchServers(E, Request.DeserializeWorldData()); Switcher.BeginSwitch(); - - // MyGameService.OnPingServerResponded += PingResponded; - //MyGameService.OnPingServerFailedToRespond += FailedToRespond; - - //MyGameService.PingServer(Transfer.IPAdress); } } } diff --git a/SeamlessTransfer/SwitchServers.cs b/SeamlessTransfer/SwitchServers.cs index d616365..00e1a4e 100644 --- a/SeamlessTransfer/SwitchServers.cs +++ b/SeamlessTransfer/SwitchServers.cs @@ -123,9 +123,10 @@ namespace SeamlessClientPlugin.SeamlessTransfer RemoveOldEntities(); UpdateWorldGenerator(); - StartEntitySync(); + + MyModAPIHelper.Initialize(); // Allow the game to start proccessing incoming messages in the buffer MyMultiplayer.Static.StartProcessingClientMessages(); diff --git a/Utilities/Patches.cs b/Utilities/Patches.cs index f575607..23a4eb1 100644 --- a/Utilities/Patches.cs +++ b/Utilities/Patches.cs @@ -9,6 +9,8 @@ using Sandbox.Game.World; using Sandbox.Game.World.Generator; using Sandbox.Graphics; using Sandbox.Graphics.GUI; +using Sandbox.ModAPI; +using SeamlessClientPlugin.ClientMessages; using System; using System.Collections.Generic; using System.IO; @@ -115,23 +117,31 @@ namespace SeamlessClientPlugin.SeamlessTransfer - MethodInfo ConnectToServer = GetMethod(typeof(MyGameService), "ConnectToServer", BindingFlags.Static | BindingFlags.Public); + //MethodInfo ConnectToServer = GetMethod(typeof(MyGameService), "ConnectToServer", BindingFlags.Static | BindingFlags.Public); MethodInfo LoadingScreenDraw = GetMethod(typeof(MyGuiScreenLoading), "DrawInternal", BindingFlags.Instance | BindingFlags.NonPublic); + + Patcher.Patch(LoadingScreenDraw, prefix: new HarmonyMethod(GetPatchMethod(nameof(DrawInternal)))); Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined)))); Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession)))); - //Patcher.Patch(ConnectToServer, prefix: new HarmonyMethod(GetPatchMethod(nameof(OnConnectToServer)))); } + + + private static MethodInfo GetPatchMethod(string v) { return typeof(Patches).GetMethod(v, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } + + + + #region LoadingScreen /* Loading Screen Stuff */ @@ -142,6 +152,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer private static bool LoadMultiplayerSession(MyObjectBuilder_World world, MyMultiplayerBase multiplayerSession) { + if (SeamlessClient.IsSwitching) + return true; + MyLog.Default.WriteLine("LoadSession() - Start"); if (!MyWorkshop.CheckLocalModsAllowed(world.Checkpoint.Mods, allowLocalMods: false)) @@ -150,6 +163,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyLog.Default.WriteLine("LoadSession() - End"); return false; } + + MyWorkshop.DownloadModsAsync(world.Checkpoint.Mods, delegate (bool success) { if (success) @@ -302,6 +317,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer } } + + + private static bool OnConnectToServer(MyGameServerItem server, Action onDone) { if (SeamlessClient.IsSwitching) @@ -315,6 +333,10 @@ namespace SeamlessClientPlugin.SeamlessTransfer + + + /* Patch Utils */ + private static MethodInfo GetMethod(Type type, string MethodName, BindingFlags Flags) { try From 1f888260f2e56176ffc4b0103f157be427a402a2 Mon Sep 17 00:00:00 2001 From: Bob Da Ross <52760019+BobDaRoss@users.noreply.github.com> Date: Sat, 18 Sep 2021 23:56:52 -0500 Subject: [PATCH 2/5] Started mod unloading/loading --- SeamlessTransfer/ModLoader.cs | 84 ++++++++++++++++++++++++++++++- SeamlessTransfer/PingServer.cs | 2 + SeamlessTransfer/SwitchServers.cs | 28 ++++++++++- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/SeamlessTransfer/ModLoader.cs b/SeamlessTransfer/ModLoader.cs index 069301b..4c98be7 100644 --- a/SeamlessTransfer/ModLoader.cs +++ b/SeamlessTransfer/ModLoader.cs @@ -1,12 +1,17 @@ -using System; +using Sandbox.Definitions; +using Sandbox.Engine.Networking; +using Sandbox.Game.World; +using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; +using VRage.Game; namespace SeamlessClientPlugin.SeamlessTransfer { - public class ModLoader + public static class ModLoader { /* Mod loader should download and load missing mods for target server, and unload ones that arent needed * @@ -22,5 +27,80 @@ namespace SeamlessClientPlugin.SeamlessTransfer * */ + + //Mods that are currently loaded in this instance. + private static List CurrentLoadedMods = new List(); + + //Mods that we are switching to. + private static List TargetServerMods = new List(); + + + private static bool FinishedDownloadingMods = false; + private static bool DownloadSuccess = false; + + private static DateTime DownloadTimeout; + + + + + public static void DownloadNewMods(List Target) + { + CurrentLoadedMods = MySession.Static.Mods; + TargetServerMods = Target; + + + DownloadTimeout = DateTime.Now + TimeSpan.FromMinutes(5); + SeamlessClient.TryShow("Downloading New Mods"); + MyWorkshop.DownloadModsAsync(Target, ModDownloadingFinished); + + } + + private static void ModDownloadingFinished(bool Success) + { + if (Success) + { + SeamlessClient.TryShow("Mod Downloading Finished!"); + FinishedDownloadingMods = true; + DownloadSuccess = true; + //May need to wait seamless loading if mods have yet to finish downloading + } + else + { + DownloadSuccess = false; + FinishedDownloadingMods = true; + } + } + + public static void ReadyModSwitch() + { + + while (!FinishedDownloadingMods) + { + + //Break out of loop + if (DownloadTimeout < DateTime.Now) + break; + + + Thread.Sleep(20); + } + + FinishedDownloadingMods = false; + + //Skip mod switch + if (!DownloadSuccess) + return; + + MySession.Static.ScriptManager.LoadData(); + MyDefinitionManager.Static.LoadData(TargetServerMods); + MyLocalCache.PreloadLocalInventoryConfig(); + SeamlessClient.TryShow("Finished transfering!"); + + } + + + + + } } diff --git a/SeamlessTransfer/PingServer.cs b/SeamlessTransfer/PingServer.cs index 218e9ea..a081ee1 100644 --- a/SeamlessTransfer/PingServer.cs +++ b/SeamlessTransfer/PingServer.cs @@ -40,6 +40,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer SeamlessClient.TryShow("Beginning Redirect to server: " + Transfer.TargetServerID); + + SwitchServers Switcher = new SwitchServers(E, Request.DeserializeWorldData()); Switcher.BeginSwitch(); } diff --git a/SeamlessTransfer/SwitchServers.cs b/SeamlessTransfer/SwitchServers.cs index 00e1a4e..592c47b 100644 --- a/SeamlessTransfer/SwitchServers.cs +++ b/SeamlessTransfer/SwitchServers.cs @@ -1,4 +1,5 @@ using Sandbox; +using Sandbox.Definitions; using Sandbox.Engine.Multiplayer; using Sandbox.Engine.Networking; using Sandbox.Game; @@ -27,6 +28,7 @@ using VRage.Steam; using VRage.Utils; using VRageMath; using VRageRender; +using VRageRender.Messages; namespace SeamlessClientPlugin.SeamlessTransfer { @@ -42,6 +44,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer { this.TargetServer = TargetServer; this.TargetWorld = TargetWorld; + + ModLoader.DownloadNewMods(TargetWorld.Checkpoint.Mods); } @@ -115,11 +119,31 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyHud.Chat.RegisterChat(MyMultiplayer.Static); - MyMultiplayer.Static.OnSessionReady(); + LoadConnectedClients(); LoadOnlinePlayers(); SetWorldSettings(); + + + ModLoader.ReadyModSwitch(); + MySector.InitEnvironmentSettings(TargetWorld.Sector.Environment); + + + MyModAPIHelper.Initialize(); + string text = ((!string.IsNullOrEmpty(TargetWorld.Checkpoint.CustomSkybox)) ? TargetWorld.Checkpoint.CustomSkybox : MySector.EnvironmentDefinition.EnvironmentTexture); + MyRenderProxy.PreloadTextures(new string[1] { text }, TextureType.CubeMap); + MySession.Static.LoadDataComponents(); + MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents); + + + MethodInfo A = typeof(MySession).GetMethod("LoadGameDefinition", BindingFlags.Instance | BindingFlags.NonPublic); + A.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint }); + + + + MyMultiplayer.Static.OnSessionReady(); + RemoveOldEntities(); UpdateWorldGenerator(); @@ -127,7 +151,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer - MyModAPIHelper.Initialize(); + // Allow the game to start proccessing incoming messages in the buffer MyMultiplayer.Static.StartProcessingClientMessages(); From cf51b5f0e7361aadc4db474d9e9a1d352f880686 Mon Sep 17 00:00:00 2001 From: Bob Da Ross <52760019+BobDaRoss@users.noreply.github.com> Date: Sat, 6 Nov 2021 11:24:38 -0500 Subject: [PATCH 3/5] Added Mod Loading & Unloading --- SeamlessClient.cs | 2 +- SeamlessTransfer/ModLoader.cs | 3 ++- SeamlessTransfer/SwitchServers.cs | 12 +++++++++--- Utilities/Patches.cs | 12 +++++++++--- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/SeamlessClient.cs b/SeamlessClient.cs index 6a5b996..92b62ec 100644 --- a/SeamlessClient.cs +++ b/SeamlessClient.cs @@ -108,7 +108,7 @@ namespace SeamlessClientPlugin public static string Version = "1.3.04"; - public static bool Debug = false; + public static bool Debug = true; private static bool Initilized = false; diff --git a/SeamlessTransfer/ModLoader.cs b/SeamlessTransfer/ModLoader.cs index 4c98be7..8724b6d 100644 --- a/SeamlessTransfer/ModLoader.cs +++ b/SeamlessTransfer/ModLoader.cs @@ -91,11 +91,12 @@ namespace SeamlessClientPlugin.SeamlessTransfer if (!DownloadSuccess) return; + /* MySession.Static.ScriptManager.LoadData(); MyDefinitionManager.Static.LoadData(TargetServerMods); MyLocalCache.PreloadLocalInventoryConfig(); SeamlessClient.TryShow("Finished transfering!"); - + */ } diff --git a/SeamlessTransfer/SwitchServers.cs b/SeamlessTransfer/SwitchServers.cs index 592c47b..c170e9b 100644 --- a/SeamlessTransfer/SwitchServers.cs +++ b/SeamlessTransfer/SwitchServers.cs @@ -10,8 +10,10 @@ using Sandbox.Game.Multiplayer; using Sandbox.Game.SessionComponents; using Sandbox.Game.World; using Sandbox.Game.World.Generator; +using Sandbox.Graphics.GUI; using Sandbox.ModAPI; using SeamlessClientPlugin.Utilities; +using SpaceEngineers.Game.GUI; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -134,11 +136,11 @@ namespace SeamlessClientPlugin.SeamlessTransfer string text = ((!string.IsNullOrEmpty(TargetWorld.Checkpoint.CustomSkybox)) ? TargetWorld.Checkpoint.CustomSkybox : MySector.EnvironmentDefinition.EnvironmentTexture); MyRenderProxy.PreloadTextures(new string[1] { text }, TextureType.CubeMap); MySession.Static.LoadDataComponents(); - MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents); + // MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents); - MethodInfo A = typeof(MySession).GetMethod("LoadGameDefinition", BindingFlags.Instance | BindingFlags.NonPublic); - A.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint }); + //MethodInfo A = typeof(MySession).GetMethod("LoadGameDefinition", BindingFlags.Instance | BindingFlags.NonPublic); + // A.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint }); @@ -426,6 +428,10 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyMultiplayer.Static.ReplicationLayer.Dispose(); MyMultiplayer.Static.Dispose(); MyMultiplayer.Static = null; + + //Close any respawn screens that are open + MyGuiScreenMedicals.Close(); + } private void RemoveOldEntities() diff --git a/Utilities/Patches.cs b/Utilities/Patches.cs index 23a4eb1..bde0e47 100644 --- a/Utilities/Patches.cs +++ b/Utilities/Patches.cs @@ -121,13 +121,16 @@ namespace SeamlessClientPlugin.SeamlessTransfer MethodInfo LoadingScreenDraw = GetMethod(typeof(MyGuiScreenLoading), "DrawInternal", BindingFlags.Instance | BindingFlags.NonPublic); - + Patcher.Patch(LoadingScreenDraw, prefix: new HarmonyMethod(GetPatchMethod(nameof(DrawInternal)))); Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined)))); Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession)))); + + + } @@ -152,8 +155,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer private static bool LoadMultiplayerSession(MyObjectBuilder_World world, MyMultiplayerBase multiplayerSession) { - if (SeamlessClient.IsSwitching) - return true; + // + MyLog.Default.WriteLine("LoadSession() - Start"); @@ -164,6 +167,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer return false; } + MyLog.Default.WriteLine("Seamless Downloading mods!"); + + MyWorkshop.DownloadModsAsync(world.Checkpoint.Mods, delegate (bool success) { From 4bd456a05be4295c570a362e62e112b3337b8ae6 Mon Sep 17 00:00:00 2001 From: Bob Da Ross <52760019+BobDaRoss@users.noreply.github.com> Date: Mon, 14 Feb 2022 20:19:30 -0600 Subject: [PATCH 4/5] Mod switching --- SeamlessClient.cs | 12 +-- SeamlessClientPlugin.csproj | 1 + SeamlessTransfer/ModLoader.cs | 86 +++++++++++++++++--- SeamlessTransfer/MyScriptManagerLoader.cs | 83 +++++++++++++++++++ SeamlessTransfer/SwitchServers.cs | 97 ++++++++++++++++++++--- Utilities/Patches.cs | 80 ++++++++++++++++++- 6 files changed, 330 insertions(+), 29 deletions(-) create mode 100644 SeamlessTransfer/MyScriptManagerLoader.cs diff --git a/SeamlessClient.cs b/SeamlessClient.cs index 92b62ec..9cbc00a 100644 --- a/SeamlessClient.cs +++ b/SeamlessClient.cs @@ -114,7 +114,7 @@ namespace SeamlessClientPlugin public const ushort SeamlessClientNetID = 2936; - private static System.Timers.Timer PingTimer = new System.Timers.Timer(3000); + private static System.Timers.Timer PingTimer = new System.Timers.Timer(500); public static bool IsSwitching = false; public static bool RanJoin = false; @@ -123,10 +123,9 @@ namespace SeamlessClientPlugin public void Init(object gameInstance) { - Patches.GetPatches(); + TryShow("Running Seamless Client Plugin v[" + Version + "]"); - // PingTimer.Elapsed += PingTimer_Elapsed; - // PingTimer.Start(); + @@ -134,7 +133,6 @@ namespace SeamlessClientPlugin } - public void Update() { if (MyAPIGateway.Multiplayer == null) @@ -143,11 +141,14 @@ namespace SeamlessClientPlugin if (!Initilized) { + Patches.GetPatches(); TryShow("Initilizing Communications!"); RunInitilizations(); } } + + public static void RunInitilizations() @@ -158,7 +159,6 @@ namespace SeamlessClientPlugin public static void DisposeInitilizations() { - PingTimer.Stop(); MyAPIGateway.Multiplayer?.UnregisterSecureMessageHandler(SeamlessClientNetID, MessageHandler); Initilized = false; diff --git a/SeamlessClientPlugin.csproj b/SeamlessClientPlugin.csproj index 943e1bf..65311fa 100644 --- a/SeamlessClientPlugin.csproj +++ b/SeamlessClientPlugin.csproj @@ -163,6 +163,7 @@ + diff --git a/SeamlessTransfer/ModLoader.cs b/SeamlessTransfer/ModLoader.cs index 8724b6d..07fb895 100644 --- a/SeamlessTransfer/ModLoader.cs +++ b/SeamlessTransfer/ModLoader.cs @@ -1,13 +1,16 @@ using Sandbox.Definitions; using Sandbox.Engine.Networking; using Sandbox.Game.World; +using Sandbox.ModAPI; using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using VRage.Game; +using VRage.Game.GUI; namespace SeamlessClientPlugin.SeamlessTransfer { @@ -31,27 +34,55 @@ namespace SeamlessClientPlugin.SeamlessTransfer //Mods that are currently loaded in this instance. private static List CurrentLoadedMods = new List(); - //Mods that we are switching to. - private static List TargetServerMods = new List(); + + + + //Mods that we need to Load + private static List TargetLoadMods = new List(); + + //Mods that we need to UnLoad + private static List TargetUnLoadMods = new List(); private static bool FinishedDownloadingMods = false; private static bool DownloadSuccess = false; private static DateTime DownloadTimeout; + + private static MethodInfo PrepareBaseSession = typeof(MySession).GetMethod("PreloadModels", BindingFlags.Static | BindingFlags.NonPublic); + private static FieldInfo ScriptManager = typeof(MySession).GetField("ScriptManager", BindingFlags.Instance | BindingFlags.Public); + + + public static void DownloadNewMods(List Target) { CurrentLoadedMods = MySession.Static.Mods; - TargetServerMods = Target; + + + + //Loop through our current mods + foreach(var mod in CurrentLoadedMods) + { + if (!Target.Contains(mod)) + TargetUnLoadMods.Add(mod); + } + + + //Loop through our TargetMods + foreach(var mod in Target) + { + if (!CurrentLoadedMods.Contains(mod)) + TargetLoadMods.Add(mod); + } DownloadTimeout = DateTime.Now + TimeSpan.FromMinutes(5); SeamlessClient.TryShow("Downloading New Mods"); - MyWorkshop.DownloadModsAsync(Target, ModDownloadingFinished); + MyWorkshop.DownloadModsAsync(TargetLoadMods, ModDownloadingFinished); } @@ -71,7 +102,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer } } - public static void ReadyModSwitch() + + public static void ReadyModSwitch(MyObjectBuilder_Checkpoint checkpoint, MyObjectBuilder_Sector sector) { while (!FinishedDownloadingMods) @@ -91,16 +123,50 @@ namespace SeamlessClientPlugin.SeamlessTransfer if (!DownloadSuccess) return; - /* - MySession.Static.ScriptManager.LoadData(); + + + //Create new script manager? + ScriptManager.SetValue(MySession.Static, new MyScriptManager()); + + + MyGuiTextures.Static.Unload(); + MySession.Static.ScriptManager.Init(checkpoint.ScriptManagerData); MyDefinitionManager.Static.LoadData(TargetServerMods); + PrepareBaseSession.Invoke(null, new object[] { sector }); + + MyLocalCache.PreloadLocalInventoryConfig(); - SeamlessClient.TryShow("Finished transfering!"); - */ + + + //SeamlessClient.TryShow("Finished transfering!"); + + + // PrepareBaseSession.Invoke(MySession.Static, new object[] { TargetServerMods, null }); + + } - + private static void UnloadOldScripts() + { + // MySandboxGame.Log.WriteLine(string.Format("Script loaded: {0}", value.FullName)); + int amount = 0; + foreach (var mod in TargetUnLoadMods) + { + var val = MySession.Static.ScriptManager.Scripts.FirstOrDefault(x => x.Value.FullName.Contains(mod.PublishedFileId.ToString())); + MySession.Static.ScriptManager.Scripts.Remove(val.Key); + + amount++; + } + + SeamlessClient.TryShow($"Removed {amount} old scripts!"); + + + + } + + + } diff --git a/SeamlessTransfer/MyScriptManagerLoader.cs b/SeamlessTransfer/MyScriptManagerLoader.cs new file mode 100644 index 0000000..86d5eaa --- /dev/null +++ b/SeamlessTransfer/MyScriptManagerLoader.cs @@ -0,0 +1,83 @@ +using Sandbox; +using Sandbox.Game.World; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SeamlessClientPlugin.SeamlessTransfer +{ + public class MyScriptManagerLoader + { + /* + public void LoadData(MyScriptManager __instance) + { + MySandboxGame.Log.WriteLine("MyScriptManager.LoadData() - START"); + MySandboxGame.Log.IncreaseIndent(); + MyScriptManager.Static = __instance; + __instance.Scripts.Clear(); + __instance.EntityScripts.Clear(); + __instance.SubEntityScripts.Clear(); + + TryAddEntityScripts(MyModContext.BaseGame, MyPlugins.SandboxAssembly); + TryAddEntityScripts(MyModContext.BaseGame, MyPlugins.SandboxGameAssembly); + + if (MySession.Static.CurrentPath != null) + { + LoadScripts(MySession.Static.CurrentPath, MyModContext.BaseGame); + } + if (MySession.Static.Mods != null) + { + bool isServer = Sync.IsServer; + foreach (MyObjectBuilder_Checkpoint.ModItem mod in MySession.Static.Mods) + { + bool flag = false; + if (mod.IsModData()) + { + ListReader tags = mod.GetModData().Tags; + if (tags.Contains(MySteamConstants.TAG_SERVER_SCRIPTS) && !isServer) + { + continue; + } + flag = tags.Contains(MySteamConstants.TAG_NO_SCRIPTS); + } + MyModContext myModContext = (MyModContext)mod.GetModContext(); + try + { + LoadScripts(mod.GetPath(), myModContext); + } + catch (MyLoadingRuntimeCompilationNotSupportedException) + { + if (flag) + { + MyVRage.Platform.Scripting.ReportIncorrectBehaviour(MyCommonTexts.ModRuleViolation_RuntimeScripts); + continue; + } + throw; + } + catch (Exception ex2) + { + MyLog.Default.WriteLine(string.Format("Fatal error compiling {0}:{1} - {2}. This item is likely not a mod and should be removed from the mod list.", myModContext.ModServiceName, myModContext.ModId, myModContext.ModName)); + MyLog.Default.WriteLine(ex2); + throw; + } + } + } + foreach (Assembly value in Scripts.Values) + { + if (MyFakes.ENABLE_TYPES_FROM_MODS) + { + MyGlobalTypeMetadata.Static.RegisterAssembly(value); + } + MySandboxGame.Log.WriteLine(string.Format("Script loaded: {0}", value.FullName)); + } + MyTextSurfaceScriptFactory.LoadScripts(); + MyUseObjectFactory.RegisterAssemblyTypes(Scripts.Values.ToArray()); + MySandboxGame.Log.DecreaseIndent(); + MySandboxGame.Log.WriteLine("MyScriptManager.LoadData() - END"); + } + */ + + } +} diff --git a/SeamlessTransfer/SwitchServers.cs b/SeamlessTransfer/SwitchServers.cs index c170e9b..1b2ef42 100644 --- a/SeamlessTransfer/SwitchServers.cs +++ b/SeamlessTransfer/SwitchServers.cs @@ -22,6 +22,7 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; using VRage; +using VRage.Collections; using VRage.Game; using VRage.Game.Components; using VRage.Game.ModAPI; @@ -42,12 +43,15 @@ namespace SeamlessClientPlugin.SeamlessTransfer private string OldArmorSkin { get; set; } = string.Empty; + + + public SwitchServers(MyGameServerItem TargetServer, MyObjectBuilder_World TargetWorld) { this.TargetServer = TargetServer; this.TargetWorld = TargetWorld; - ModLoader.DownloadNewMods(TargetWorld.Checkpoint.Mods); + //ModLoader.DownloadNewMods(TargetWorld.Checkpoint.Mods); } @@ -61,7 +65,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer MySession.Static.SetCameraController(MyCameraControllerEnum.SpectatorFixed); UnloadCurrentServer(); SetNewMultiplayerClient(); - + SeamlessClient.IsSwitching = false; }, "SeamlessClient"); @@ -119,23 +123,75 @@ namespace SeamlessClientPlugin.SeamlessTransfer { - MyHud.Chat.RegisterChat(MyMultiplayer.Static); + - + + SetWorldSettings(); LoadConnectedClients(); LoadOnlinePlayers(); - SetWorldSettings(); + - ModLoader.ReadyModSwitch(); + //ModLoader.ReadyModSwitch(TargetWorld.Checkpoint, TargetWorld.Sector); MySector.InitEnvironmentSettings(TargetWorld.Sector.Environment); - MyModAPIHelper.Initialize(); + + + + //MethodInfo inf = typeof(MySession).GetMethod("LoadGameDefinition", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[1] { typeof(MyObjectBuilder_Checkpoint) }, null); + //inf.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint }); + + /* + CachingDictionary dic = (CachingDictionary)typeof(MySession).GetField("m_sessionComponents", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MySession.Static); + + foreach (var item in dic.ToList()) + { + if (item.Value.ModContext != null) + dic.Remove(item.Key, true); + } + + + foreach (KeyValuePair> item in MyScriptManager.Static.ScriptsPerMod) + { + MyStringId key = item.Value.First(); + MySession.Static.RegisterComponentsFromAssembly(MyScriptManager.Static.Scripts[key], true, item.Key); + } + + + + List dic1 = (List)typeof(MySession).GetField("m_sessionComponentForDrawAsync", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MySession.Static); + List dic2 = (List)typeof(MySession).GetField("m_sessionComponentForDraw", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MySession.Static); + + dic1.Clear(); + dic2.Clear(); + + foreach (MySessionComponentBase value in dic.Values) + { + + + if (value.ModContext == null || value.ModContext.IsBaseGame) + { + dic1.Add(value); + } + else + { + dic2.Add(value); + } + } + + */ + + string text = ((!string.IsNullOrEmpty(TargetWorld.Checkpoint.CustomSkybox)) ? TargetWorld.Checkpoint.CustomSkybox : MySector.EnvironmentDefinition.EnvironmentTexture); MyRenderProxy.PreloadTextures(new string[1] { text }, TextureType.CubeMap); + + MyModAPIHelper.Initialize(); MySession.Static.LoadDataComponents(); + + //MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents); + MyModAPIHelper.Initialize(); // MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents); @@ -143,7 +199,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer // A.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint }); - + MyMultiplayer.Static.OnSessionReady(); RemoveOldEntities(); @@ -152,8 +208,22 @@ namespace SeamlessClientPlugin.SeamlessTransfer StartEntitySync(); + MyHud.Chat.RegisterChat(MyMultiplayer.Static); + + /* + foreach (MySessionComponentBase value in dic.Values) + { + + if(value.ModContext != null) + { + SeamlessClient.TryShow($"{value.Definition?.ToString()} - {value.ModContext.ModName}"); + value.BeforeStart(); + } + + + } + */ - // Allow the game to start proccessing incoming messages in the buffer MyMultiplayer.Static.StartProcessingClientMessages(); @@ -163,6 +233,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer } + + + private void LoadOnlinePlayers() { //Get This players ID @@ -420,7 +493,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer Sync.Clients.Clear(); Sync.Players.ClearPlayers(); - + MyHud.Chat.UnregisterChat(MyMultiplayer.Static); MySession.Static.Gpss.RemovePlayerGpss(MySession.Static.LocalPlayerId); MyHud.GpsMarkers.Clear(); @@ -428,10 +501,12 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyMultiplayer.Static.ReplicationLayer.Dispose(); MyMultiplayer.Static.Dispose(); MyMultiplayer.Static = null; - + //Close any respawn screens that are open MyGuiScreenMedicals.Close(); + //MySession.Static.UnloadDataComponents(); + } private void RemoveOldEntities() diff --git a/Utilities/Patches.cs b/Utilities/Patches.cs index bde0e47..a85532a 100644 --- a/Utilities/Patches.cs +++ b/Utilities/Patches.cs @@ -3,6 +3,7 @@ using Sandbox.Engine.Analytics; using Sandbox.Engine.Multiplayer; using Sandbox.Engine.Networking; using Sandbox.Game; +using Sandbox.Game.Entities; using Sandbox.Game.Gui; using Sandbox.Game.Multiplayer; using Sandbox.Game.World; @@ -19,8 +20,10 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; using VRage; +using VRage.Collections; using VRage.FileSystem; using VRage.Game; +using VRage.Game.Entity; using VRage.GameServices; using VRage.Network; using VRage.Utils; @@ -79,6 +82,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer + private static FieldInfo MBuffer; + public static void GetPatches() { //Get reflected values and store them @@ -101,7 +106,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer RemoteAdminSettings = GetField(typeof(MySession), "m_remoteAdminSettings", BindingFlags.Instance | BindingFlags.NonPublic); MPlayerGPSCollection = GetField(typeof(MyPlayerCollection), "m_players", BindingFlags.Instance | BindingFlags.NonPublic); - + MBuffer = GetField(MyTransportLayerType, "m_buffer", BindingFlags.Instance | BindingFlags.NonPublic); /* Get Methods */ @@ -121,13 +126,21 @@ namespace SeamlessClientPlugin.SeamlessTransfer MethodInfo LoadingScreenDraw = GetMethod(typeof(MyGuiScreenLoading), "DrawInternal", BindingFlags.Instance | BindingFlags.NonPublic); - + + //Test patches + MethodInfo SetPlayerDed = GetMethod(typeof(MyPlayerCollection), "SetPlayerDeadInternal", BindingFlags.Instance | BindingFlags.NonPublic); + + + + + Patcher.Patch(LoadingScreenDraw, prefix: new HarmonyMethod(GetPatchMethod(nameof(DrawInternal)))); Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined)))); Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession)))); + Patcher.Patch(SetPlayerDed, prefix: new HarmonyMethod(GetPatchMethod(nameof(SetPlayerDeadInternal)))); @@ -426,5 +439,68 @@ namespace SeamlessClientPlugin.SeamlessTransfer } + + private static bool SetPlayerDeadInternal(MyPlayerCollection __instance, bool __result, ulong playerSteamId, int playerSerialId, bool deadState, bool resetIdentity) + { + + FieldInfo ControlledEntities = typeof(MyPlayerCollection).GetField("m_controlledEntities", BindingFlags.Instance | BindingFlags.NonPublic); + MethodInfo RemoveControlledEntity = typeof(MyPlayerCollection).GetMethod("RemoveControlledEntityInternal", BindingFlags.Instance | BindingFlags.NonPublic); + + CachingDictionary m_controlledEntities = (CachingDictionary)ControlledEntities.GetValue(__instance); + + + + + MyPlayer.PlayerId id = new MyPlayer.PlayerId(playerSteamId, playerSerialId); + MyPlayer playerById = Sync.Players.GetPlayerById(id); + if (playerById == null) + { + __result = false; + return false; + } + if (playerById.Identity == null) + { + __result = false; + return false; + } + playerById.Identity.SetDead(resetIdentity); + if (deadState) + { + + SeamlessClient.TryShow($"Player: {playerSteamId}, SerialID: {playerSerialId} deadstate: {deadState}, resetIdentity: {resetIdentity}"); + + playerById.Controller.TakeControl(null); + foreach (KeyValuePair controlledEntity in m_controlledEntities) + { + if (controlledEntity.Value == playerById.Id) + { + MyEntity entity = null; + MyEntities.TryGetEntityById(controlledEntity.Key, out entity); + if (entity != null) + { + //RemoveControlledEntityInternal(entity, false); + RemoveControlledEntity.Invoke(__instance, new object[] { entity, false }); + } + } + } + + + + m_controlledEntities.ApplyRemovals(); + if (Sync.Clients.LocalClient != null && playerById == Sync.Clients.LocalClient.FirstPlayer) + { + MyPlayer P = Sync.Clients.LocalClient.FirstPlayer; + SeamlessClient.TryShow($"FirstPlayerName: {P.DisplayName}, ID: {P.Id.SteamId}, Serial: {P.Id.SerialId}"); + SeamlessClient.TryShow(Environment.StackTrace); + MyPlayerCollection.RequestLocalRespawn(); + } + } + + __result = true; + return false; + } + + + } } From 9dec9a8986a3eb0f8e6beb58aaf02c98848cfea0 Mon Sep 17 00:00:00 2001 From: Bob Da Ross <52760019+BobDaRoss@users.noreply.github.com> Date: Mon, 14 Feb 2022 20:53:51 -0600 Subject: [PATCH 5/5] Seamless fix --- SeamlessTransfer/ModLoader.cs | 2 +- SeamlessTransfer/SwitchServers.cs | 93 ++++--------------------------- Utilities/Patches.cs | 74 ++---------------------- 3 files changed, 16 insertions(+), 153 deletions(-) diff --git a/SeamlessTransfer/ModLoader.cs b/SeamlessTransfer/ModLoader.cs index 07fb895..42e6cdf 100644 --- a/SeamlessTransfer/ModLoader.cs +++ b/SeamlessTransfer/ModLoader.cs @@ -131,7 +131,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyGuiTextures.Static.Unload(); MySession.Static.ScriptManager.Init(checkpoint.ScriptManagerData); - MyDefinitionManager.Static.LoadData(TargetServerMods); + //MyDefinitionManager.Static.LoadData(TargetServerMods); PrepareBaseSession.Invoke(null, new object[] { sector }); diff --git a/SeamlessTransfer/SwitchServers.cs b/SeamlessTransfer/SwitchServers.cs index 1b2ef42..2e5f1e8 100644 --- a/SeamlessTransfer/SwitchServers.cs +++ b/SeamlessTransfer/SwitchServers.cs @@ -100,10 +100,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName); Sync.Players.RegisterEvents(); - - - - } @@ -121,69 +117,19 @@ namespace SeamlessClientPlugin.SeamlessTransfer private void ForceClientConnection() { - - - - + //Set World Settings SetWorldSettings(); + //Load force load any connected players LoadConnectedClients(); - LoadOnlinePlayers(); + - - //ModLoader.ReadyModSwitch(TargetWorld.Checkpoint, TargetWorld.Sector); MySector.InitEnvironmentSettings(TargetWorld.Sector.Environment); - - - //MethodInfo inf = typeof(MySession).GetMethod("LoadGameDefinition", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[1] { typeof(MyObjectBuilder_Checkpoint) }, null); - //inf.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint }); - - /* - CachingDictionary dic = (CachingDictionary)typeof(MySession).GetField("m_sessionComponents", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MySession.Static); - - foreach (var item in dic.ToList()) - { - if (item.Value.ModContext != null) - dic.Remove(item.Key, true); - } - - - foreach (KeyValuePair> item in MyScriptManager.Static.ScriptsPerMod) - { - MyStringId key = item.Value.First(); - MySession.Static.RegisterComponentsFromAssembly(MyScriptManager.Static.Scripts[key], true, item.Key); - } - - - - List dic1 = (List)typeof(MySession).GetField("m_sessionComponentForDrawAsync", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MySession.Static); - List dic2 = (List)typeof(MySession).GetField("m_sessionComponentForDraw", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MySession.Static); - - dic1.Clear(); - dic2.Clear(); - - foreach (MySessionComponentBase value in dic.Values) - { - - - if (value.ModContext == null || value.ModContext.IsBaseGame) - { - dic1.Add(value); - } - else - { - dic2.Add(value); - } - } - - */ - - string text = ((!string.IsNullOrEmpty(TargetWorld.Checkpoint.CustomSkybox)) ? TargetWorld.Checkpoint.CustomSkybox : MySector.EnvironmentDefinition.EnvironmentTexture); MyRenderProxy.PreloadTextures(new string[1] { text }, TextureType.CubeMap); @@ -209,20 +155,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyHud.Chat.RegisterChat(MyMultiplayer.Static); + Patches.GPSRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static }); - /* - foreach (MySessionComponentBase value in dic.Values) - { - - if(value.ModContext != null) - { - SeamlessClient.TryShow($"{value.Definition?.ToString()} - {value.ModContext.ModName}"); - value.BeforeStart(); - } - - - } - */ // Allow the game to start proccessing incoming messages in the buffer MyMultiplayer.Static.StartProcessingClientMessages(); @@ -230,6 +164,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer //Recreate all controls... Will fix weird gui/paint/crap MyGuiScreenHudSpace.Static.RecreateControls(true); //MySession.Static.LocalHumanPlayer.BuildArmorSkin = OldArmorSkin; + + } @@ -388,8 +324,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer private void LoadConnectedClients() { - - + Patches.LoadMembersFromWorld.Invoke(MySession.Static, new object[] { TargetWorld, MyMultiplayer.Static }); @@ -397,13 +332,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer object VirtualClientsValue = Patches.VirtualClients.GetValue(MySession.Static); Patches.InitVirtualClients.Invoke(VirtualClientsValue, null); - /* - SeamlessClient.TryShow("Loading exsisting Members From World!"); - foreach (var Client in TargetWorld.Checkpoint.Clients) - { - SeamlessClient.TryShow("Adding New Client: " + Client.Name); - Sync.Clients.AddClient(Client.SteamId, Client.Name); - }*/ + + //load online players + LoadOnlinePlayers(); } @@ -442,6 +373,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer MyMultiplayer.Static.PendingReplicablesDone -= MyMultiplayer_PendingReplicablesDone; } + private void UpdateWorldGenerator() { //This will re-init the MyProceduralWorldGenerator. (Not doing this will result in asteroids not rendering in properly) @@ -461,12 +393,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer Generator.Init(GeneratorSettings); } - - //Force component to reload, re-syncing settings and seeds to the destination server Generator.LoadData(); - //We need to go in and force planets to be empty areas in the generator. This is originially done on planet init. FieldInfo PlanetInitArgs = typeof(MyPlanet).GetField("m_planetInitValues", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); foreach (var Planet in MyEntities.GetEntities().OfType()) diff --git a/Utilities/Patches.cs b/Utilities/Patches.cs index a85532a..c0bbae3 100644 --- a/Utilities/Patches.cs +++ b/Utilities/Patches.cs @@ -69,6 +69,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer public static MethodInfo LoadPlayerInternal { get; private set; } public static MethodInfo LoadMembersFromWorld { get; private set; } public static MethodInfo LoadMultiplayer { get; private set; } + public static MethodInfo GPSRegisterChat { get; private set; } public static MethodInfo SendPlayerData; @@ -118,7 +119,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer LoadMultiplayer = GetMethod(typeof(MySession), "LoadMultiplayer", BindingFlags.Static | BindingFlags.NonPublic); SendPlayerData = GetMethod(ClientType, "SendPlayerData", BindingFlags.Instance | BindingFlags.NonPublic); UnloadProceduralWorldGenerator = GetMethod(typeof(MyProceduralWorldGenerator), "UnloadData", BindingFlags.Instance | BindingFlags.NonPublic); - + GPSRegisterChat = GetMethod(typeof(MyGpsCollection), "RegisterChat", BindingFlags.Instance | BindingFlags.NonPublic); @@ -128,7 +129,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer //Test patches - MethodInfo SetPlayerDed = GetMethod(typeof(MyPlayerCollection), "SetPlayerDeadInternal", BindingFlags.Instance | BindingFlags.NonPublic); + //MethodInfo SetPlayerDed = GetMethod(typeof(MyPlayerCollection), "SetPlayerDeadInternal", BindingFlags.Instance | BindingFlags.NonPublic); @@ -140,7 +141,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer Patcher.Patch(LoadingScreenDraw, prefix: new HarmonyMethod(GetPatchMethod(nameof(DrawInternal)))); Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined)))); Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession)))); - Patcher.Patch(SetPlayerDed, prefix: new HarmonyMethod(GetPatchMethod(nameof(SetPlayerDeadInternal)))); + //Patcher.Patch(SetPlayerDed, prefix: new HarmonyMethod(GetPatchMethod(nameof(SetPlayerDeadInternal)))); @@ -434,73 +435,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer { throw Ex; } - - } - - - - private static bool SetPlayerDeadInternal(MyPlayerCollection __instance, bool __result, ulong playerSteamId, int playerSerialId, bool deadState, bool resetIdentity) - { - - FieldInfo ControlledEntities = typeof(MyPlayerCollection).GetField("m_controlledEntities", BindingFlags.Instance | BindingFlags.NonPublic); - MethodInfo RemoveControlledEntity = typeof(MyPlayerCollection).GetMethod("RemoveControlledEntityInternal", BindingFlags.Instance | BindingFlags.NonPublic); - - CachingDictionary m_controlledEntities = (CachingDictionary)ControlledEntities.GetValue(__instance); - - - - - MyPlayer.PlayerId id = new MyPlayer.PlayerId(playerSteamId, playerSerialId); - MyPlayer playerById = Sync.Players.GetPlayerById(id); - if (playerById == null) - { - __result = false; - return false; - } - if (playerById.Identity == null) - { - __result = false; - return false; - } - playerById.Identity.SetDead(resetIdentity); - if (deadState) - { - - SeamlessClient.TryShow($"Player: {playerSteamId}, SerialID: {playerSerialId} deadstate: {deadState}, resetIdentity: {resetIdentity}"); - - playerById.Controller.TakeControl(null); - foreach (KeyValuePair controlledEntity in m_controlledEntities) - { - if (controlledEntity.Value == playerById.Id) - { - MyEntity entity = null; - MyEntities.TryGetEntityById(controlledEntity.Key, out entity); - if (entity != null) - { - //RemoveControlledEntityInternal(entity, false); - RemoveControlledEntity.Invoke(__instance, new object[] { entity, false }); - } - } - } - - - - m_controlledEntities.ApplyRemovals(); - if (Sync.Clients.LocalClient != null && playerById == Sync.Clients.LocalClient.FirstPlayer) - { - MyPlayer P = Sync.Clients.LocalClient.FirstPlayer; - SeamlessClient.TryShow($"FirstPlayerName: {P.DisplayName}, ID: {P.Id.SteamId}, Serial: {P.Id.SerialId}"); - SeamlessClient.TryShow(Environment.StackTrace); - MyPlayerCollection.RequestLocalRespawn(); - } - } - - __result = true; - return false; - } - - - } }