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;
+ }
+
+
+
}
}