Update for latest version of seamless
Some checks failed
Build / Compute Version (push) Successful in 5s
Build / Build Nuget package (push) Failing after 35s

Notable feature: ModAPI
This commit is contained in:
2025-05-11 16:14:22 -04:00
parent c8c0255edd
commit d84f37bea7
15 changed files with 310 additions and 113 deletions

View File

@@ -34,12 +34,12 @@ namespace SeamlessClient.Components
private bool ScannedMods = false; private bool ScannedMods = false;
public static string JoiningServerName { get; private set; } public static string JoiningServerName { get; private set; }
public static List<string> CustomLoadingTextures { get; private set; } = new List<string>(); public static List<string> CustomLoadingTextures { get; private set; } = new List<string>();
static Random random = new Random(Guid.NewGuid().GetHashCode()); static Random random = new Random(Guid.NewGuid().GetHashCode());
delegate void MyDelegate(string text); delegate void MyDelegate(string text);
private static List<MyObjectBuilder_Checkpoint.ModItem> mods; private static List<MyObjectBuilder_Checkpoint.ModItem> mods;
public override void Patch(Harmony patcher) public override void Patch(Harmony patcher)
{ {
@@ -97,7 +97,7 @@ namespace SeamlessClient.Components
//Use custom loading screen //Use custom loading screen
GUILoadingScreen myGuiScreenLoading = new GUILoadingScreen(newGameplayScreen, MyGuiScreenGamePlay.Static, customLoadingBackground, customLoadingtext); GUILoadingScreen myGuiScreenLoading = new GUILoadingScreen(newGameplayScreen, MyGuiScreenGamePlay.Static, customLoadingBackground, customLoadingtext);
myGuiScreenLoading.OnScreenLoadingFinished += delegate myGuiScreenLoading.OnScreenLoadingFinished += delegate
{ {
if (MySession.Static != null) if (MySession.Static != null)

119
Components/ModAPI.cs Normal file
View File

@@ -0,0 +1,119 @@
using HarmonyLib;
using Sandbox.Game.World;
using SeamlessClient.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using VRage.Collections;
using VRage.Game;
using VRage.Game.Components;
using VRage.Utils;
namespace SeamlessClient.Components
{
/// <summary>
/// ModAPI so that mods can register seamless events
/// </summary>
public class ModAPI : ComponentBase
{
private static FieldInfo SessionComponents;
private static List<LoadedMod> LoadedMods = new List<LoadedMod>();
public class LoadedMod
{
public MethodInfo SeamlessServerUnload;
public MethodInfo SeamlessServerLoad;
public MySessionComponentBase ModSession;
}
public override void Patch(Harmony patcher)
{
var AddModAssembly = PatchUtils.GetMethod(typeof(MySession), "TryRegisterSessionComponent");
patcher.Patch(AddModAssembly, postfix: new HarmonyMethod(Get(typeof(ModAPI), nameof(AddModAssembly))));
SessionComponents = PatchUtils.GetField(typeof(MySession), "m_sessionComponents");
base.Patch(patcher);
}
public static void ClearCache()
{
LoadedMods.Clear();
}
public static void StartModSwitching()
{
Seamless.TryShow($"Invoking SeamlessUnload API on {LoadedMods.Count} mods!");
foreach (var mod in LoadedMods)
{
try
{
mod.SeamlessServerUnload?.Invoke(mod.ModSession, null);
}
catch (Exception ex)
{
Seamless.TryShow(ex, $"Error during modAPI unloading! {mod.SeamlessServerUnload.Name}");
}
}
}
public static void ServerSwitched()
{
Seamless.TryShow($"Invoking SeamlessServerLoad API on {LoadedMods.Count} mods!");
foreach (var mod in LoadedMods)
{
try
{
mod.SeamlessServerLoad?.Invoke(mod.ModSession, null);
}
catch (Exception ex)
{
Seamless.TryShow(ex, $"Error during modAPI loading! {mod.SeamlessServerLoad.Name}");
}
}
}
public static void AddModAssembly(Type type, bool modAssembly, MyModContext context)
{
if (!modAssembly || context == null)
return;
CachingDictionary<Type, MySessionComponentBase> dict = (CachingDictionary<Type, MySessionComponentBase>)SessionComponents.GetValue(MySession.Static);
dict.TryGetValue(type, out MySessionComponentBase component);
Seamless.TryShow($"Loading Mod Assembly: {component.ComponentType.FullName}");
MethodInfo Load = AccessTools.Method(component.ComponentType, "SeamlessServerLoaded");
MethodInfo Unload = AccessTools.Method(component.ComponentType, "SeamlessServerUnloaded");
if(Load != null || Unload != null)
{
LoadedMod newMod = new LoadedMod();
newMod.SeamlessServerLoad = Load;
newMod.SeamlessServerUnload = Unload;
newMod.ModSession = component;
Seamless.TryShow($"Mod Assembly: {component.ComponentType.FullName} has SeamlessServerLoaded/SeamlessServerUnloaded methods!");
LoadedMods.Add(newMod);
return;
}
}
}
}

View File

@@ -55,8 +55,8 @@ namespace SeamlessClient.Components
item.GetCell(0).Text.Append("Nexus Lobby"); item.GetCell(0).Text.Append("Nexus Lobby");
} }
} }

View File

@@ -51,11 +51,11 @@ namespace SeamlessClient.Components
double t = Math.Round(CalculateTimeToTarget(v0, distance), 0); double t = Math.Round(CalculateTimeToTarget(v0, distance), 0);
if(t <= 0)
if (t <= 0)
return; return;
stringBuilder.AppendLine($" [T-{FormatDuration(t)}]"); stringBuilder.AppendLine($" [T-{FormatDuration(t)}]");

View File

@@ -47,7 +47,7 @@ namespace SeamlessClient.OnlinePlayersWindow
foreach (OnlineClientServer server in servers) foreach (OnlineClientServer server in servers)
{ {
if(server.ServerID == CurrentServer) if (server.ServerID == CurrentServer)
{ {
onlineServer = server; onlineServer = server;
continue; continue;

View File

@@ -91,7 +91,7 @@ namespace SeamlessClient.ServerSwitching
private void PauseResetTimer_Elapsed(object sender, ElapsedEventArgs e) private void PauseResetTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {
if(MySandboxGame.IsPaused) if (MySandboxGame.IsPaused)
{ {
Seamless.TryShow("Game is still paused... Attempting to unpause!"); Seamless.TryShow("Game is still paused... Attempting to unpause!");
MySandboxGame.PausePop(); MySandboxGame.PausePop();
@@ -164,7 +164,7 @@ namespace SeamlessClient.ServerSwitching
//SendPlayerData //SendPlayerData
@@ -179,6 +179,7 @@ namespace SeamlessClient.ServerSwitching
MySandboxGame.PausePop(); MySandboxGame.PausePop();
} }
ModAPI.ServerSwitched();
SendPlayerData.Invoke(MyMultiplayer.Static, new object[] { MyGameService.OnlineName }); SendPlayerData.Invoke(MyMultiplayer.Static, new object[] { MyGameService.OnlineName });
isSwitch = false; isSwitch = false;
} }
@@ -186,19 +187,19 @@ namespace SeamlessClient.ServerSwitching
public static bool LoadClientsFromWorld(ref List<MyObjectBuilder_Client> clients) public static bool LoadClientsFromWorld(ref List<MyObjectBuilder_Client> clients)
{ {
if(!isSwitch || clients == null || clients.Count == 0) if (!isSwitch || clients == null || clients.Count == 0)
return true; return true;
//Dictionary<ulong, MyConnectedClientData> //Dictionary<ulong, MyConnectedClientData>
IDictionary m_memberData = (IDictionary)PatchUtils.GetField(PatchUtils.ClientType, "m_memberData").GetValue(MyMultiplayer.Static); IDictionary m_memberData = (IDictionary)PatchUtils.GetField(PatchUtils.ClientType, "m_memberData").GetValue(MyMultiplayer.Static);
Seamless.TryShow($"{m_memberData.Count} members from clients"); Seamless.TryShow($"{m_memberData.Count} members from clients");
var keys = m_memberData.Keys.Cast<ulong>(); var keys = m_memberData.Keys.Cast<ulong>();
for(int i = clients.Count - 1; i >= 0; i-- ) for (int i = clients.Count - 1; i >= 0; i--)
{ {
Seamless.TryShow($"Client {clients[i].SteamId}"); Seamless.TryShow($"Client {clients[i].SteamId}");
if (keys.Contains(clients[i].SteamId)) if (keys.Contains(clients[i].SteamId))
@@ -206,8 +207,8 @@ namespace SeamlessClient.ServerSwitching
Seamless.TryShow($"Remove {clients[i].SteamId}"); Seamless.TryShow($"Remove {clients[i].SteamId}");
clients.RemoveAt(i); clients.RemoveAt(i);
} }
} }
return false; return false;
@@ -217,7 +218,7 @@ namespace SeamlessClient.ServerSwitching
private static bool ProcessAllMembersData(ref AllMembersDataMsg msg) private static bool ProcessAllMembersData(ref AllMembersDataMsg msg)
{ {
if(!isSwitch) if (!isSwitch)
return true; return true;
@@ -245,7 +246,7 @@ namespace SeamlessClient.ServerSwitching
private static bool RemovePlayerFromDict(MyPlayer.PlayerId playerId) private static bool RemovePlayerFromDict(MyPlayer.PlayerId playerId)
{ {
//Seamless.TryShow($"Removing player {playerId.SteamId} from dictionariy! \n {Environment.StackTrace.ToString()} - Sender: {MyEventContext.Current.Sender}"); //Seamless.TryShow($"Removing player {playerId.SteamId} from dictionariy! \n {Environment.StackTrace.ToString()} - Sender: {MyEventContext.Current.Sender}");
return true; return true;
@@ -272,7 +273,7 @@ namespace SeamlessClient.ServerSwitching
{ {
if (steamId != Sync.MyId) if (steamId != Sync.MyId)
return; return;
//Seamless.TryShow(Environment.StackTrace.ToString()); //Seamless.TryShow(Environment.StackTrace.ToString());
} }
@@ -307,13 +308,13 @@ namespace SeamlessClient.ServerSwitching
originalLocalCharacter = MySession.Static.LocalCharacter; originalLocalCharacter = MySession.Static.LocalCharacter;
//originalControlledEntity = MySession.Static.ControlledEntity; //originalControlledEntity = MySession.Static.ControlledEntity;
player = MySession.Static.LocalHumanPlayer.GetObjectBuilder(); player = MySession.Static.LocalHumanPlayer.GetObjectBuilder();
player.Connected = false; player.Connected = false;
AsyncInvoke.InvokeAsync(() => AsyncInvoke.InvokeAsync(() =>
{ {
Seamless.TryShow($"Needs entity Unload: {needsEntityUnload}"); Seamless.TryShow($"Needs entity Unload: {needsEntityUnload}");
@@ -326,7 +327,8 @@ namespace SeamlessClient.ServerSwitching
UnloadServer(); UnloadServer();
SetNewMultiplayerClient(); SetNewMultiplayerClient();
}catch(Exception ex) }
catch (Exception ex)
{ {
Seamless.TryShow(ex.ToString()); Seamless.TryShow(ex.ToString());
} }
@@ -390,7 +392,7 @@ namespace SeamlessClient.ServerSwitching
//client.Disconnect(); //client.Disconnect();
MyGameService.Peer2Peer.CloseSession(Sync.ServerId); MyGameService.Peer2Peer.CloseSession(Sync.ServerId);
@@ -422,7 +424,7 @@ namespace SeamlessClient.ServerSwitching
Seamless.TryShow($"2 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}"); Seamless.TryShow($"2 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}");
ModAPI.StartModSwitching();
//MyMultiplayer.Static.ReplicationLayer.Disconnect(); //MyMultiplayer.Static.ReplicationLayer.Disconnect();
//MyMultiplayer.Static.ReplicationLayer.Dispose(); //MyMultiplayer.Static.ReplicationLayer.Dispose();
@@ -464,7 +466,7 @@ namespace SeamlessClient.ServerSwitching
Seamless.TryShow($"3 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}"); Seamless.TryShow($"3 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}");
Seamless.TryShow($"3 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}"); Seamless.TryShow($"3 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}");
MySandboxGame.Static.SessionCompatHelper.FixSessionComponentObjectBuilders(TargetWorld.Checkpoint, TargetWorld.Sector); MySandboxGame.Static.SessionCompatHelper.FixSessionComponentObjectBuilders(TargetWorld.Checkpoint, TargetWorld.Sector);
@@ -473,7 +475,7 @@ namespace SeamlessClient.ServerSwitching
PatchUtils.ClientType.GetProperty("Server", BindingFlags.Public | BindingFlags.Instance).SetValue(MyMultiplayer.Static, TargetServer); PatchUtils.ClientType.GetProperty("Server", BindingFlags.Public | BindingFlags.Instance).SetValue(MyMultiplayer.Static, TargetServer);
typeof(MyMultiplayerBase).GetProperty("ServerId", BindingFlags.Public | BindingFlags.Instance).SetValue(MyMultiplayer.Static, TargetServer.SteamID); typeof(MyMultiplayerBase).GetProperty("ServerId", BindingFlags.Public | BindingFlags.Instance).SetValue(MyMultiplayer.Static, TargetServer.SteamID);
MyGameService.ConnectToServer(TargetServer, delegate (JoinResult joinResult) MyGameService.ConnectToServer(TargetServer, delegate (JoinResult joinResult)
{ {
@@ -503,7 +505,7 @@ namespace SeamlessClient.ServerSwitching
MyMultiplayer.Static = UtilExtensions.CastToReflected(instance, PatchUtils.ClientType); MyMultiplayer.Static = UtilExtensions.CastToReflected(instance, PatchUtils.ClientType);
MyMultiplayer.Static.ExperimentalMode = true; MyMultiplayer.Static.ExperimentalMode = true;
// Set the new SyncLayer to the MySession.Static.SyncLayer // Set the new SyncLayer to the MySession.Static.SyncLayer
MySessionLayer.SetValue(MySession.Static, MyMultiplayer.Static.SyncLayer); MySessionLayer.SetValue(MySession.Static, MyMultiplayer.Static.SyncLayer);
@@ -521,7 +523,7 @@ namespace SeamlessClient.ServerSwitching
private void StartSwitch() private void StartSwitch()
{ {
MyReplicationClient clienta = (MyReplicationClient)MyMultiplayer.Static.ReplicationLayer; MyReplicationClient clienta = (MyReplicationClient)MyMultiplayer.Static.ReplicationLayer;
Seamless.TryShow($"5 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}"); Seamless.TryShow($"5 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}");
Seamless.TryShow($"5 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}"); Seamless.TryShow($"5 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}");
@@ -534,14 +536,14 @@ namespace SeamlessClient.ServerSwitching
List<ulong> clients = new List<ulong>(); List<ulong> clients = new List<ulong>();
foreach(var client in Sync.Clients.GetClients()) foreach (var client in Sync.Clients.GetClients())
{ {
clients.Add(client.SteamUserId); clients.Add(client.SteamUserId);
Seamless.TryShow($"ADDING {client.SteamUserId} - {Sync.MyId}"); Seamless.TryShow($"ADDING {client.SteamUserId} - {Sync.MyId}");
} }
foreach(var client in clients) foreach (var client in clients)
{ {
if (client == TargetServer.SteamID || client == Sync.MyId) if (client == TargetServer.SteamID || client == Sync.MyId)
continue; continue;
@@ -573,7 +575,7 @@ namespace SeamlessClient.ServerSwitching
typeof(MySandboxGame).GetField("m_pauseStackCount", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, 0); typeof(MySandboxGame).GetField("m_pauseStackCount", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, 0);
MyHud.Chat.RegisterChat(MyMultiplayer.Static); MyHud.Chat.RegisterChat(MyMultiplayer.Static);
//GpsRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static }); //GpsRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static });
@@ -582,12 +584,12 @@ namespace SeamlessClient.ServerSwitching
//Recreate all controls... Will fix weird gui/paint/crap //Recreate all controls... Will fix weird gui/paint/crap
//MyGuiScreenHudSpace.Static?.RecreateControls(true); //MyGuiScreenHudSpace.Static?.RecreateControls(true);
Seamless.TryShow($"6 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}"); Seamless.TryShow($"6 NexusMajor: {Seamless.NexusVersion.Major} - ConrolledEntity {MySession.Static.ControlledEntity == null} - HumanPlayer {MySession.Static.LocalHumanPlayer == null} - Character {MySession.Static.LocalCharacter == null}");
Seamless.TryShow($"6 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}"); Seamless.TryShow($"6 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}");
originalLocalCharacter?.Close(); originalLocalCharacter?.Close();
ResetReplicationTime(true); ResetReplicationTime(true);
@@ -764,7 +766,7 @@ namespace SeamlessClient.ServerSwitching
} }
} }
private void StartEntitySync() private void StartEntitySync()
{ {
Seamless.TryShow("Requesting Player From Server"); Seamless.TryShow("Requesting Player From Server");
@@ -772,7 +774,7 @@ namespace SeamlessClient.ServerSwitching
if (!Sandbox.Engine.Platform.Game.IsDedicated && MySession.Static.LocalHumanPlayer == null) if (!Sandbox.Engine.Platform.Game.IsDedicated && MySession.Static.LocalHumanPlayer == null)
{ {
Seamless.TryShow("RequestNewPlayer"); Seamless.TryShow("RequestNewPlayer");
} }
else if (MySession.Static.ControlledEntity == null && Sync.IsServer && !Sandbox.Engine.Platform.Game.IsDedicated) else if (MySession.Static.ControlledEntity == null && Sync.IsServer && !Sandbox.Engine.Platform.Game.IsDedicated)
@@ -782,7 +784,7 @@ namespace SeamlessClient.ServerSwitching
MyPlayerCollection.RequestLocalRespawn(); MyPlayerCollection.RequestLocalRespawn();
} }
//Request client state batch //Request client state batch
(MyMultiplayer.Static as MyMultiplayerClientBase).RequestBatchConfirmation(); (MyMultiplayer.Static as MyMultiplayerClientBase).RequestBatchConfirmation();
@@ -832,7 +834,7 @@ namespace SeamlessClient.ServerSwitching
player.IsWildlifeAgent = true; player.IsWildlifeAgent = true;
CreateNewPlayerInternal.Invoke(MySession.Static.Players, new object[] { Sync.Clients.LocalClient, savingPlayerId.Value, player }); CreateNewPlayerInternal.Invoke(MySession.Static.Players, new object[] { Sync.Clients.LocalClient, savingPlayerId.Value, player });
typeof(MyPlayerCollection).GetMethod("LoadPlayerInternal", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(MySession.Static.Players, new object[] { savingPlayerId.Value, player, false }); typeof(MyPlayerCollection).GetMethod("LoadPlayerInternal", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(MySession.Static.Players, new object[] { savingPlayerId.Value, player, false });
Seamless.TryShow("Saving PlayerID: " + savingPlayerId.ToString()); Seamless.TryShow("Saving PlayerID: " + savingPlayerId.ToString());

View File

@@ -69,17 +69,17 @@ namespace SeamlessClient.Components
if (WaitingForClientCheck == false && isSeamlessSwitching) if (WaitingForClientCheck == false && isSeamlessSwitching)
WaitingForClientCheck = true; WaitingForClientCheck = true;
if(WaitingForClientCheck && MySession.Static.LocalHumanPlayer != null) if (WaitingForClientCheck && MySession.Static.LocalHumanPlayer != null)
WaitingForClientCheck = false; WaitingForClientCheck = false;
if (isSeamlessSwitching || WaitingForClientCheck) if (isSeamlessSwitching || WaitingForClientCheck)
{ {
//SeamlessClient.TryShow("Switching Servers!"); //SeamlessClient.TryShow("Switching Servers!");
MyRenderProxy.DebugDrawText2D(new VRageMath.Vector2(MySandboxGame.ScreenViewport.Width/2, MySandboxGame.ScreenViewport.Height - 150), SwitchingText, VRageMath.Color.AliceBlue, 1f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER); MyRenderProxy.DebugDrawText2D(new VRageMath.Vector2(MySandboxGame.ScreenViewport.Width / 2, MySandboxGame.ScreenViewport.Height - 150), SwitchingText, VRageMath.Color.AliceBlue, 1f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);
MyRenderProxy.DebugDrawText2D(new VRageMath.Vector2(MySandboxGame.ScreenViewport.Width / 2, MySandboxGame.ScreenViewport.Height - 200), $"Transferring to {TargetServer.Name}", VRageMath.Color.Yellow, 1.5f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER); MyRenderProxy.DebugDrawText2D(new VRageMath.Vector2(MySandboxGame.ScreenViewport.Width / 2, MySandboxGame.ScreenViewport.Height - 200), $"Transferring to {TargetServer.Name}", VRageMath.Color.Yellow, 1.5f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);
MyRenderProxy.DebugDrawLine2D(new VRageMath.Vector2((MySandboxGame.ScreenViewport.Width / 2) - 250, MySandboxGame.ScreenViewport.Height - 170), new VRageMath.Vector2((MySandboxGame.ScreenViewport.Width / 2)+250, MySandboxGame.ScreenViewport.Height - 170), VRageMath.Color.Blue, VRageMath.Color.Green); MyRenderProxy.DebugDrawLine2D(new VRageMath.Vector2((MySandboxGame.ScreenViewport.Width / 2) - 250, MySandboxGame.ScreenViewport.Height - 170), new VRageMath.Vector2((MySandboxGame.ScreenViewport.Width / 2) + 250, MySandboxGame.ScreenViewport.Height - 170), VRageMath.Color.Blue, VRageMath.Color.Green);
} }
} }
@@ -87,7 +87,7 @@ namespace SeamlessClient.Components
public override void Patch(Harmony patcher) public override void Patch(Harmony patcher)
{ {
TransportLayerConstructor = PatchUtils.GetConstructor(PatchUtils.MyTransportLayerType, new[] { typeof(int) }); TransportLayerConstructor = PatchUtils.GetConstructor(PatchUtils.MyTransportLayerType, new[] { typeof(int) });
SyncLayerConstructor = PatchUtils.GetConstructor(PatchUtils.SyncLayerType, new[] { PatchUtils.MyTransportLayerType }); SyncLayerConstructor = PatchUtils.GetConstructor(PatchUtils.SyncLayerType, new[] { PatchUtils.MyTransportLayerType });
ClientConstructor = PatchUtils.GetConstructor(PatchUtils.ClientType, new[] { typeof(MyGameServerItem), PatchUtils.SyncLayerType }); ClientConstructor = PatchUtils.GetConstructor(PatchUtils.ClientType, new[] { typeof(MyGameServerItem), PatchUtils.SyncLayerType });
MySessionLayer = PatchUtils.GetProperty(typeof(MySession), "SyncLayer"); MySessionLayer = PatchUtils.GetProperty(typeof(MySession), "SyncLayer");
@@ -100,8 +100,51 @@ namespace SeamlessClient.Components
InitVirtualClients = PatchUtils.GetMethod(PatchUtils.VirtualClientsType, "Init"); InitVirtualClients = PatchUtils.GetMethod(PatchUtils.VirtualClientsType, "Init");
VirtualClients = PatchUtils.GetField(typeof(MySession), "VirtualClients"); VirtualClients = PatchUtils.GetField(typeof(MySession), "VirtualClients");
patcher.Patch(onJoin, postfix: new HarmonyMethod(Get(typeof(ServerSwitcherComponentOLD), nameof(OnUserJoined)))); patcher.Patch(onJoin, postfix: new HarmonyMethod(Get(typeof(ServerSwitcherComponentOLD), nameof(OnUserJoined))));
base.Patch(patcher);
}
public override void Initilized()
{
MyAPIGateway.Utilities.MessageEntered += Utilities_MessageEntered;
}
private void Utilities_MessageEntered(string messageText, ref bool sendToOthers)
{
if (!messageText.StartsWith("/nexus"))
return;
string[] cmd = messageText.ToLowerInvariant().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (cmd[1] == "refreshcharacter")
{
if (MySession.Static.LocalHumanPlayer == null)
{
MyAPIGateway.Utilities?.ShowMessage("Seamless", "LocalHumanPlayer Null!");
return;
}
if (MySession.Static.LocalHumanPlayer.Character == null)
{
MyAPIGateway.Utilities?.ShowMessage("Seamless", "LocalHumanPlayerCharacter Null!");
return;
}
//None of this shit works.... 5/3/2025
MySession.Static.LocalHumanPlayer.SpawnIntoCharacter(MySession.Static.LocalHumanPlayer.Character);
MySession.Static.LocalHumanPlayer.Controller.TakeControl(MySession.Static.LocalHumanPlayer.Character);
MySession.Static.LocalHumanPlayer.Character.GetOffLadder();
MySession.Static.LocalHumanPlayer.Character.Stand();
MySession.Static.LocalHumanPlayer.Character.ResetControls();
MySession.Static.LocalHumanPlayer.Character.UpdateCharacterPhysics(true);
MyAPIGateway.Utilities?.ShowMessage("Seamless", "Character Controls Reset!");
}
} }
private static void OnUserJoined(ref JoinResultMsg msg) private static void OnUserJoined(ref JoinResultMsg msg)
@@ -111,14 +154,16 @@ namespace SeamlessClient.Components
//SeamlessClient.TryShow("User Joined! Result: " + msg.JoinResult.ToString()); //SeamlessClient.TryShow("User Joined! Result: " + msg.JoinResult.ToString());
//Invoke the switch event //Invoke the switch event
SwitchingText = "Server Responded! Removing Old Entities and forcing client connection!"; SwitchingText = "Server Responded! Removing Old Entities and forcing client connection!";
RemoveOldEntities(); RemoveOldEntities();
ForceClientConnection(); ForceClientConnection();
ModAPI.ServerSwitched();
//Fix any character issues
if (MySession.Static.LocalCharacter != null)
MySession.Static.LocalHumanPlayer.SpawnIntoCharacter(MySession.Static.LocalCharacter);
MySession.Static.LocalHumanPlayer?.Character?.Stand();
isSeamlessSwitching = false; isSeamlessSwitching = false;
} }
} }
@@ -126,12 +171,12 @@ namespace SeamlessClient.Components
public void StartBackendSwitch(MyGameServerItem _TargetServer, MyObjectBuilder_World _TargetWorld) public void StartBackendSwitch(MyGameServerItem _TargetServer, MyObjectBuilder_World _TargetWorld)
{ {
if(MySession.Static.LocalCharacter != null) if (MySession.Static.LocalCharacter != null)
{ {
var viewMatrix = MySession.Static.LocalCharacter.GetViewMatrix(); var viewMatrix = MySession.Static.LocalCharacter.GetViewMatrix();
MySpectator.Static.SetViewMatrix(viewMatrix); MySpectator.Static.SetViewMatrix(viewMatrix);
} }
SwitchingText = "Starting Seamless Switch... Please wait!"; SwitchingText = "Starting Seamless Switch... Please wait!";
isSeamlessSwitching = true; isSeamlessSwitching = true;
OldArmorSkin = MySession.Static.LocalHumanPlayer.BuildArmorSkin; OldArmorSkin = MySession.Static.LocalHumanPlayer.BuildArmorSkin;
@@ -140,10 +185,15 @@ namespace SeamlessClient.Components
MySandboxGame.Static.Invoke(delegate MySandboxGame.Static.Invoke(delegate
{ {
//Pause the game/update thread while we load
MySandboxGame.IsPaused = true;
//Set camera controller to fixed spectator //Set camera controller to fixed spectator
MySession.Static.SetCameraController(MyCameraControllerEnum.SpectatorFixed); MySession.Static.SetCameraController(MyCameraControllerEnum.SpectatorFixed);
UnloadCurrentServer(); UnloadCurrentServer();
SetNewMultiplayerClient(); SetNewMultiplayerClient();
ModAPI.StartModSwitching();
//SeamlessClient.IsSwitching = false; //SeamlessClient.IsSwitching = false;
SwitchingText = "Waiting for server response..."; SwitchingText = "Waiting for server response...";
@@ -172,7 +222,7 @@ namespace SeamlessClient.Components
SwitchingText = "New Multiplayer Session Set"; SwitchingText = "New Multiplayer Session Set";
Seamless.TryShow("Successfully set MyMultiplayer.Static"); Seamless.TryShow("Successfully set MyMultiplayer.Static");
MySandboxGame.IsPaused = true;
Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName); Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName);
Sync.Players.RegisterEvents(); Sync.Players.RegisterEvents();
@@ -184,6 +234,8 @@ namespace SeamlessClient.Components
private static void ForceClientConnection() private static void ForceClientConnection()
{ {
//Set World Settings //Set World Settings
SetWorldSettings(); SetWorldSettings();
@@ -217,6 +269,8 @@ namespace SeamlessClient.Components
StartEntitySync(); StartEntitySync();
//Resume the game/update thread
MySandboxGame.IsPaused = false;
MyHud.Chat.RegisterChat(MyMultiplayer.Static); MyHud.Chat.RegisterChat(MyMultiplayer.Static);
GpsRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static }); GpsRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static });
@@ -228,6 +282,12 @@ namespace SeamlessClient.Components
//Recreate all controls... Will fix weird gui/paint/crap //Recreate all controls... Will fix weird gui/paint/crap
MyGuiScreenHudSpace.Static.RecreateControls(true); MyGuiScreenHudSpace.Static.RecreateControls(true);
SwitchingText = "Client Registered. Waiting for entities from server..."; SwitchingText = "Client Registered. Waiting for entities from server...";
Seamless.TryShow($"LocalHumanPlayer = {MySession.Static.LocalHumanPlayer == null}");
//MySession.Static.LocalHumanPlayer.BuildArmorSkin = OldArmorSkin; //MySession.Static.LocalHumanPlayer.BuildArmorSkin = OldArmorSkin;
} }
@@ -392,6 +452,8 @@ namespace SeamlessClient.Components
private static void LoadConnectedClients() private static void LoadConnectedClients()
{ {
//TargetWorld.Checkpoint.AllPlayers.Count
Seamless.TryShow($"Loading members from world... {TargetWorld.Checkpoint.AllPlayers.Count}");
LoadMembersFromWorld.Invoke(MySession.Static, new object[] { TargetWorld, MyMultiplayer.Static }); LoadMembersFromWorld.Invoke(MySession.Static, new object[] { TargetWorld, MyMultiplayer.Static });
@@ -511,7 +573,8 @@ namespace SeamlessClient.Components
//Close any respawn screens that are open //Close any respawn screens that are open
MyGuiScreenMedicals.Close(); MyGuiScreenMedicals.Close();
//MySession.Static.UnloadDataComponents(); //Unload any lingering updates queued
MyEntities.Orchestrator.Unload();
} }
@@ -520,7 +583,11 @@ namespace SeamlessClient.Components
foreach (var ent in MyEntities.GetEntities()) foreach (var ent in MyEntities.GetEntities())
{ {
if (ent is MyPlanet) if (ent is MyPlanet)
{
//Re-Add planet updates
MyEntities.RegisterForUpdate(ent);
continue; continue;
}
ent.Close(); ent.Close();
} }
@@ -530,7 +597,7 @@ namespace SeamlessClient.Components
{ {
AccessTools.Field(typeof(MyCoordinateSystem), "m_lastCoordSysId").SetValue(MyCoordinateSystem.Static, 1L); AccessTools.Field(typeof(MyCoordinateSystem), "m_lastCoordSysId").SetValue(MyCoordinateSystem.Static, 1L);
AccessTools.Field(typeof(MyCoordinateSystem), "m_localCoordSystems").SetValue(MyCoordinateSystem.Static, new Dictionary<long, MyLocalCoordSys>()); AccessTools.Field(typeof(MyCoordinateSystem), "m_localCoordSystems").SetValue(MyCoordinateSystem.Static, new Dictionary<long, MyLocalCoordSys>());
} }

View File

@@ -113,7 +113,7 @@ namespace SeamlessClient.GUI.Screens
m_isTopMostScreen = true; m_isTopMostScreen = true;
object instance = PatchUtils.GetProperty(PatchUtils.MyLoadingPerformance, "Instance").GetValue(null); object instance = PatchUtils.GetProperty(PatchUtils.MyLoadingPerformance, "Instance").GetValue(null);
if(instance != null) if (instance != null)
PatchUtils.GetMethod(PatchUtils.MyLoadingPerformance, "StartTiming").Invoke(instance, null); PatchUtils.GetMethod(PatchUtils.MyLoadingPerformance, "StartTiming").Invoke(instance, null);
//MyLoadingPerformance.Instance.StartTiming(); //MyLoadingPerformance.Instance.StartTiming();
@@ -160,7 +160,7 @@ namespace SeamlessClient.GUI.Screens
MySession.LoadingLocalTotalSet = (Action<float>)Delegate.Combine(MySession.LoadingLocalTotalSet, new Action<float>(SetLocalTotal)); MySession.LoadingLocalTotalSet = (Action<float>)Delegate.Combine(MySession.LoadingLocalTotalSet, new Action<float>(SetLocalTotal));
@@ -200,8 +200,8 @@ namespace SeamlessClient.GUI.Screens
m_multiTextControl.OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM; m_multiTextControl.OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM;
m_multiTextControl.TextBoxAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM; m_multiTextControl.TextBoxAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM;
Controls.Add(m_wheel); Controls.Add(m_wheel);
RefreshText(); RefreshText();
} }
@@ -235,12 +235,12 @@ namespace SeamlessClient.GUI.Screens
MySandboxGame.Log.DecreaseIndent(); MySandboxGame.Log.DecreaseIndent();
MySandboxGame.Log.WriteLine("MyGuiScreenLoading.LoadContent - END"); MySandboxGame.Log.WriteLine("MyGuiScreenLoading.LoadContent - END");
} }
public static string GetRandomBackgroundTexture() public static string GetRandomBackgroundTexture()
{ {
string text = MyUtils.GetRandomInt(MyPerGameSettings.GUI.LoadingScreenIndexRange.X, MyPerGameSettings.GUI.LoadingScreenIndexRange.Y + 1).ToString().PadLeft(3, '0'); string text = MyUtils.GetRandomInt(MyPerGameSettings.GUI.LoadingScreenIndexRange.X, MyPerGameSettings.GUI.LoadingScreenIndexRange.Y + 1).ToString().PadLeft(3, '0');
return "Textures\\GUI\\Screens\\loading_background_" + text + ".dds"; return "Textures\\GUI\\Screens\\loading_background_" + text + ".dds";
@@ -531,9 +531,9 @@ namespace SeamlessClient.GUI.Screens
MyGuiManager.GetSafeHeightFullScreenPictureSize(MyGuiConstants.LOADING_BACKGROUND_TEXTURE_REAL_SIZE, out outRect); MyGuiManager.GetSafeHeightFullScreenPictureSize(MyGuiConstants.LOADING_BACKGROUND_TEXTURE_REAL_SIZE, out outRect);
bool isCustom = false; bool isCustom = false;
if(LoadingScreenComponent.CustomLoadingTextures.Count != 0) if (LoadingScreenComponent.CustomLoadingTextures.Count != 0)
{ {
if(LoadingScreenComponent.CustomLoadingTextures.Count > 1) if (LoadingScreenComponent.CustomLoadingTextures.Count > 1)
{ {
if (!backgroundTimer.Enabled) if (!backgroundTimer.Enabled)
{ {
@@ -567,9 +567,9 @@ namespace SeamlessClient.GUI.Screens
MyGuiManager.DrawString(m_font, loading, MyGuiConstants.LOADING_PLEASE_WAIT_POSITION, MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f, new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * m_transitionAlpha), MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM); MyGuiManager.DrawString(m_font, loading, MyGuiConstants.LOADING_PLEASE_WAIT_POSITION, MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f, new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * m_transitionAlpha), MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM);
MyGuiManager.DrawString(m_font, string.Format("{0}%", m_displayProgress), MyGuiConstants.LOADING_PERCENTAGE_POSITION, MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f, new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * m_transitionAlpha), MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM); MyGuiManager.DrawString(m_font, string.Format("{0}%", m_displayProgress), MyGuiConstants.LOADING_PERCENTAGE_POSITION, MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f, new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * m_transitionAlpha), MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM);
if (!isCustom && string.IsNullOrEmpty(m_customTextFromConstructor)) if (!isCustom && string.IsNullOrEmpty(m_customTextFromConstructor))
{ {
string font = m_font; string font = m_font;
@@ -590,7 +590,7 @@ namespace SeamlessClient.GUI.Screens
} }
private void BackgroundTimer_Elapsed(object sender, ElapsedEventArgs e) private void BackgroundTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {

View File

@@ -37,7 +37,7 @@ namespace SeamlessClient.Messages
this.IdentityID = playerIdentity; this.IdentityID = playerIdentity;
} }
public void SerializeWorldData(MyObjectBuilder_World WorldData) public void SerializeWorldData(MyObjectBuilder_World WorldData)
{ {

View File

@@ -385,8 +385,6 @@ namespace SeamlessClient.OnlinePlayersWindow
Controls.Add(m_playersTable); Controls.Add(m_playersTable);
string servername = PlayersWindowComponent.onlineServer?.ServerName ?? "thisServer";
foreach (MyPlayer onlinePlayer in Sync.Players.GetOnlinePlayers()) foreach (MyPlayer onlinePlayer in Sync.Players.GetOnlinePlayers())
{ {
if (onlinePlayer.Id.SerialId != 0) if (onlinePlayer.Id.SerialId != 0)
@@ -403,16 +401,14 @@ namespace SeamlessClient.OnlinePlayersWindow
} }
} }
AddPlayer(onlinePlayer.Id.SteamId, $"{MyMultiplayer.Static.HostName ?? "thisServer"}*");
AddPlayer(onlinePlayer.Id.SteamId, servername);
} }
foreach(var server in PlayersWindowComponent.allServers) foreach (var server in PlayersWindowComponent.allServers)
{ {
foreach(var player in server.Players) foreach (var player in server.Players)
AddPlayerFromOtherServer(player, server.ServerName); AddPlayerFromOtherServer(player, server.ServerName);
} }
@@ -796,7 +792,7 @@ namespace SeamlessClient.OnlinePlayersWindow
protected void Multiplayer_PlayerJoined(ulong userId, string userName) protected void Multiplayer_PlayerJoined(ulong userId, string userName)
{ {
AddPlayer(userId, PlayersWindowComponent.onlineServer.ServerName); AddPlayer(userId, PlayersWindowComponent.onlineServer?.ServerName ?? "Unknown");
} }
protected void Multiplayer_PlayerLeft(ulong userId, MyChatMemberStateChangeEnum arg2) protected void Multiplayer_PlayerLeft(ulong userId, MyChatMemberStateChangeEnum arg2)
@@ -962,7 +958,7 @@ namespace SeamlessClient.OnlinePlayersWindow
{ {
Seamless.TryShow("Requesting Refresh Pings!"); Seamless.TryShow("Requesting Refresh Pings!");
MyMultiplayer.RaiseStaticEvent((IMyEventOwner s) => MyGuiScreenPlayers.RequestPingsAndRefresh); MyMultiplayer.RaiseStaticEvent((IMyEventOwner s) => MyGuiScreenPlayers.RequestPingsAndRefresh);
} }

View File

@@ -33,5 +33,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.0.0.6")] //Set these both to the same [assembly: AssemblyVersion("3.0.0.10")] //Set these both to the same
[assembly: AssemblyFileVersion("3.0.0.6")] [assembly: AssemblyFileVersion("3.0.0.10")]

View File

@@ -13,13 +13,21 @@ With Nexus servers, all data is shared between servers. (Factions, Identities, P
## How to install ## How to install
Simply install the plguin loader, and check this plugins box to be added to the plugin loaders' active plugin list. (SE will need to be restarted afterwards) Simply install the plugin loader, and check this plugin's box to be added to the plugin loaders' active plugin list. (SE will need to be restarted afterwards)
## Known issues ## Known issues
Obviously this is not an issue free-system. Currently since im doing no mod unloading or loading there could be issues if your servers dont have the exact same mods, or the mods dont properly work right. Please do not swarm mod authors with faults if seamless doesnt play nice with it. ***Its not their fault*** its ***mine***. I will be trying to implement mod unloading and loading switching between servers, just no ETA. Obviously this is not an issue-free system. Currently, since im doing no mod unloading or loading, there could be issues if your servers don't have the same mods, or the mods don't work right. Please do not swarm mod authors with faults if seamless doesn't play nice with it. ***Its not their fault*** its ***mine***. I will be trying to implement mod unloading and loading switching between servers, just no ETA.
## ModAPI
I attempted to avoid implementing any modAPI in seamless, but unfortunately, Space Engineers doesn't handle unloading and reloading the same mod without compiling easily. Either I compile the mod every time you switch servers, eventually running into memory issues, or I attempt to unload the mod manually and restart it.
In both scenarios, unloading static variables are often up to the mod author and sometimes are set to null. On mod load, these variables are not re-instantiated with the default values resulting in many issues. It is way easier for mod authors when needed implement seamless unload and load logic appropriately.
There are two methods you can add to your mods (In the main mod session component class)
private void SeamlessServerLoaded(){}
private void SeamlessServerUnloaded(){}
Unloaded happens when seamless starts switching, Loaded when seamless is done switching. Seamless patches these methods on mod compilation.
## Fork Changes
This fork changes how components are loaded to be compatible with [CringeLauncher](https://git.zznty.ru/PvE/se-launcher).

View File

@@ -2,6 +2,7 @@
using HarmonyLib; using HarmonyLib;
using NLog.Fluent; using NLog.Fluent;
using Sandbox; using Sandbox;
using Sandbox.Engine.Multiplayer;
using Sandbox.Game.Localization; using Sandbox.Game.Localization;
using Sandbox.Game.World; using Sandbox.Game.World;
using Sandbox.ModAPI; using Sandbox.ModAPI;
@@ -39,7 +40,7 @@ namespace SeamlessClient
public static bool isSeamlessServer { get; private set; } = false; public static bool isSeamlessServer { get; private set; } = false;
public static bool isDebug = false; public static bool isDebug = false;
public static bool UseNewVersion = false; public static bool UseNewVersion = false;
public void Init(object gameInstance) public void Init(object gameInstance)
@@ -49,10 +50,15 @@ namespace SeamlessClient
GetComponents(); GetComponents();
PatchComponents(SeamlessPatcher); PatchComponents(SeamlessPatcher);
MySession.LoadingStep += SessionLoaded;
} }
private void SessionLoaded(LoadingProgress progress)
{
if (progress >= LoadingProgress.PROGRESS_STEP8)
SendSeamlessVersion();
}
private void GetComponents() private void GetComponents()
{ {
@@ -93,16 +99,19 @@ namespace SeamlessClient
} }
} }
private void InitilizeComponents() private void InitilizeComponents()
{ {
foreach(ComponentBase component in allComps) foreach (ComponentBase component in allComps)
{ {
try try
{ {
component.Initilized(); component.Initilized();
TryShow($"Initilized {component.GetType()}"); TryShow($"Initilized {component.GetType()}");
}catch(Exception ex) }
catch (Exception ex)
{ {
TryShow(ex, $"Failed to initialize {component.GetType()}"); TryShow(ex, $"Failed to initialize {component.GetType()}");
} }
@@ -126,24 +135,18 @@ namespace SeamlessClient
isSeamlessServer = true; isSeamlessServer = true;
switch (msg.MessageType) switch (msg.MessageType)
{ {
case ClientMessageType.FirstJoin:
Seamless.TryShow("Sending First Join!");
SendSeamlessVersion();
break;
case ClientMessageType.TransferServer: case ClientMessageType.TransferServer:
StartSwitch(msg.GetTransferData()); StartSwitch(msg.GetTransferData());
break; break;
case ClientMessageType.OnlinePlayers: case ClientMessageType.OnlinePlayers:
//Not implemented yet
var playerData = msg.GetOnlinePlayers(); var playerData = msg.GetOnlinePlayers();
PlayersWindowComponent.ApplyRecievedPlayers(playerData.OnlineServers, playerData.currentServerID); PlayersWindowComponent.ApplyRecievedPlayers(playerData.OnlineServers, playerData.currentServerID);
break; break;
} }
} }
public static void SendSeamlessVersion() public static void SendSeamlessVersion()
@@ -151,13 +154,15 @@ namespace SeamlessClient
ClientMessage response = new ClientMessage(SeamlessVersion.ToString()); ClientMessage response = new ClientMessage(SeamlessVersion.ToString());
MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetId, MessageUtils.Serialize(response)); MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetId, MessageUtils.Serialize(response));
Seamless.TryShow("Sending Seamless request..."); Seamless.TryShow("Sending Seamless request...");
} }
public void Dispose() public void Dispose()
{ {
} }
public void Update() public void Update()
{ {

View File

@@ -1,23 +1,23 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<PluginData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="GitHubPlugin"> <PluginData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="GitHubPlugin">
<!-- Place your github repository name here. One repository can only store one plugin. This one is from https://github.com/austinvaness/ToolSwitcherPlugin --> <!-- Place your github repository name here. One repository can only store one plugin. This one is from https://github.com/austinvaness/ToolSwitcherPlugin -->
<Id>Casimir255/SeamlessClient</Id> <Id>Casimir255/SeamlessClient</Id>
<!-- Optional tag that specifies the group this plugin belongs to. Only one plugin from a given group can be enabled. --> <!-- Optional tag that specifies the group this plugin belongs to. Only one plugin from a given group can be enabled. -->
<GroupId>NexusSeamless</GroupId> <GroupId>NexusSeamless</GroupId>
<!-- The name of your plugin that will appear in the list. --> <!-- The name of your plugin that will appear in the list. -->
<FriendlyName>SeamlessClient</FriendlyName> <FriendlyName>SeamlessClient</FriendlyName>
<!-- The author name that you want to appear in the list. --> <!-- The author name that you want to appear in the list. -->
<Author>Casimir</Author> <Author>Casimir</Author>
<!-- Optional tag that adds a tooltip to the plugin in-game. --> <!-- Optional tag that adds a tooltip to the plugin in-game. -->
<Tooltip>Allows transferring between Nexus enabled servers seamlessly</Tooltip> <Tooltip>Allows transferring between Nexus enabled servers seamlessly</Tooltip>
<!-- Optional tag that adds a plugin description. If omitted, this will be the same as the Tooltip. 1000 characters max. --> <!-- Optional tag that adds a plugin description. If omitted, this will be the same as the Tooltip. 1000 characters max. -->
<Description>This plugin allows seamless transfers between Nexus enabled servers. Some mods or plugins may not play nice with switching between servers. Be cautious when using!</Description> <Description>This plugin allows seamless transfers between Nexus enabled servers. Some mods or plugins may not play nice with switching between servers. Be cautious when using!</Description>
<!-- The commit id. You can find this in the commits list: https://github.com/austinvaness/ToolSwitcherPlugin/commits/main --> <!-- The commit id. You can find this in the commits list: https://github.com/austinvaness/ToolSwitcherPlugin/commits/main -->
<Commit>7a5ff795fba108309810a4cde7f414c1ffb1ba73</Commit> <Commit>7a5ff795fba108309810a4cde7f414c1ffb1ba73</Commit>
</PluginData> </PluginData>

View File

@@ -70,7 +70,7 @@ Type.GetType("Sandbox.Game.Screens.Helpers.MyLoadingScreenText, Sandbox.Game");
/* Static MethodInfos */ /* Static MethodInfos */
public static MethodInfo LoadPlayerInternal { get; private set; } public static MethodInfo LoadPlayerInternal { get; private set; }
@@ -84,7 +84,7 @@ Type.GetType("Sandbox.Game.Screens.Helpers.MyLoadingScreenText, Sandbox.Game");
public override void Patch(Harmony patcher) public override void Patch(Harmony patcher)
{ {
MySessionConstructor = GetConstructor(MySessionType, new[] { typeof(MySyncLayer), typeof(bool) }); MySessionConstructor = GetConstructor(MySessionType, new[] { typeof(MySyncLayer), typeof(bool) });
MyMultiplayerClientBaseConstructor = GetConstructor(MyMultiplayerClientBase, new[] { typeof(MySyncLayer) }); MyMultiplayerClientBaseConstructor = GetConstructor(MyMultiplayerClientBase, new[] { typeof(MySyncLayer) });
@@ -92,12 +92,12 @@ Type.GetType("Sandbox.Game.Screens.Helpers.MyLoadingScreenText, Sandbox.Game");
/* Get Methods */ /* Get Methods */
LoadPlayerInternal = GetMethod(typeof(MyPlayerCollection), "LoadPlayerInternal"); LoadPlayerInternal = GetMethod(typeof(MyPlayerCollection), "LoadPlayerInternal");
//MethodInfo ConnectToServer = GetMethod(typeof(MyGameService), "ConnectToServer", BindingFlags.Static | BindingFlags.Public);
base.Patch(patcher); base.Patch(patcher);
} }