Cleaned up code after my massive bug fix
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using ProtoBuf;
|
using ProtoBuf;
|
||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using Sandbox.ModAPI;
|
using Sandbox.ModAPI;
|
||||||
|
using SeamlessClientPlugin.SeamlessTransfer;
|
||||||
using SeamlessClientPlugin.Utilities;
|
using SeamlessClientPlugin.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -31,15 +32,13 @@ namespace SeamlessClientPlugin.ClientMessages
|
|||||||
[ProtoMember(5)]
|
[ProtoMember(5)]
|
||||||
public string PluginVersion = "0";
|
public string PluginVersion = "0";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ClientMessage(ClientMessageType Type)
|
public ClientMessage(ClientMessageType Type)
|
||||||
{
|
{
|
||||||
MessageType = Type;
|
MessageType = Type;
|
||||||
|
|
||||||
if (MyAPIGateway.Multiplayer != null && !MyAPIGateway.Multiplayer.IsServer)
|
if (MyAPIGateway.Multiplayer != null && !MyAPIGateway.Multiplayer.IsServer)
|
||||||
{
|
{
|
||||||
if(MyAPIGateway.Session.LocalHumanPlayer == null)
|
if (MyAPIGateway.Session.LocalHumanPlayer == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -57,12 +56,15 @@ namespace SeamlessClientPlugin.ClientMessages
|
|||||||
MessageData = Utility.Serialize(Data);
|
MessageData = Utility.Serialize(Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T DeserializeData<T>()
|
|
||||||
|
public Transfer GetTransferData()
|
||||||
{
|
{
|
||||||
if (MessageData == null)
|
if (MessageData == null)
|
||||||
return default(T);
|
return default(Transfer);
|
||||||
|
|
||||||
|
return Utility.Deserialize<Transfer>(MessageData);
|
||||||
|
|
||||||
return Utility.Deserialize<T>(MessageData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
67
Messages/Transfer.cs
Normal file
67
Messages/Transfer.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using ProtoBuf;
|
||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
|
using Sandbox.Game.Entities;
|
||||||
|
using Sandbox.Game.Gui;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using Sandbox.Graphics.GUI;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
|
using SeamlessClientPlugin.ClientMessages;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VRage;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.GameServices;
|
||||||
|
using VRage.Network;
|
||||||
|
using VRage.Steam;
|
||||||
|
using VRage.Utils;
|
||||||
|
using VRageMath;
|
||||||
|
|
||||||
|
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||||
|
{
|
||||||
|
|
||||||
|
[ProtoContract]
|
||||||
|
public class Transfer
|
||||||
|
{
|
||||||
|
[ProtoMember(1)]
|
||||||
|
public ulong TargetServerID;
|
||||||
|
[ProtoMember(2)]
|
||||||
|
public string IPAdress;
|
||||||
|
[ProtoMember(6)]
|
||||||
|
public WorldRequest WorldRequest;
|
||||||
|
[ProtoMember(7)]
|
||||||
|
public string PlayerName;
|
||||||
|
|
||||||
|
[ProtoMember(8)]
|
||||||
|
public List<MyObjectBuilder_Gps.Entry> PlayerGPSCoords;
|
||||||
|
|
||||||
|
[ProtoMember(9)]
|
||||||
|
public MyObjectBuilder_Toolbar PlayerToolbar;
|
||||||
|
|
||||||
|
public List<Vector3> PlayerBuildSlots;
|
||||||
|
|
||||||
|
public Transfer(ulong ServerID, string IPAdress)
|
||||||
|
{
|
||||||
|
/* This is only called serverside
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.IPAdress = IPAdress;
|
||||||
|
TargetServerID = ServerID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transfer() { }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -108,56 +108,23 @@ namespace SeamlessClientPlugin
|
|||||||
|
|
||||||
public static string Version = "1.2.12";
|
public static string Version = "1.2.12";
|
||||||
public static bool Debug = false;
|
public static bool Debug = false;
|
||||||
|
private static bool Initilized = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private bool Initilized = false;
|
|
||||||
private bool SentPingResponse = false;
|
|
||||||
public const ushort SeamlessClientNetID = 2936;
|
public const ushort SeamlessClientNetID = 2936;
|
||||||
private System.Timers.Timer PingTimer = new System.Timers.Timer(3000);
|
private static System.Timers.Timer PingTimer = new System.Timers.Timer(3000);
|
||||||
|
|
||||||
public static LoadServer Server = new LoadServer();
|
|
||||||
public static bool IsSwitching = false;
|
public static bool IsSwitching = false;
|
||||||
public static bool RanJoin = false;
|
public static bool RanJoin = false;
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
|
||||||
MyAPIGateway.Multiplayer?.UnregisterMessageHandler(SeamlessClientNetID, MessageHandler);
|
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
|
||||||
Initilized = false;
|
|
||||||
SentPingResponse = false;
|
|
||||||
PingTimer.Stop();
|
|
||||||
//throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(object gameInstance)
|
public void Init(object gameInstance)
|
||||||
{
|
{
|
||||||
TryShow("Running Seamless Client Plugin v[" + Version + "]");
|
TryShow("Running Seamless Client Plugin v[" + Version + "]");
|
||||||
|
|
||||||
// Reload = new ReloadPatch();
|
|
||||||
//Patching goes here
|
|
||||||
|
|
||||||
|
|
||||||
PingTimer.Elapsed += PingTimer_Elapsed;
|
PingTimer.Elapsed += PingTimer_Elapsed;
|
||||||
PingTimer.Start();
|
PingTimer.Start();
|
||||||
//throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void PingTimer_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
//TryShow("Sending PluginVersion to Server!");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ClientMessage PingServer = new ClientMessage(ClientMessageType.FirstJoin);
|
|
||||||
MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetID, Utilities.Utility.Serialize(PingServer));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TryShow(ex.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,8 +137,8 @@ namespace SeamlessClientPlugin
|
|||||||
{
|
{
|
||||||
TryShow("Initilizing Communications!");
|
TryShow("Initilizing Communications!");
|
||||||
RunInitilizations();
|
RunInitilizations();
|
||||||
Initilized = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//OnNewPlayerRequest
|
//OnNewPlayerRequest
|
||||||
//throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
@@ -179,35 +146,15 @@ namespace SeamlessClientPlugin
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void RunInitilizations()
|
|
||||||
{
|
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
|
||||||
MyAPIGateway.Multiplayer.RegisterMessageHandler(SeamlessClientNetID, MessageHandler);
|
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
|
||||||
//We need to initiate ping request
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DisposeInitilizations()
|
|
||||||
{
|
|
||||||
MyAPIGateway.Multiplayer.UnregisterMessageHandler(SeamlessClientNetID, MessageHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void MessageHandler(byte[] bytes)
|
private void PingTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
|
// Terrible way to make sure server knows we are running seamless client
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ClientMessage Recieved = Utilities.Utility.Deserialize<ClientMessage>(bytes);
|
ClientMessage PingServer = new ClientMessage(ClientMessageType.FirstJoin);
|
||||||
if (Recieved.MessageType == ClientMessageType.TransferServer)
|
MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetID, Utilities.Utility.Serialize(PingServer));
|
||||||
{
|
|
||||||
Transfer TransferMessage = Recieved.DeserializeData<Transfer>();
|
|
||||||
IsSwitching = true;
|
|
||||||
TransferMessage.PingServerAndBeginRedirect();
|
|
||||||
RanJoin = false;
|
|
||||||
MySession.Static.SetCameraController(VRage.Game.MyCameraControllerEnum.SpectatorFixed);
|
|
||||||
|
|
||||||
//DisposeInitilizations();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -216,6 +163,47 @@ namespace SeamlessClientPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void RunInitilizations()
|
||||||
|
{
|
||||||
|
TryShow("Initilizing Communications!");
|
||||||
|
MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(SeamlessClientNetID, MessageHandler);
|
||||||
|
Initilized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DisposeInitilizations()
|
||||||
|
{
|
||||||
|
PingTimer.Stop();
|
||||||
|
MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(SeamlessClientNetID, MessageHandler);
|
||||||
|
Initilized = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void MessageHandler(ushort obj1, byte[] obj2, ulong obj3, bool obj4)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ClientMessage Recieved = Utilities.Utility.Deserialize<ClientMessage>(obj2);
|
||||||
|
if (Recieved.MessageType == ClientMessageType.TransferServer)
|
||||||
|
{
|
||||||
|
Transfer TransferMessage = Recieved.GetTransferData();
|
||||||
|
|
||||||
|
ServerPing.StartServerPing(TransferMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TryShow(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void TryShow(string message)
|
public static void TryShow(string message)
|
||||||
@@ -226,30 +214,9 @@ namespace SeamlessClientPlugin
|
|||||||
MyLog.Default?.WriteLineAndConsole($"SeamlessClient: {message}");
|
MyLog.Default?.WriteLineAndConsole($"SeamlessClient: {message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
public static void RestartClientAfterUpdate()
|
|
||||||
{
|
{
|
||||||
try
|
DisposeInitilizations();
|
||||||
{
|
|
||||||
TryShow("Restarting Client!");
|
|
||||||
string exe = Assembly.GetEntryAssembly().Location;
|
|
||||||
Process currentProcess = Process.GetCurrentProcess();
|
|
||||||
|
|
||||||
string[] CommandArgs = Environment.GetCommandLineArgs();
|
|
||||||
string NewCommandLine = "";
|
|
||||||
for(int i = 1; i < CommandArgs.Length; i++)
|
|
||||||
{
|
|
||||||
NewCommandLine += " "+ CommandArgs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
TryShow(NewCommandLine);
|
|
||||||
Process.Start(exe, NewCommandLine);
|
|
||||||
currentProcess.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TryShow("Restarting Client error!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -162,9 +162,10 @@
|
|||||||
<Compile Include="Messages\WorldRequest.cs" />
|
<Compile Include="Messages\WorldRequest.cs" />
|
||||||
<Compile Include="SeamlessClient.cs" />
|
<Compile Include="SeamlessClient.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SeamlessTransfer\LoadServer.cs" />
|
<Compile Include="SeamlessTransfer\PingServer.cs" />
|
||||||
<Compile Include="SeamlessTransfer\Transfer.cs" />
|
<Compile Include="Messages\Transfer.cs" />
|
||||||
<Compile Include="Updater\UpdateChecker.cs" />
|
<Compile Include="SeamlessTransfer\Patches.cs" />
|
||||||
|
<Compile Include="SeamlessTransfer\SwitchServers.cs" />
|
||||||
<Compile Include="Utilities\Utility.cs" />
|
<Compile Include="Utilities\Utility.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -1,723 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using Sandbox;
|
|
||||||
using Sandbox.Definitions;
|
|
||||||
using Sandbox.Engine;
|
|
||||||
using Sandbox.Engine.Analytics;
|
|
||||||
using Sandbox.Engine.Multiplayer;
|
|
||||||
using Sandbox.Engine.Networking;
|
|
||||||
using Sandbox.Engine.Physics;
|
|
||||||
using Sandbox.Engine.Utils;
|
|
||||||
using Sandbox.Engine.Voxels;
|
|
||||||
using Sandbox.Game;
|
|
||||||
using Sandbox.Game.Entities;
|
|
||||||
using Sandbox.Game.Gui;
|
|
||||||
using Sandbox.Game.GUI;
|
|
||||||
using Sandbox.Game.Multiplayer;
|
|
||||||
using Sandbox.Game.Screens.Helpers;
|
|
||||||
using Sandbox.Game.SessionComponents;
|
|
||||||
using Sandbox.Game.World;
|
|
||||||
using Sandbox.Graphics.GUI;
|
|
||||||
using Sandbox.ModAPI;
|
|
||||||
using SeamlessClientPlugin.Utilities;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Reflection.Emit;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Timers;
|
|
||||||
using VRage;
|
|
||||||
using VRage.FileSystem;
|
|
||||||
using VRage.Game;
|
|
||||||
using VRage.Game.ModAPI;
|
|
||||||
using VRage.Game.SessionComponents;
|
|
||||||
using VRage.Game.Voxels;
|
|
||||||
using VRage.GameServices;
|
|
||||||
using VRage.Network;
|
|
||||||
using VRage.Serialization;
|
|
||||||
using VRage.Utils;
|
|
||||||
using VRageMath;
|
|
||||||
using VRageRender;
|
|
||||||
using VRageRender.Messages;
|
|
||||||
|
|
||||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
|
||||||
{
|
|
||||||
public class LoadServer
|
|
||||||
{
|
|
||||||
//Protected or internal class types
|
|
||||||
private static readonly Type ClientType = Type.GetType("Sandbox.Engine.Multiplayer.MyMultiplayerClient, Sandbox.Game");
|
|
||||||
private static readonly Type SyncLayerType = Type.GetType("Sandbox.Game.Multiplayer.MySyncLayer, Sandbox.Game");
|
|
||||||
private static readonly Type MyTransportLayerType = Type.GetType("Sandbox.Engine.Multiplayer.MyTransportLayer, Sandbox.Game");
|
|
||||||
private static readonly Type MySessionType = Type.GetType("Sandbox.Game.World.MySession, Sandbox.Game");
|
|
||||||
private static readonly Type VirtualClientsType = Type.GetType("Sandbox.Engine.Multiplayer.MyVirtualClients, Sandbox.Game");
|
|
||||||
private static readonly Type GUIScreenChat = Type.GetType("Sandbox.Game.Gui.MyGuiScreenChat, Sandbox.Game");
|
|
||||||
private static readonly Type MyMultiplayerClientBase = Type.GetType("Sandbox.Engine.Multiplayer.MyMultiplayerClientBase, Sandbox.Game");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static Harmony Patcher = new Harmony("SeamlessClientReUnload");
|
|
||||||
private static MyGameServerItem Server;
|
|
||||||
private static MyObjectBuilder_World World;
|
|
||||||
|
|
||||||
public static object MyMulitplayerClient;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static ConstructorInfo ClientConstructor;
|
|
||||||
public static ConstructorInfo SyncLayerConstructor;
|
|
||||||
public static ConstructorInfo TransportLayerConstructor;
|
|
||||||
public static ConstructorInfo MySessionConstructor;
|
|
||||||
public static ConstructorInfo MyMultiplayerClientBaseConstructor;
|
|
||||||
|
|
||||||
//Reflected Methods
|
|
||||||
public static FieldInfo VirtualClients;
|
|
||||||
public static FieldInfo AdminSettings;
|
|
||||||
|
|
||||||
public static FieldInfo RemoteAdminSettings;
|
|
||||||
public static FieldInfo MPlayerGPSCollection;
|
|
||||||
public static MethodInfo RemovePlayerFromDictionary;
|
|
||||||
public static MethodInfo InitVirtualClients;
|
|
||||||
public static MethodInfo LoadPlayerInternal;
|
|
||||||
public static MethodInfo LoadMembersFromWorld;
|
|
||||||
|
|
||||||
public static FieldInfo DisconnectedClients;
|
|
||||||
public static FieldInfo MClients;
|
|
||||||
public static PropertyInfo MySessionLayer;
|
|
||||||
|
|
||||||
public static MethodInfo LoadMultiplayer;
|
|
||||||
|
|
||||||
private static ulong LocalSteamID;
|
|
||||||
|
|
||||||
|
|
||||||
public LoadServer()
|
|
||||||
{
|
|
||||||
InitiatePatches();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void InitiatePatches()
|
|
||||||
{
|
|
||||||
//Patch the on connection event
|
|
||||||
MethodInfo OnJoin = ClientType.GetMethod("OnUserJoined", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined))));
|
|
||||||
|
|
||||||
|
|
||||||
ClientConstructor = ClientType?.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2] { typeof(MyGameServerItem), SyncLayerType }, null);
|
|
||||||
SyncLayerConstructor = SyncLayerType?.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { MyTransportLayerType }, null);
|
|
||||||
TransportLayerConstructor = MyTransportLayerType?.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(int) }, null);
|
|
||||||
MySessionConstructor = MySessionType?.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2] { typeof(MySyncLayer), typeof(bool) }, null);
|
|
||||||
MyMultiplayerClientBaseConstructor = MyMultiplayerClientBase?.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(MySyncLayer) }, null);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MethodInfo ClientJoined = ClientType.GetMethod("OnClientConnected", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
MethodInfo ClientLeft = SyncLayerType?.GetMethod("OnClientLeft", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
Timer ClientChecker = new Timer(5000);
|
|
||||||
ClientChecker.Elapsed += ClientChecker_Elapsed;
|
|
||||||
ClientChecker.Start();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Patcher.Patch(ClientJoined, prefix: new HarmonyMethod(GetPatchMethod(nameof(OnClientJoined))));
|
|
||||||
Patcher.Patch(ClientLeft, prefix: new HarmonyMethod(GetPatchMethod(nameof(OnClientLeft))));
|
|
||||||
|
|
||||||
|
|
||||||
if (ClientConstructor == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Couldn't find ClientConstructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SyncLayerConstructor == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Couldn't find SyncLayerConstructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TransportLayerConstructor == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Couldn't find TransportLayerConstructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MySessionConstructor == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Couldn't find MySessionConstructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
RemovePlayerFromDictionary = typeof(MyPlayerCollection).GetMethod("RemovePlayerFromDictionary", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
|
|
||||||
DisconnectedClients = typeof(MyClientCollection).GetField("m_disconnectedClients", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
MClients = typeof(MyClientCollection).GetField("m_clients", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
|
|
||||||
MySessionLayer = typeof(MySession).GetProperty("SyncLayer", BindingFlags.Instance | BindingFlags.Public);
|
|
||||||
|
|
||||||
|
|
||||||
VirtualClients = typeof(MySession).GetField("VirtualClients", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
|
||||||
InitVirtualClients = VirtualClientsType.GetMethod("Init", BindingFlags.Instance | BindingFlags.Public);
|
|
||||||
LoadPlayerInternal = typeof(MyPlayerCollection).GetMethod("LoadPlayerInternal", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
LoadMembersFromWorld = typeof(MySession).GetMethod("LoadMembersFromWorld", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
AdminSettings = typeof(MySession).GetField("m_adminSettings", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
RemoteAdminSettings = typeof(MySession).GetField("m_remoteAdminSettings", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
MPlayerGPSCollection = typeof(MyPlayerCollection).GetField("m_players", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
LoadMultiplayer = typeof(MySession).GetMethod("LoadMultiplayer", BindingFlags.Static | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MethodInfo LoadingAction = typeof(MySessionLoader).GetMethod("LoadMultiplayerSession", BindingFlags.Public | BindingFlags.Static);
|
|
||||||
Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession))));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static MethodInfo GetPatchMethod(string v)
|
|
||||||
{
|
|
||||||
return typeof(LoadServer).GetMethod(v, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static bool GetCustomLoadingScreenPath(List<MyObjectBuilder_Checkpoint.ModItem> Mods, out string File)
|
|
||||||
{
|
|
||||||
File = null;
|
|
||||||
string WorkshopDir = MyFileSystem.ModsPath;
|
|
||||||
SeamlessClient.TryShow(WorkshopDir);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Installed Mods: " + Mods);
|
|
||||||
foreach (var Mod in Mods)
|
|
||||||
{
|
|
||||||
string SearchDir = Mod.GetPath();
|
|
||||||
|
|
||||||
if (!Directory.Exists(SearchDir))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var files = Directory.GetFiles(SearchDir, "*.dds", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
if (Path.GetFileNameWithoutExtension(file) == "CustomLoadingBackground")
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow(Mod.FriendlyName + " contains a custom loading background!");
|
|
||||||
File = file;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow(ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("No installed custom loading screen!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static bool LoadMultiplayerSession(MyObjectBuilder_World world, MyMultiplayerBase multiplayerSession)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
MyLog.Default.WriteLine("LoadSession() - Start");
|
|
||||||
if (!MyWorkshop.CheckLocalModsAllowed(world.Checkpoint.Mods, allowLocalMods: false))
|
|
||||||
{
|
|
||||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MyCommonTexts.DialogTextLocalModsDisabledInMultiplayer)));
|
|
||||||
MyLog.Default.WriteLine("LoadSession() - End");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MyWorkshop.DownloadModsAsync(world.Checkpoint.Mods, delegate (bool success)
|
|
||||||
{
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
MyScreenManager.CloseAllScreensNowExcept(null);
|
|
||||||
MyGuiSandbox.Update(16);
|
|
||||||
if (MySession.Static != null)
|
|
||||||
{
|
|
||||||
MySession.Static.Unload();
|
|
||||||
MySession.Static = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string CustomBackgroundImage = null;
|
|
||||||
GetCustomLoadingScreenPath(world.Checkpoint.Mods, out CustomBackgroundImage);
|
|
||||||
|
|
||||||
MySessionLoader.StartLoading(delegate
|
|
||||||
{
|
|
||||||
|
|
||||||
LoadMultiplayer.Invoke(null, new object[] { world, multiplayerSession });
|
|
||||||
//MySession.LoadMultiplayer(world, multiplayerSession);
|
|
||||||
}, null, CustomBackgroundImage, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
multiplayerSession.Dispose();
|
|
||||||
MySessionLoader.UnloadAndExitToMenu();
|
|
||||||
if (MyGameService.IsOnline)
|
|
||||||
{
|
|
||||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MyCommonTexts.DialogTextDownloadModsFailed)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: new StringBuilder(string.Format(MyTexts.GetString(MyCommonTexts.DialogTextDownloadModsFailedSteamOffline), MySession.GameServiceName))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MyLog.Default.WriteLine("LoadSession() - End");
|
|
||||||
}, delegate
|
|
||||||
{
|
|
||||||
multiplayerSession.Dispose();
|
|
||||||
MySessionLoader.UnloadAndExitToMenu();
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static void OnUserJoined(ref JoinResultMsg msg)
|
|
||||||
{
|
|
||||||
if (SeamlessClient.IsSwitching && msg.JoinResult == JoinResult.OK)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("User Joined! Result: " + msg.JoinResult.ToString());
|
|
||||||
|
|
||||||
|
|
||||||
if(MySessionLayer == null)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Null SessionLayer FieldInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (MySession.Static == null)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Null MySession.Static");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MyMultiplayer.Static.SyncLayer == null)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Null MyMultiplayer.Static.SyncLayer");
|
|
||||||
}
|
|
||||||
|
|
||||||
MySessionLayer.SetValue(MySession.Static , MyMultiplayer.Static.SyncLayer);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ForceClientConnection();
|
|
||||||
MyMultiplayer.Static.StartProcessingClientMessages();
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (SeamlessClient.IsSwitching && msg.JoinResult != JoinResult.OK)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Failed to join server! Reason: " + msg.JoinResult.ToString());
|
|
||||||
MySession.Static?.Unload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void OnClientJoined(MyPacket packet)
|
|
||||||
{
|
|
||||||
ConnectedClientDataMsg msg = MySerializer.CreateAndRead<ConnectedClientDataMsg>(packet.BitStream);
|
|
||||||
SeamlessClient.TryShow($"Client: {msg.ClientId} Name: {msg.Name} PacketSender: {packet.Sender.Id.Value}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnClientLeft(ulong steamUserId, MyChatMemberStateChangeEnum leaveReason)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow($"Client {steamUserId} left!");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void ClientChecker_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var Clients = Sync.Clients.GetClients();
|
|
||||||
SeamlessClient.TryShow("---------------------");
|
|
||||||
foreach (var client in Clients)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow($"{client.DisplayName}:{client.SteamUserId}");
|
|
||||||
}
|
|
||||||
SeamlessClient.TryShow("---------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void LoadWorldData(MyGameServerItem TargetServer, MyObjectBuilder_World TargetWorld)
|
|
||||||
{
|
|
||||||
Server = TargetServer;
|
|
||||||
World = TargetWorld;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void ResetMPClient()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
//m_memberData
|
|
||||||
|
|
||||||
|
|
||||||
MySandboxGame.Static.SessionCompatHelper.FixSessionComponentObjectBuilders(World.Checkpoint, World.Sector);
|
|
||||||
var LayerInstance = TransportLayerConstructor.Invoke(new object[] { 2 });
|
|
||||||
var SyncInstance = SyncLayerConstructor.Invoke(new object[] { LayerInstance });
|
|
||||||
var instance = ClientConstructor.Invoke(new object[] { Server, SyncInstance });
|
|
||||||
MyMulitplayerClient = instance;
|
|
||||||
|
|
||||||
MyMultiplayer.Static = Utility.CastToReflected(instance, ClientType);
|
|
||||||
MyMultiplayer.Static.ExperimentalMode = true;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("Successfully set MyMultiplayer.Static");
|
|
||||||
//var m = ClientType.GetMethod("SendPlayerData", BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
//m.Invoke(MyMultiplayer.Static, new object[] { MyGameService.UserName });
|
|
||||||
Server.GetGameTagByPrefix("gamemode");
|
|
||||||
//typeof(MySession).GetMethod("LoadMembersFromWorld", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(MySession.Static, new object[] { LoadServer.TargetWorld, MyMultiplayer.Static });
|
|
||||||
|
|
||||||
//MyMultiplayer.Static.ClientJoined += Static_ClientJoined;
|
|
||||||
|
|
||||||
//MyScreenManager.CloseScreen(GUIScreenChat);
|
|
||||||
MyHud.Chat.RegisterChat(MyMultiplayer.Static);
|
|
||||||
//MySession.SetSpectatorPositionFromServer(SeamlessClient.PreviousPosition ?? Vector3D.Zero);
|
|
||||||
MySession.Static.SetCameraController(MyCameraControllerEnum.SpectatorFixed);
|
|
||||||
|
|
||||||
|
|
||||||
Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName);
|
|
||||||
Sync.Players.RegisterEvents();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Error! " + ex.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void LoadMP(MyObjectBuilder_World world, MyMultiplayerBase multiplayerSession)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Starting LoadMP!");
|
|
||||||
|
|
||||||
|
|
||||||
//var MySessionConstructor = MySessionType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2] { typeof(MySyncLayer), typeof(bool) }, null);
|
|
||||||
//MySession.Static = (MySession)MySessionConstructor.Invoke(new object[] { MyMultiplayer.Static.SyncLayer, true });
|
|
||||||
MySession.Static.Mods = World.Checkpoint.Mods;
|
|
||||||
MySession.Static.Settings = World.Checkpoint.Settings;
|
|
||||||
MySession.Static.CurrentPath = MyLocalCache.GetSessionSavesPath(MyUtils.StripInvalidChars(world.Checkpoint.SessionName), contentFolder: false, createIfNotExists: false);
|
|
||||||
MySession.Static.WorldBoundaries = world.Checkpoint.WorldBoundaries;
|
|
||||||
MySession.Static.InGameTime = MyObjectBuilder_Checkpoint.DEFAULT_DATE;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MySession.Static.Players.LoadConnectedPlayers(world.Checkpoint);
|
|
||||||
|
|
||||||
//typeof(MySession).GetMethod("PrepareBaseSession", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(MyObjectBuilder_Checkpoint), typeof(MyObjectBuilder_Sector) }, null).Invoke(MySession.Static, new object[] { world.Checkpoint, world.Sector });
|
|
||||||
|
|
||||||
if (MyFakes.MP_SYNC_CLUSTERTREE)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Deserializing Clusters!");
|
|
||||||
//MyPhysics.DeserializeClusters(world.Clusters);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//_ = world.Checkpoint.ControlledObject;
|
|
||||||
//world.Checkpoint.ControlledObject = -1L;
|
|
||||||
LoadOnlinePlayers(world.Checkpoint);
|
|
||||||
LoadWorld(world.Checkpoint, world.Sector);
|
|
||||||
SeamlessClient.TryShow("Loading World Complete!");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static void LoadWorld(MyObjectBuilder_Checkpoint checkpoint, MyObjectBuilder_Sector sector)
|
|
||||||
{
|
|
||||||
|
|
||||||
Dictionary<ulong, AdminSettingsEnum> AdminSettingsList = (Dictionary<ulong, AdminSettingsEnum>)RemoteAdminSettings.GetValue(MySession.Static);
|
|
||||||
AdminSettingsList.Clear();
|
|
||||||
|
|
||||||
MySession.Static.PromotedUsers.Clear();
|
|
||||||
MySession.Static.CreativeTools.Clear();
|
|
||||||
|
|
||||||
MyEntities.MemoryLimitAddFailureReset();
|
|
||||||
MySession.Static.ElapsedGameTime = new TimeSpan(checkpoint.ElapsedGameTime);
|
|
||||||
MySession.Static.InGameTime = checkpoint.InGameTime;
|
|
||||||
MySession.Static.Name = MyStatControlText.SubstituteTexts(checkpoint.SessionName);
|
|
||||||
MySession.Static.Description = checkpoint.Description;
|
|
||||||
|
|
||||||
|
|
||||||
if (checkpoint.PromotedUsers != null)
|
|
||||||
{
|
|
||||||
MySession.Static.PromotedUsers = checkpoint.PromotedUsers.Dictionary;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MySession.Static.PromotedUsers = new Dictionary<ulong, MyPromoteLevel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach (KeyValuePair<MyObjectBuilder_Checkpoint.PlayerId, MyObjectBuilder_Player> item in checkpoint.AllPlayersData.Dictionary)
|
|
||||||
{
|
|
||||||
ulong clientId = item.Key.GetClientId();
|
|
||||||
AdminSettingsEnum adminSettingsEnum = (AdminSettingsEnum)item.Value.RemoteAdminSettings;
|
|
||||||
if (checkpoint.RemoteAdminSettings != null && checkpoint.RemoteAdminSettings.Dictionary.TryGetValue(clientId, out var value))
|
|
||||||
{
|
|
||||||
adminSettingsEnum = (AdminSettingsEnum)value;
|
|
||||||
}
|
|
||||||
if (!MyPlatformGameSettings.IsIgnorePcuAllowed)
|
|
||||||
{
|
|
||||||
adminSettingsEnum &= ~AdminSettingsEnum.IgnorePcu;
|
|
||||||
adminSettingsEnum &= ~AdminSettingsEnum.KeepOriginalOwnershipOnPaste;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AdminSettingsList[clientId] = adminSettingsEnum;
|
|
||||||
if (!Sync.IsDedicated && clientId == Sync.MyId)
|
|
||||||
{
|
|
||||||
AdminSettings.SetValue(MySession.Static, adminSettingsEnum);
|
|
||||||
|
|
||||||
//m_adminSettings = adminSettingsEnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!MySession.Static.PromotedUsers.TryGetValue(clientId, out var value2))
|
|
||||||
{
|
|
||||||
value2 = MyPromoteLevel.None;
|
|
||||||
}
|
|
||||||
if (item.Value.PromoteLevel > value2)
|
|
||||||
{
|
|
||||||
MySession.Static.PromotedUsers[clientId] = item.Value.PromoteLevel;
|
|
||||||
}
|
|
||||||
if (!MySession.Static.CreativeTools.Contains(clientId) && item.Value.CreativeToolsEnabled)
|
|
||||||
{
|
|
||||||
MySession.Static.CreativeTools.Add(clientId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//MySession.Static.WorkshopId = checkpoint.WorkshopId;
|
|
||||||
MySession.Static.Password = checkpoint.Password;
|
|
||||||
MySession.Static.PreviousEnvironmentHostility = checkpoint.PreviousEnvironmentHostility;
|
|
||||||
MySession.Static.RequiresDX = checkpoint.RequiresDX;
|
|
||||||
MySession.Static.CustomLoadingScreenImage = checkpoint.CustomLoadingScreenImage;
|
|
||||||
MySession.Static.CustomLoadingScreenText = checkpoint.CustomLoadingScreenText;
|
|
||||||
MySession.Static.CustomSkybox = checkpoint.CustomSkybox;
|
|
||||||
//FixIncorrectSettings(Settings);
|
|
||||||
// MySession.Static.AppVersionFromSave = checkpoint.AppVersion;
|
|
||||||
//MyToolbarComponent.InitCharacterToolbar(checkpoint.CharacterToolbar);
|
|
||||||
//LoadCameraControllerSettings(checkpoint);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("LocalPlayerID: " + MySession.Static.LocalPlayerId);
|
|
||||||
//checkpoint.Gps.Dictionary.TryGetValue(MySession.Static.LocalPlayerId, out MyObjectBuilder_Gps GPSCollection);
|
|
||||||
//SeamlessClient.TryShow("You have " + GPSCollection.Entries.Count + " gps points!");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MySession.Static.Gpss = new MyGpsCollection();
|
|
||||||
MySession.Static.Gpss.LoadGpss(checkpoint);
|
|
||||||
MyRenderProxy.RebuildCullingStructure();
|
|
||||||
//MySession.Static.Toolbars.LoadToolbars(checkpoint);
|
|
||||||
|
|
||||||
Sync.Players.RespawnComponent.InitFromCheckpoint(checkpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void ForceClientConnection()
|
|
||||||
{
|
|
||||||
SeamlessClient.IsSwitching = false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (MyMultiplayer.Static == null)
|
|
||||||
SeamlessClient.TryShow("MyMultiplayer.Static is null");
|
|
||||||
|
|
||||||
if (World == null)
|
|
||||||
SeamlessClient.TryShow("TargetWorld is null");
|
|
||||||
|
|
||||||
LoadClients();
|
|
||||||
|
|
||||||
LoadMP(World, MyMultiplayer.Static);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow(ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("Requesting Player From Server");
|
|
||||||
Sync.Players.RequestNewPlayer(Sync.MyId, 0, MyGameService.UserName, null, realPlayer: true, initialPlayer: true);
|
|
||||||
if (MySession.Static.ControlledEntity == null && Sync.IsServer && !Sandbox.Engine.Platform.Game.IsDedicated)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("C");
|
|
||||||
MyLog.Default.WriteLine("ControlledObject was null, respawning character");
|
|
||||||
//m_cameraAwaitingEntity = true;
|
|
||||||
MyPlayerCollection.RequestLocalRespawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
//typeof(MyGuiScreenTerminal).GetMethod("CreateTabs")
|
|
||||||
MyMultiplayer.Static.OnSessionReady();
|
|
||||||
MySession.Static.LoadDataComponents();
|
|
||||||
//MyGuiSandbox.LoadData(false);
|
|
||||||
//MyGuiSandbox.AddScreen(MyGuiSandbox.CreateScreen(MyPerGameSettings.GUI.HUDScreen));
|
|
||||||
MyRenderProxy.RebuildCullingStructure();
|
|
||||||
MyRenderProxy.CollectGarbage();
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("OnlinePlayers: " + MySession.Static.Players.GetOnlinePlayers().Count);
|
|
||||||
SeamlessClient.TryShow("Loading Complete!");
|
|
||||||
|
|
||||||
MyMultiplayer.Static.OnSessionReady();
|
|
||||||
//Recreate all controls... Will fix weird gui/paint/crap
|
|
||||||
MyGuiScreenHudSpace.Static.RecreateControls(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception Ex)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow(Ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static void LoadClients()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
//Reset Disconnected Clients
|
|
||||||
foreach (var Client in Sync.Clients.GetClients().ToList())
|
|
||||||
{
|
|
||||||
if (Client.SteamUserId == Sync.MyId)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sync.Clients.RemoveClient(Client.SteamUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Remove all old players
|
|
||||||
//Sync.Clients.Clear();
|
|
||||||
|
|
||||||
//Add server client
|
|
||||||
Sync.Clients.AddClient(Sync.ServerId, "Good.bot");
|
|
||||||
//Sync.Clients.AddClient(Sync.MyId, Sync.MyName);
|
|
||||||
|
|
||||||
object VirtualClientsValue = VirtualClients.GetValue(MySession.Static);
|
|
||||||
|
|
||||||
//Re-Initilize Virtual clients
|
|
||||||
SeamlessClient.TryShow("Initilizing Virtual Clients!");
|
|
||||||
InitVirtualClients.Invoke(VirtualClientsValue, null);
|
|
||||||
|
|
||||||
|
|
||||||
//Load Members from world
|
|
||||||
SeamlessClient.TryShow("Loading Members From World!");
|
|
||||||
//LoadMembersFromWorld.Invoke(MySession.Static, new object[] { World, MyMulitplayerClient });
|
|
||||||
foreach (var Client in World.Checkpoint.Clients)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("Adding New Client: " + Client.Name);
|
|
||||||
Sync.Clients.AddClient(Client.SteamId, Client.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow(ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void LoadOnlinePlayers(MyObjectBuilder_Checkpoint checkpoint)
|
|
||||||
{
|
|
||||||
//Get This players ID
|
|
||||||
MyPlayer.PlayerId? savingPlayerId = new MyPlayer.PlayerId(Sync.MyId);
|
|
||||||
if (!savingPlayerId.HasValue)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("SavingPlayerID is null! Creating Default!");
|
|
||||||
savingPlayerId = new MyPlayer.PlayerId(Sync.MyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("Saving PlayerID: " + savingPlayerId.ToString());
|
|
||||||
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("Checkpoint.AllPlayers: " + checkpoint.AllPlayers.Count);
|
|
||||||
//These both are null/empty. Server doesnt need to send them to the client
|
|
||||||
//SeamlessClient.TryShow("Checkpoint.ConnectedPlayers: " + checkpoint.ConnectedPlayers.Dictionary.Count);
|
|
||||||
//SeamlessClient.TryShow("Checkpoint.DisconnectedPlayers: " + checkpoint.DisconnectedPlayers.Dictionary.Count);
|
|
||||||
SeamlessClient.TryShow("Checkpoint.AllPlayersData: " + checkpoint.AllPlayersData.Dictionary.Count);
|
|
||||||
|
|
||||||
|
|
||||||
foreach (KeyValuePair<MyObjectBuilder_Checkpoint.PlayerId, MyObjectBuilder_Player> item3 in checkpoint.AllPlayersData.Dictionary)
|
|
||||||
{
|
|
||||||
MyPlayer.PlayerId playerId5 = new MyPlayer.PlayerId(item3.Key.GetClientId(), item3.Key.SerialId);
|
|
||||||
|
|
||||||
SeamlessClient.TryShow($"ConnectedPlayer: {playerId5.ToString()}");
|
|
||||||
if (savingPlayerId.HasValue && playerId5.SteamId == savingPlayerId.Value.SteamId)
|
|
||||||
{
|
|
||||||
playerId5 = new MyPlayer.PlayerId(Sync.MyId, playerId5.SerialId);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadPlayerInternal.Invoke(MySession.Static.Players, new object[] { playerId5, item3.Value, false });
|
|
||||||
ConcurrentDictionary<MyPlayer.PlayerId, MyPlayer> Players = (ConcurrentDictionary<MyPlayer.PlayerId, MyPlayer>)MPlayerGPSCollection.GetValue(MySession.Static.Players);
|
|
||||||
//LoadPlayerInternal(ref playerId5, item3.Value);
|
|
||||||
if (Players.TryGetValue(playerId5, out MyPlayer myPlayer))
|
|
||||||
{
|
|
||||||
List<Vector3> value2 = null;
|
|
||||||
if (checkpoint.AllPlayersColors != null && checkpoint.AllPlayersColors.Dictionary.TryGetValue(item3.Key, out value2))
|
|
||||||
{
|
|
||||||
myPlayer.SetBuildColorSlots(value2);
|
|
||||||
}
|
|
||||||
else if (checkpoint.CharacterToolbar != null && checkpoint.CharacterToolbar.ColorMaskHSVList != null && checkpoint.CharacterToolbar.ColorMaskHSVList.Count > 0)
|
|
||||||
{
|
|
||||||
myPlayer.SetBuildColorSlots(checkpoint.CharacterToolbar.ColorMaskHSVList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void UpdatePlayerData()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
293
SeamlessTransfer/Patches.cs
Normal file
293
SeamlessTransfer/Patches.cs
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using Sandbox.Graphics.GUI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VRage;
|
||||||
|
using VRage.FileSystem;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.GameServices;
|
||||||
|
using VRage.Network;
|
||||||
|
using VRage.Utils;
|
||||||
|
|
||||||
|
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||||
|
{
|
||||||
|
public static class Patches
|
||||||
|
{
|
||||||
|
/* All internal classes Types */
|
||||||
|
public static readonly Type ClientType = Type.GetType("Sandbox.Engine.Multiplayer.MyMultiplayerClient, Sandbox.Game");
|
||||||
|
public static readonly Type SyncLayerType = Type.GetType("Sandbox.Game.Multiplayer.MySyncLayer, Sandbox.Game");
|
||||||
|
public static readonly Type MyTransportLayerType = Type.GetType("Sandbox.Engine.Multiplayer.MyTransportLayer, Sandbox.Game");
|
||||||
|
public static readonly Type MySessionType = Type.GetType("Sandbox.Game.World.MySession, Sandbox.Game");
|
||||||
|
public static readonly Type VirtualClientsType = Type.GetType("Sandbox.Engine.Multiplayer.MyVirtualClients, Sandbox.Game");
|
||||||
|
public static readonly Type GUIScreenChat = Type.GetType("Sandbox.Game.Gui.MyGuiScreenChat, Sandbox.Game");
|
||||||
|
public static readonly Type MyMultiplayerClientBase = Type.GetType("Sandbox.Engine.Multiplayer.MyMultiplayerClientBase, Sandbox.Game");
|
||||||
|
|
||||||
|
/* Harmony Patcher */
|
||||||
|
private static Harmony Patcher = new Harmony("SeamlessClientPatcher");
|
||||||
|
|
||||||
|
|
||||||
|
/* Static Contructors */
|
||||||
|
public static ConstructorInfo ClientConstructor { get; private set; }
|
||||||
|
public static ConstructorInfo SyncLayerConstructor { get; private set; }
|
||||||
|
public static ConstructorInfo TransportLayerConstructor { get; private set; }
|
||||||
|
public static ConstructorInfo MySessionConstructor { get; private set; }
|
||||||
|
public static ConstructorInfo MyMultiplayerClientBaseConstructor { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Static FieldInfos */
|
||||||
|
public static FieldInfo MySessionLayer { get; private set; }
|
||||||
|
public static FieldInfo VirtualClients { get; private set; }
|
||||||
|
public static FieldInfo AdminSettings { get; private set; }
|
||||||
|
public static FieldInfo RemoteAdminSettings { get; private set; }
|
||||||
|
public static FieldInfo MPlayerGPSCollection { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Static MethodInfos */
|
||||||
|
public static MethodInfo InitVirtualClients { get; private set; }
|
||||||
|
public static MethodInfo LoadPlayerInternal { get; private set; }
|
||||||
|
public static MethodInfo LoadMembersFromWorld { get; private set; }
|
||||||
|
public static MethodInfo LoadMultiplayer { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
public static event EventHandler<JoinResultMsg> OnJoinEvent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void GetPatches()
|
||||||
|
{
|
||||||
|
//Get reflected values and store them
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Get Constructors */
|
||||||
|
ClientConstructor = GetConstructor(ClientType, BindingFlags.Instance | BindingFlags.NonPublic, new Type[2] { typeof(MyGameServerItem), SyncLayerType });
|
||||||
|
SyncLayerConstructor = GetConstructor(SyncLayerType, BindingFlags.Instance | BindingFlags.NonPublic, new Type[1] { MyTransportLayerType });
|
||||||
|
TransportLayerConstructor = GetConstructor(MyTransportLayerType, BindingFlags.Instance | BindingFlags.Public, new Type[1] { typeof(int) });
|
||||||
|
MySessionConstructor = GetConstructor(MySessionType, BindingFlags.Instance | BindingFlags.NonPublic, new Type[2] { typeof(MySyncLayer), typeof(bool) });
|
||||||
|
MyMultiplayerClientBaseConstructor = GetConstructor(MyMultiplayerClientBase, BindingFlags.Instance | BindingFlags.NonPublic, new Type[] { typeof(MySyncLayer) });
|
||||||
|
|
||||||
|
|
||||||
|
/* Get Fields */
|
||||||
|
MySessionLayer = GetField(typeof(MySession), "SyncLayer", BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
VirtualClients = GetField(typeof(MySession), "VirtualClients", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
AdminSettings = GetField(typeof(MySession), "m_adminSettings", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
RemoteAdminSettings = GetField(typeof(MySession), "m_remoteAdminSettings", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
MPlayerGPSCollection = GetField(typeof(MyPlayerCollection), "m_players", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Get Methods */
|
||||||
|
MethodInfo OnJoin = GetMethod(ClientType, "OnUserJoined", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
MethodInfo LoadingAction = GetMethod(typeof(MySessionLoader),"LoadMultiplayerSession", BindingFlags.Public | BindingFlags.Static);
|
||||||
|
InitVirtualClients = GetMethod(VirtualClientsType, "Init", BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
LoadPlayerInternal = GetMethod(typeof(MyPlayerCollection), "LoadPlayerInternal", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
LoadMembersFromWorld = GetMethod(typeof(MySession), "LoadMembersFromWorld", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
LoadMultiplayer = GetMethod(typeof(MySession), "LoadMultiplayer", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined))));
|
||||||
|
Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodInfo GetPatchMethod(string v)
|
||||||
|
{
|
||||||
|
return typeof(Patches).GetMethod(v, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region LoadingScreen
|
||||||
|
/* Loading Screen Stuff */
|
||||||
|
private static bool LoadMultiplayerSession(MyObjectBuilder_World world, MyMultiplayerBase multiplayerSession)
|
||||||
|
{
|
||||||
|
MyLog.Default.WriteLine("LoadSession() - Start");
|
||||||
|
if (!MyWorkshop.CheckLocalModsAllowed(world.Checkpoint.Mods, allowLocalMods: false))
|
||||||
|
{
|
||||||
|
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MyCommonTexts.DialogTextLocalModsDisabledInMultiplayer)));
|
||||||
|
MyLog.Default.WriteLine("LoadSession() - End");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MyWorkshop.DownloadModsAsync(world.Checkpoint.Mods, delegate (bool success)
|
||||||
|
{
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
MyScreenManager.CloseAllScreensNowExcept(null);
|
||||||
|
MyGuiSandbox.Update(16);
|
||||||
|
if (MySession.Static != null)
|
||||||
|
{
|
||||||
|
MySession.Static.Unload();
|
||||||
|
MySession.Static = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string CustomBackgroundImage = null;
|
||||||
|
GetCustomLoadingScreenPath(world.Checkpoint.Mods, out CustomBackgroundImage);
|
||||||
|
|
||||||
|
MySessionLoader.StartLoading(delegate
|
||||||
|
{
|
||||||
|
|
||||||
|
LoadMultiplayer.Invoke(null, new object[] { world, multiplayerSession });
|
||||||
|
//MySession.LoadMultiplayer(world, multiplayerSession);
|
||||||
|
}, null, CustomBackgroundImage, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
multiplayerSession.Dispose();
|
||||||
|
MySessionLoader.UnloadAndExitToMenu();
|
||||||
|
if (MyGameService.IsOnline)
|
||||||
|
{
|
||||||
|
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MyCommonTexts.DialogTextDownloadModsFailed)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: new StringBuilder(string.Format(MyTexts.GetString(MyCommonTexts.DialogTextDownloadModsFailedSteamOffline), MySession.GameServiceName))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyLog.Default.WriteLine("LoadSession() - End");
|
||||||
|
}, delegate
|
||||||
|
{
|
||||||
|
multiplayerSession.Dispose();
|
||||||
|
MySessionLoader.UnloadAndExitToMenu();
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool GetCustomLoadingScreenPath(List<MyObjectBuilder_Checkpoint.ModItem> Mods, out string File)
|
||||||
|
{
|
||||||
|
File = null;
|
||||||
|
string WorkshopDir = MyFileSystem.ModsPath;
|
||||||
|
SeamlessClient.TryShow(WorkshopDir);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SeamlessClient.TryShow("Installed Mods: " + Mods);
|
||||||
|
foreach (var Mod in Mods)
|
||||||
|
{
|
||||||
|
string SearchDir = Mod.GetPath();
|
||||||
|
|
||||||
|
if (!Directory.Exists(SearchDir))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var files = Directory.GetFiles(SearchDir, "*.dds", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
if (Path.GetFileNameWithoutExtension(file) == "CustomLoadingBackground")
|
||||||
|
{
|
||||||
|
SeamlessClient.TryShow(Mod.FriendlyName + " contains a custom loading background!");
|
||||||
|
File = file;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SeamlessClient.TryShow(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
SeamlessClient.TryShow("No installed custom loading screen!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
private static void OnUserJoined(ref JoinResultMsg msg)
|
||||||
|
{
|
||||||
|
if (msg.JoinResult == JoinResult.OK)
|
||||||
|
{
|
||||||
|
//SeamlessClient.TryShow("User Joined! Result: " + msg.JoinResult.ToString());
|
||||||
|
|
||||||
|
//Invoke the switch event
|
||||||
|
OnJoinEvent?.Invoke(null, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static MethodInfo GetMethod(Type type, string MethodName, BindingFlags Flags)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MethodInfo FoundMethod = type.GetMethod(MethodName, Flags);
|
||||||
|
|
||||||
|
if (FoundMethod == null)
|
||||||
|
throw new NullReferenceException($"Method for {MethodName} is null!");
|
||||||
|
|
||||||
|
|
||||||
|
return FoundMethod;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(Exception Ex)
|
||||||
|
{
|
||||||
|
throw Ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FieldInfo GetField(Type type, string FieldName, BindingFlags Flags)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FieldInfo FoundField = type.GetField(FieldName, Flags);
|
||||||
|
|
||||||
|
if (FoundField == null)
|
||||||
|
throw new NullReferenceException($"Field for {FieldName} is null!");
|
||||||
|
|
||||||
|
|
||||||
|
return FoundField;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception Ex)
|
||||||
|
{
|
||||||
|
throw Ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ConstructorInfo GetConstructor(Type type, BindingFlags Flags, Type[] Types)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConstructorInfo FoundConstructor = type.GetConstructor(Flags, null, Types, null);
|
||||||
|
|
||||||
|
if (FoundConstructor == null)
|
||||||
|
throw new NullReferenceException($"Contructor for {type.Name} is null!");
|
||||||
|
|
||||||
|
|
||||||
|
return FoundConstructor;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception Ex)
|
||||||
|
{
|
||||||
|
throw Ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
72
SeamlessTransfer/PingServer.cs
Normal file
72
SeamlessTransfer/PingServer.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using Sandbox.Engine.Networking;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using SeamlessClientPlugin.ClientMessages;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VRage.GameServices;
|
||||||
|
|
||||||
|
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||||
|
{
|
||||||
|
public class ServerPing
|
||||||
|
{
|
||||||
|
|
||||||
|
private static WorldRequest Request;
|
||||||
|
private static Transfer Transfer;
|
||||||
|
|
||||||
|
|
||||||
|
public static void StartServerPing(Transfer ClientTransfer)
|
||||||
|
{
|
||||||
|
// We need to first ping the server to make sure its running and so we can get a connection
|
||||||
|
|
||||||
|
if (Transfer.TargetServerID == 0)
|
||||||
|
{
|
||||||
|
SeamlessClient.TryShow("This is not a valid server!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transfer = ClientTransfer;
|
||||||
|
Request = Transfer.WorldRequest;
|
||||||
|
|
||||||
|
|
||||||
|
SeamlessClient.TryShow("Beginning Redirect to server: " + Transfer.TargetServerID);
|
||||||
|
MyGameService.OnPingServerResponded += PingResponded;
|
||||||
|
MyGameService.OnPingServerFailedToRespond += FailedToRespond;
|
||||||
|
|
||||||
|
MyGameService.PingServer(Transfer.IPAdress);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PingResponded(object sender, MyGameServerItem e)
|
||||||
|
{
|
||||||
|
//If server ping was successful we need to begin the switching proccess
|
||||||
|
UnRegisterEvents();
|
||||||
|
|
||||||
|
SeamlessClient.TryShow($"{e.Name} was successfully pinged!");
|
||||||
|
SwitchServers Switcher = new SwitchServers(e, Request.DeserializeWorldData());
|
||||||
|
Switcher.BeginSwitch();
|
||||||
|
// LoadServer.LoadWorldData(e, Request.DeserializeWorldData());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void FailedToRespond(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// If the target server failed to respond, we need to exit/return to menu
|
||||||
|
|
||||||
|
UnRegisterEvents();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void UnRegisterEvents()
|
||||||
|
{
|
||||||
|
//Un-register ping events
|
||||||
|
MyGameService.OnPingServerResponded -= PingResponded;
|
||||||
|
MyGameService.OnPingServerFailedToRespond -= FailedToRespond;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
328
SeamlessTransfer/SwitchServers.cs
Normal file
328
SeamlessTransfer/SwitchServers.cs
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
|
using Sandbox.Game;
|
||||||
|
using Sandbox.Game.Entities;
|
||||||
|
using Sandbox.Game.Gui;
|
||||||
|
using Sandbox.Game.GUI;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using SeamlessClientPlugin.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
using VRage.GameServices;
|
||||||
|
using VRage.Utils;
|
||||||
|
using VRageMath;
|
||||||
|
using VRageRender;
|
||||||
|
|
||||||
|
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||||
|
{
|
||||||
|
public class SwitchServers
|
||||||
|
{
|
||||||
|
public MyGameServerItem TargetServer { get; }
|
||||||
|
public MyObjectBuilder_World TargetWorld { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public SwitchServers(MyGameServerItem TargetServer, MyObjectBuilder_World TargetWorld)
|
||||||
|
{
|
||||||
|
this.TargetServer = TargetServer;
|
||||||
|
this.TargetWorld = TargetWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void BeginSwitch()
|
||||||
|
{
|
||||||
|
MySandboxGame.Static.Invoke(delegate
|
||||||
|
{
|
||||||
|
//Set camera controller to fixed spectator
|
||||||
|
MySession.Static.SetCameraController(MyCameraControllerEnum.SpectatorFixed);
|
||||||
|
UnloadCurrentServer();
|
||||||
|
SetNewMultiplayerClient();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}, "SeamlessClient");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void SetNewMultiplayerClient()
|
||||||
|
{
|
||||||
|
// Following is called when the multiplayer is set successfully to target server
|
||||||
|
Patches.OnJoinEvent += OnJoinEvent;
|
||||||
|
|
||||||
|
|
||||||
|
MySandboxGame.Static.SessionCompatHelper.FixSessionComponentObjectBuilders(TargetWorld.Checkpoint, TargetWorld.Sector);
|
||||||
|
|
||||||
|
// Create constructors
|
||||||
|
var LayerInstance = Patches.TransportLayerConstructor.Invoke(new object[] { 2 });
|
||||||
|
var SyncInstance = Patches.SyncLayerConstructor.Invoke(new object[] { LayerInstance });
|
||||||
|
var instance = Patches.ClientConstructor.Invoke(new object[] { TargetServer, SyncInstance });
|
||||||
|
|
||||||
|
|
||||||
|
MyMultiplayer.Static = Utility.CastToReflected(instance, Patches.ClientType);
|
||||||
|
MyMultiplayer.Static.ExperimentalMode = true;
|
||||||
|
|
||||||
|
SeamlessClient.TryShow("Successfully set MyMultiplayer.Static");
|
||||||
|
|
||||||
|
MyHud.Chat.RegisterChat(MyMultiplayer.Static);
|
||||||
|
Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName);
|
||||||
|
Sync.Players.RegisterEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void OnJoinEvent(object sender, VRage.Network.JoinResultMsg e)
|
||||||
|
{
|
||||||
|
ForceClientConnection();
|
||||||
|
|
||||||
|
// Un-register the event
|
||||||
|
Patches.OnJoinEvent -= OnJoinEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void ForceClientConnection()
|
||||||
|
{
|
||||||
|
// Set the new SyncLayer to the MySession.Static.SyncLayer
|
||||||
|
Patches.MySessionLayer.SetValue(MySession.Static, MyMultiplayer.Static.SyncLayer);
|
||||||
|
|
||||||
|
LoadConnectedClients();
|
||||||
|
LoadOnlinePlayers();
|
||||||
|
SetWorldSettings();
|
||||||
|
RemoveOldEntities();
|
||||||
|
StartEntitySync();
|
||||||
|
|
||||||
|
|
||||||
|
// Allow the game to start proccessing incoming messages in the buffer
|
||||||
|
MyMultiplayer.Static.StartProcessingClientMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void LoadOnlinePlayers()
|
||||||
|
{
|
||||||
|
//Get This players ID
|
||||||
|
MyPlayer.PlayerId? savingPlayerId = new MyPlayer.PlayerId(Sync.MyId);
|
||||||
|
if (!savingPlayerId.HasValue)
|
||||||
|
{
|
||||||
|
SeamlessClient.TryShow("SavingPlayerID is null! Creating Default!");
|
||||||
|
savingPlayerId = new MyPlayer.PlayerId(Sync.MyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SeamlessClient.TryShow("Saving PlayerID: " + savingPlayerId.ToString());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (KeyValuePair<MyObjectBuilder_Checkpoint.PlayerId, MyObjectBuilder_Player> item3 in TargetWorld.Checkpoint.AllPlayersData.Dictionary)
|
||||||
|
{
|
||||||
|
MyPlayer.PlayerId playerId5 = new MyPlayer.PlayerId(item3.Key.GetClientId(), item3.Key.SerialId);
|
||||||
|
|
||||||
|
SeamlessClient.TryShow($"ConnectedPlayer: {playerId5.ToString()}");
|
||||||
|
if (savingPlayerId.HasValue && playerId5.SteamId == savingPlayerId.Value.SteamId)
|
||||||
|
{
|
||||||
|
playerId5 = new MyPlayer.PlayerId(Sync.MyId, playerId5.SerialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Patches.LoadPlayerInternal.Invoke(MySession.Static.Players, new object[] { playerId5, item3.Value, false });
|
||||||
|
ConcurrentDictionary<MyPlayer.PlayerId, MyPlayer> Players = (ConcurrentDictionary<MyPlayer.PlayerId, MyPlayer>)Patches.MPlayerGPSCollection.GetValue(MySession.Static.Players);
|
||||||
|
//LoadPlayerInternal(ref playerId5, item3.Value);
|
||||||
|
if (Players.TryGetValue(playerId5, out MyPlayer myPlayer))
|
||||||
|
{
|
||||||
|
List<Vector3> value2 = null;
|
||||||
|
if (TargetWorld.Checkpoint.AllPlayersColors != null && TargetWorld.Checkpoint.AllPlayersColors.Dictionary.TryGetValue(item3.Key, out value2))
|
||||||
|
{
|
||||||
|
myPlayer.SetBuildColorSlots(value2);
|
||||||
|
}
|
||||||
|
else if (TargetWorld.Checkpoint.CharacterToolbar != null && TargetWorld.Checkpoint.CharacterToolbar.ColorMaskHSVList != null && TargetWorld.Checkpoint.CharacterToolbar.ColorMaskHSVList.Count > 0)
|
||||||
|
{
|
||||||
|
myPlayer.SetBuildColorSlots(TargetWorld.Checkpoint.CharacterToolbar.ColorMaskHSVList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetWorldSettings()
|
||||||
|
{
|
||||||
|
//MyEntities.MemoryLimitAddFailureReset();
|
||||||
|
|
||||||
|
//Clear old list
|
||||||
|
MySession.Static.PromotedUsers.Clear();
|
||||||
|
MySession.Static.CreativeTools.Clear();
|
||||||
|
Dictionary<ulong, AdminSettingsEnum> AdminSettingsList = (Dictionary<ulong, AdminSettingsEnum>)Patches.RemoteAdminSettings.GetValue(MySession.Static);
|
||||||
|
AdminSettingsList.Clear();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Set new world settings
|
||||||
|
MySession.Static.Name = MyStatControlText.SubstituteTexts(TargetWorld.Checkpoint.SessionName);
|
||||||
|
MySession.Static.Description = TargetWorld.Checkpoint.Description;
|
||||||
|
|
||||||
|
MySession.Static.Mods = TargetWorld.Checkpoint.Mods;
|
||||||
|
MySession.Static.Settings = TargetWorld.Checkpoint.Settings;
|
||||||
|
MySession.Static.CurrentPath = MyLocalCache.GetSessionSavesPath(MyUtils.StripInvalidChars(TargetWorld.Checkpoint.SessionName), contentFolder: false, createIfNotExists: false);
|
||||||
|
MySession.Static.WorldBoundaries = TargetWorld.Checkpoint.WorldBoundaries;
|
||||||
|
MySession.Static.InGameTime = MyObjectBuilder_Checkpoint.DEFAULT_DATE;
|
||||||
|
MySession.Static.ElapsedGameTime = new TimeSpan(TargetWorld.Checkpoint.ElapsedGameTime);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MySession.Static.Password = TargetWorld.Checkpoint.Password;
|
||||||
|
MySession.Static.PreviousEnvironmentHostility = TargetWorld.Checkpoint.PreviousEnvironmentHostility;
|
||||||
|
MySession.Static.RequiresDX = TargetWorld.Checkpoint.RequiresDX;
|
||||||
|
MySession.Static.CustomLoadingScreenImage = TargetWorld.Checkpoint.CustomLoadingScreenImage;
|
||||||
|
MySession.Static.CustomLoadingScreenText = TargetWorld.Checkpoint.CustomLoadingScreenText;
|
||||||
|
MySession.Static.CustomSkybox = TargetWorld.Checkpoint.CustomSkybox;
|
||||||
|
|
||||||
|
|
||||||
|
MySession.Static.Gpss = new MyGpsCollection();
|
||||||
|
MySession.Static.Gpss.LoadGpss(TargetWorld.Checkpoint);
|
||||||
|
MyRenderProxy.RebuildCullingStructure();
|
||||||
|
//MySession.Static.Toolbars.LoadToolbars(checkpoint);
|
||||||
|
|
||||||
|
Sync.Players.RespawnComponent.InitFromCheckpoint(TargetWorld.Checkpoint);
|
||||||
|
|
||||||
|
|
||||||
|
// Set new admin settings
|
||||||
|
|
||||||
|
if (TargetWorld.Checkpoint.PromotedUsers != null)
|
||||||
|
{
|
||||||
|
MySession.Static.PromotedUsers = TargetWorld.Checkpoint.PromotedUsers.Dictionary;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MySession.Static.PromotedUsers = new Dictionary<ulong, MyPromoteLevel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (KeyValuePair<MyObjectBuilder_Checkpoint.PlayerId, MyObjectBuilder_Player> item in TargetWorld.Checkpoint.AllPlayersData.Dictionary)
|
||||||
|
{
|
||||||
|
ulong clientId = item.Key.GetClientId();
|
||||||
|
AdminSettingsEnum adminSettingsEnum = (AdminSettingsEnum)item.Value.RemoteAdminSettings;
|
||||||
|
if (TargetWorld.Checkpoint.RemoteAdminSettings != null && TargetWorld.Checkpoint.RemoteAdminSettings.Dictionary.TryGetValue(clientId, out var value))
|
||||||
|
{
|
||||||
|
adminSettingsEnum = (AdminSettingsEnum)value;
|
||||||
|
}
|
||||||
|
if (!MyPlatformGameSettings.IsIgnorePcuAllowed)
|
||||||
|
{
|
||||||
|
adminSettingsEnum &= ~AdminSettingsEnum.IgnorePcu;
|
||||||
|
adminSettingsEnum &= ~AdminSettingsEnum.KeepOriginalOwnershipOnPaste;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AdminSettingsList[clientId] = adminSettingsEnum;
|
||||||
|
if (!Sync.IsDedicated && clientId == Sync.MyId)
|
||||||
|
{
|
||||||
|
Patches.AdminSettings.SetValue(MySession.Static, adminSettingsEnum);
|
||||||
|
|
||||||
|
//m_adminSettings = adminSettingsEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!MySession.Static.PromotedUsers.TryGetValue(clientId, out var value2))
|
||||||
|
{
|
||||||
|
value2 = MyPromoteLevel.None;
|
||||||
|
}
|
||||||
|
if (item.Value.PromoteLevel > value2)
|
||||||
|
{
|
||||||
|
MySession.Static.PromotedUsers[clientId] = item.Value.PromoteLevel;
|
||||||
|
}
|
||||||
|
if (!MySession.Static.CreativeTools.Contains(clientId) && item.Value.CreativeToolsEnabled)
|
||||||
|
{
|
||||||
|
MySession.Static.CreativeTools.Add(clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConnectedClients()
|
||||||
|
{
|
||||||
|
//Re-Initilize Virtual clients
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartEntitySync()
|
||||||
|
{
|
||||||
|
SeamlessClient.TryShow("Requesting Player From Server");
|
||||||
|
Sync.Players.RequestNewPlayer(Sync.MyId, 0, MyGameService.UserName, null, realPlayer: true, initialPlayer: true);
|
||||||
|
if (MySession.Static.ControlledEntity == null && Sync.IsServer && !Sandbox.Engine.Platform.Game.IsDedicated)
|
||||||
|
{
|
||||||
|
MyLog.Default.WriteLine("ControlledObject was null, respawning character");
|
||||||
|
//m_cameraAwaitingEntity = true;
|
||||||
|
MyPlayerCollection.RequestLocalRespawn();
|
||||||
|
}
|
||||||
|
|
||||||
|
//typeof(MyGuiScreenTerminal).GetMethod("CreateTabs")
|
||||||
|
MyMultiplayer.Static.OnSessionReady();
|
||||||
|
MySession.Static.LoadDataComponents();
|
||||||
|
//MyGuiSandbox.LoadData(false);
|
||||||
|
//MyGuiSandbox.AddScreen(MyGuiSandbox.CreateScreen(MyPerGameSettings.GUI.HUDScreen));
|
||||||
|
MyRenderProxy.RebuildCullingStructure();
|
||||||
|
MyRenderProxy.CollectGarbage();
|
||||||
|
|
||||||
|
SeamlessClient.TryShow("OnlinePlayers: " + MySession.Static.Players.GetOnlinePlayers().Count);
|
||||||
|
SeamlessClient.TryShow("Loading Complete!");
|
||||||
|
|
||||||
|
MyMultiplayer.Static.OnSessionReady();
|
||||||
|
//Recreate all controls... Will fix weird gui/paint/crap
|
||||||
|
MyGuiScreenHudSpace.Static.RecreateControls(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void UnloadCurrentServer()
|
||||||
|
{
|
||||||
|
//Unload current session on game thread
|
||||||
|
if (MyMultiplayer.Static == null)
|
||||||
|
throw new Exception("MyMultiplayer.Static is null on unloading? dafuq?");
|
||||||
|
|
||||||
|
|
||||||
|
//Clear all old players and clients.
|
||||||
|
Sync.Clients.Clear();
|
||||||
|
Sync.Players.ClearPlayers();
|
||||||
|
|
||||||
|
|
||||||
|
MyHud.Chat.UnregisterChat(MyMultiplayer.Static);
|
||||||
|
MySession.Static.Gpss.RemovePlayerGpss(MySession.Static.LocalPlayerId);
|
||||||
|
MyHud.GpsMarkers.Clear();
|
||||||
|
MyMultiplayer.Static.ReplicationLayer.Disconnect();
|
||||||
|
MyMultiplayer.Static.ReplicationLayer.Dispose();
|
||||||
|
MyMultiplayer.Static.Dispose();
|
||||||
|
MyMultiplayer.Static = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveOldEntities()
|
||||||
|
{
|
||||||
|
foreach (var ent in MyEntities.GetEntities())
|
||||||
|
{
|
||||||
|
if (ent is MyPlanet)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ent.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -1,184 +0,0 @@
|
|||||||
using ProtoBuf;
|
|
||||||
using Sandbox;
|
|
||||||
using Sandbox.Engine.Multiplayer;
|
|
||||||
using Sandbox.Engine.Networking;
|
|
||||||
using Sandbox.Game.Entities;
|
|
||||||
using Sandbox.Game.Gui;
|
|
||||||
using Sandbox.Game.Multiplayer;
|
|
||||||
using Sandbox.Game.World;
|
|
||||||
using Sandbox.Graphics.GUI;
|
|
||||||
using Sandbox.ModAPI;
|
|
||||||
using SeamlessClientPlugin.ClientMessages;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using VRage;
|
|
||||||
using VRage.Game;
|
|
||||||
using VRage.GameServices;
|
|
||||||
using VRage.Network;
|
|
||||||
using VRage.Steam;
|
|
||||||
using VRage.Utils;
|
|
||||||
using VRageMath;
|
|
||||||
|
|
||||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
|
||||||
{
|
|
||||||
|
|
||||||
[ProtoContract]
|
|
||||||
public class Transfer
|
|
||||||
{
|
|
||||||
[ProtoMember(1)]
|
|
||||||
public ulong TargetServerID;
|
|
||||||
[ProtoMember(2)]
|
|
||||||
public string IPAdress;
|
|
||||||
[ProtoMember(6)]
|
|
||||||
public WorldRequest WorldRequest;
|
|
||||||
[ProtoMember(7)]
|
|
||||||
public string PlayerName;
|
|
||||||
|
|
||||||
[ProtoMember(8)]
|
|
||||||
public List<MyObjectBuilder_Gps.Entry> PlayerGPSCoords;
|
|
||||||
|
|
||||||
[ProtoMember(9)]
|
|
||||||
public MyObjectBuilder_Toolbar PlayerToolbar;
|
|
||||||
|
|
||||||
public List<Vector3> PlayerBuildSlots;
|
|
||||||
|
|
||||||
public Transfer(ulong ServerID, string IPAdress)
|
|
||||||
{
|
|
||||||
/* This is only called serverside
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.IPAdress = IPAdress;
|
|
||||||
TargetServerID = ServerID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transfer() { }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void PingServerAndBeginRedirect()
|
|
||||||
{
|
|
||||||
if (TargetServerID == 0)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow("This is not a valid server!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SeamlessClient.TryShow("SyncMyID: " + Sync.MyId.ToString());
|
|
||||||
SeamlessClient.TryShow("Beginning Redirect to server: " + TargetServerID);
|
|
||||||
MyGameService.OnPingServerResponded += MyGameService_OnPingServerResponded;
|
|
||||||
MyGameService.OnPingServerFailedToRespond += MyGameService_OnPingServerFailedToRespond;
|
|
||||||
|
|
||||||
MyGameService.PingServer(IPAdress);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MyGameService_OnPingServerFailedToRespond(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
MyGameService.OnPingServerResponded -= MyGameService_OnPingServerResponded;
|
|
||||||
MyGameService.OnPingServerFailedToRespond -= MyGameService_OnPingServerFailedToRespond;
|
|
||||||
SeamlessClient.TryShow("ServerPing failed!");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MyGameService_OnPingServerResponded(object sender, MyGameServerItem e)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
MyGameService.OnPingServerResponded -= MyGameService_OnPingServerResponded;
|
|
||||||
MyGameService.OnPingServerFailedToRespond -= MyGameService_OnPingServerFailedToRespond;
|
|
||||||
SeamlessClient.TryShow("ServerPing Successful! Attempting to connect to lobby: " + e.GameID);
|
|
||||||
|
|
||||||
|
|
||||||
LoadServer.LoadWorldData(e, WorldRequest.DeserializeWorldData());
|
|
||||||
|
|
||||||
|
|
||||||
MySandboxGame.Static.Invoke(delegate
|
|
||||||
{
|
|
||||||
StringBuilder Builder = new StringBuilder();
|
|
||||||
Builder.AppendLine("Please be patient! Some users can spend a minute switching servers... others may be able to swtich faster. Lots of factors to consider.");
|
|
||||||
Builder.AppendLine();
|
|
||||||
Builder.AppendLine("Sitting in spectator is perfectly normal for a few seconds!");
|
|
||||||
|
|
||||||
MyAPIGateway.Utilities.ShowMissionScreen("Switching Servers!",null, null, Builder.ToString(), null, "Ok!");
|
|
||||||
//MySessionLoader.UnloadAndExitToMenu();
|
|
||||||
UnloadCurrentServer();
|
|
||||||
|
|
||||||
//MyJoinGameHelper.JoinGame(e, true);
|
|
||||||
LoadServer.ResetMPClient();
|
|
||||||
|
|
||||||
ClearEntities();
|
|
||||||
//ReloadPatch.SeamlessSwitch = false;
|
|
||||||
}, "SeamlessClient");
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void UnloadCurrentServer()
|
|
||||||
{
|
|
||||||
if (MyMultiplayer.Static != null)
|
|
||||||
{
|
|
||||||
Sync.Clients.Clear();
|
|
||||||
Sync.Players.ClearPlayers();
|
|
||||||
|
|
||||||
MyHud.Chat.UnregisterChat(MyMultiplayer.Static);
|
|
||||||
//OnPlayerCreated
|
|
||||||
//OnConnectedClient
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Could throw error when there are no gps points
|
|
||||||
var PCollection = MySession.Static.Gpss[MySession.Static.LocalPlayerId];
|
|
||||||
PCollection?.Clear();
|
|
||||||
SeamlessClient.TryShow(PCollection.Count + "registered GPS points");
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
SeamlessClient.TryShow(ex.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MyHud.GpsMarkers.Clear();
|
|
||||||
|
|
||||||
|
|
||||||
MyMultiplayer.Static.ReplicationLayer.Disconnect();
|
|
||||||
MyMultiplayer.Static.ReplicationLayer.Dispose();
|
|
||||||
|
|
||||||
MyMultiplayer.Static.Dispose();
|
|
||||||
MyMultiplayer.Static = null;
|
|
||||||
|
|
||||||
//Sync.Clients.Clear();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MyGuiSandbox.UnloadContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void ClearEntities()
|
|
||||||
{
|
|
||||||
foreach (var ent in MyEntities.GetEntities())
|
|
||||||
{
|
|
||||||
if (ent is MyPlanet)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ent.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@@ -25,6 +25,7 @@ namespace SeamlessClientPlugin.Utilities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static T Deserialize<T>(byte[] data)
|
public static T Deserialize<T>(byte[] data)
|
||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
@@ -36,7 +37,6 @@ namespace SeamlessClientPlugin.Utilities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static dynamic CastToReflected(this object o, Type type)
|
public static dynamic CastToReflected(this object o, Type type)
|
||||||
{
|
{
|
||||||
return Convert.ChangeType(o, type);
|
return Convert.ChangeType(o, type);
|
||||||
|
Reference in New Issue
Block a user