Compare commits
6 Commits
NexusV3-Su
...
actual-v3
Author | SHA1 | Date | |
---|---|---|---|
7b5a895246 | |||
d84f37bea7 | |||
c8c0255edd | |||
95d4b1ba27 | |||
7db71ab013 | |||
4e728d823e |
44
.github/workflows/build.yml
vendored
Normal file
44
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
compute-version:
|
||||
name: Compute Version
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- id: version
|
||||
uses: paulhatch/semantic-version@v5.3.0
|
||||
with:
|
||||
tag_prefix: ''
|
||||
major_pattern: 'Add project files'
|
||||
minor_pattern: 'feature:'
|
||||
bump_each_commit: true
|
||||
enable_prerelease_mode: false
|
||||
|
||||
build-nuget:
|
||||
name: Build Nuget package
|
||||
runs-on: ubuntu-latest
|
||||
needs: [compute-version]
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
|
||||
- run: dotnet restore ./SeamlessClient.csproj --locked-mode
|
||||
name: Restore Project
|
||||
|
||||
- run: dotnet pack -c Release -o ./pub ./SeamlessClient.csproj --no-restore -p:Version="${{ needs.compute-version.outputs.version }}"
|
||||
name: Pack Project
|
||||
|
||||
- name: Push Project
|
||||
run: dotnet nuget push -s https://ng.zznty.ru/v3/index.json -k ${{ secrets.NUGET_API_KEY }} ./pub/*.nupkg
|
@@ -34,12 +34,12 @@ namespace SeamlessClient.Components
|
||||
private bool ScannedMods = false;
|
||||
|
||||
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());
|
||||
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)
|
||||
{
|
||||
@@ -97,7 +97,7 @@ namespace SeamlessClient.Components
|
||||
|
||||
//Use custom loading screen
|
||||
GUILoadingScreen myGuiScreenLoading = new GUILoadingScreen(newGameplayScreen, MyGuiScreenGamePlay.Static, customLoadingBackground, customLoadingtext);
|
||||
|
||||
|
||||
myGuiScreenLoading.OnScreenLoadingFinished += delegate
|
||||
{
|
||||
if (MySession.Static != null)
|
||||
|
119
Components/ModAPI.cs
Normal file
119
Components/ModAPI.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -39,6 +39,10 @@ namespace SeamlessClient.Components
|
||||
return;
|
||||
|
||||
MyGuiControlTable myGuiControlTable = (MyGuiControlTable)typeof(MyGuiScreenMedicals).GetField("m_respawnsTable", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(__instance);
|
||||
if (myGuiControlTable == null)
|
||||
return;
|
||||
|
||||
|
||||
string s = MyTexts.GetString(MySpaceTexts.SpawnInSpaceSuit);
|
||||
foreach (var item in myGuiControlTable.Rows)
|
||||
{
|
||||
@@ -51,8 +55,8 @@ namespace SeamlessClient.Components
|
||||
item.GetCell(0).Text.Append("Nexus Lobby");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -51,11 +51,11 @@ namespace SeamlessClient.Components
|
||||
|
||||
double t = Math.Round(CalculateTimeToTarget(v0, distance), 0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(t <= 0)
|
||||
|
||||
if (t <= 0)
|
||||
return;
|
||||
|
||||
stringBuilder.AppendLine($" [T-{FormatDuration(t)}]");
|
||||
|
@@ -47,7 +47,7 @@ namespace SeamlessClient.OnlinePlayersWindow
|
||||
|
||||
foreach (OnlineClientServer server in servers)
|
||||
{
|
||||
if(server.ServerID == CurrentServer)
|
||||
if (server.ServerID == CurrentServer)
|
||||
{
|
||||
onlineServer = server;
|
||||
continue;
|
||||
|
@@ -91,7 +91,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
private void PauseResetTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if(MySandboxGame.IsPaused)
|
||||
if (MySandboxGame.IsPaused)
|
||||
{
|
||||
Seamless.TryShow("Game is still paused... Attempting to unpause!");
|
||||
MySandboxGame.PausePop();
|
||||
@@ -164,7 +164,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//SendPlayerData
|
||||
|
||||
|
||||
@@ -179,6 +179,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
MySandboxGame.PausePop();
|
||||
}
|
||||
|
||||
ModAPI.ServerSwitched();
|
||||
SendPlayerData.Invoke(MyMultiplayer.Static, new object[] { MyGameService.OnlineName });
|
||||
isSwitch = false;
|
||||
}
|
||||
@@ -186,19 +187,19 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
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;
|
||||
|
||||
|
||||
|
||||
//Dictionary<ulong, MyConnectedClientData>
|
||||
|
||||
IDictionary m_memberData = (IDictionary)PatchUtils.GetField(PatchUtils.ClientType, "m_memberData").GetValue(MyMultiplayer.Static);
|
||||
|
||||
|
||||
Seamless.TryShow($"{m_memberData.Count} members from clients");
|
||||
|
||||
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}");
|
||||
if (keys.Contains(clients[i].SteamId))
|
||||
@@ -206,8 +207,8 @@ namespace SeamlessClient.ServerSwitching
|
||||
Seamless.TryShow($"Remove {clients[i].SteamId}");
|
||||
clients.RemoveAt(i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -217,7 +218,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
private static bool ProcessAllMembersData(ref AllMembersDataMsg msg)
|
||||
{
|
||||
if(!isSwitch)
|
||||
if (!isSwitch)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -245,7 +246,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
private static bool RemovePlayerFromDict(MyPlayer.PlayerId playerId)
|
||||
{
|
||||
//Seamless.TryShow($"Removing player {playerId.SteamId} from dictionariy! \n {Environment.StackTrace.ToString()} - Sender: {MyEventContext.Current.Sender}");
|
||||
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
@@ -272,7 +273,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
{
|
||||
if (steamId != Sync.MyId)
|
||||
return;
|
||||
|
||||
|
||||
//Seamless.TryShow(Environment.StackTrace.ToString());
|
||||
}
|
||||
|
||||
@@ -307,13 +308,13 @@ namespace SeamlessClient.ServerSwitching
|
||||
originalLocalCharacter = MySession.Static.LocalCharacter;
|
||||
//originalControlledEntity = MySession.Static.ControlledEntity;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
player = MySession.Static.LocalHumanPlayer.GetObjectBuilder();
|
||||
player.Connected = false;
|
||||
|
||||
AsyncInvoke.InvokeAsync(() =>
|
||||
AsyncInvoke.InvokeAsync(() =>
|
||||
{
|
||||
Seamless.TryShow($"Needs entity Unload: {needsEntityUnload}");
|
||||
|
||||
@@ -326,7 +327,8 @@ namespace SeamlessClient.ServerSwitching
|
||||
UnloadServer();
|
||||
SetNewMultiplayerClient();
|
||||
|
||||
}catch(Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Seamless.TryShow(ex.ToString());
|
||||
}
|
||||
@@ -390,7 +392,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
//client.Disconnect();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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}");
|
||||
|
||||
|
||||
|
||||
ModAPI.StartModSwitching();
|
||||
|
||||
//MyMultiplayer.Static.ReplicationLayer.Disconnect();
|
||||
//MyMultiplayer.Static.ReplicationLayer.Dispose();
|
||||
@@ -464,7 +466,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
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}");
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
typeof(MyMultiplayerBase).GetProperty("ServerId", BindingFlags.Public | BindingFlags.Instance).SetValue(MyMultiplayer.Static, TargetServer.SteamID);
|
||||
|
||||
|
||||
|
||||
MyGameService.ConnectToServer(TargetServer, delegate (JoinResult joinResult)
|
||||
{
|
||||
@@ -503,7 +505,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
MyMultiplayer.Static = UtilExtensions.CastToReflected(instance, PatchUtils.ClientType);
|
||||
MyMultiplayer.Static.ExperimentalMode = true;
|
||||
|
||||
|
||||
|
||||
|
||||
// Set the new SyncLayer to the MySession.Static.SyncLayer
|
||||
MySessionLayer.SetValue(MySession.Static, MyMultiplayer.Static.SyncLayer);
|
||||
@@ -521,7 +523,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
private void StartSwitch()
|
||||
{
|
||||
|
||||
|
||||
MyReplicationClient clienta = (MyReplicationClient)MyMultiplayer.Static.ReplicationLayer;
|
||||
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}");
|
||||
@@ -534,14 +536,14 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
|
||||
|
||||
List<ulong> clients = new List<ulong>();
|
||||
foreach(var client in Sync.Clients.GetClients())
|
||||
List<ulong> clients = new List<ulong>();
|
||||
foreach (var client in Sync.Clients.GetClients())
|
||||
{
|
||||
clients.Add(client.SteamUserId);
|
||||
Seamless.TryShow($"ADDING {client.SteamUserId} - {Sync.MyId}");
|
||||
}
|
||||
|
||||
foreach(var client in clients)
|
||||
foreach (var client in clients)
|
||||
{
|
||||
if (client == TargetServer.SteamID || client == Sync.MyId)
|
||||
continue;
|
||||
@@ -573,7 +575,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
typeof(MySandboxGame).GetField("m_pauseStackCount", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, 0);
|
||||
|
||||
|
||||
|
||||
|
||||
MyHud.Chat.RegisterChat(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
|
||||
//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 Streaming: {clienta.HasPendingStreamingReplicables} - LastMessage: {clienta.LastMessageFromServer}");
|
||||
|
||||
|
||||
originalLocalCharacter?.Close();
|
||||
ResetReplicationTime(true);
|
||||
|
||||
@@ -764,7 +766,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
}
|
||||
}
|
||||
|
||||
private void StartEntitySync()
|
||||
private void StartEntitySync()
|
||||
{
|
||||
Seamless.TryShow("Requesting Player From Server");
|
||||
|
||||
@@ -772,7 +774,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
if (!Sandbox.Engine.Platform.Game.IsDedicated && MySession.Static.LocalHumanPlayer == null)
|
||||
{
|
||||
Seamless.TryShow("RequestNewPlayer");
|
||||
|
||||
|
||||
|
||||
}
|
||||
else if (MySession.Static.ControlledEntity == null && Sync.IsServer && !Sandbox.Engine.Platform.Game.IsDedicated)
|
||||
@@ -782,7 +784,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
MyPlayerCollection.RequestLocalRespawn();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Request client state batch
|
||||
(MyMultiplayer.Static as MyMultiplayerClientBase).RequestBatchConfirmation();
|
||||
@@ -832,7 +834,7 @@ namespace SeamlessClient.ServerSwitching
|
||||
|
||||
player.IsWildlifeAgent = true;
|
||||
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());
|
||||
|
||||
|
@@ -27,12 +27,19 @@ using Sandbox.Game;
|
||||
using VRage.Game.ModAPI;
|
||||
using VRage.Utils;
|
||||
using SeamlessClient.ServerSwitching;
|
||||
using Sandbox.Game.Entities.Character;
|
||||
using VRage.Game.Utils;
|
||||
using VRage;
|
||||
using Sandbox.Game.GameSystems.CoordinateSystem;
|
||||
|
||||
namespace SeamlessClient.Components
|
||||
{
|
||||
public class ServerSwitcherComponentOLD : ComponentBase
|
||||
{
|
||||
private static bool isSeamlessSwitching = false;
|
||||
private static bool isSeamlessSwitching { get; set; } = false;
|
||||
private static bool WaitingForClientCheck { get; set; } = false;
|
||||
|
||||
|
||||
private static ConstructorInfo TransportLayerConstructor;
|
||||
private static ConstructorInfo SyncLayerConstructor;
|
||||
private static ConstructorInfo ClientConstructor;
|
||||
@@ -53,15 +60,34 @@ namespace SeamlessClient.Components
|
||||
private string OldArmorSkin { get; set; } = string.Empty;
|
||||
|
||||
public ServerSwitcherComponentOLD() { Instance = this; }
|
||||
public static string SwitchingText = string.Empty;
|
||||
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
//Toggle waiting for client check
|
||||
if (WaitingForClientCheck == false && isSeamlessSwitching)
|
||||
WaitingForClientCheck = true;
|
||||
|
||||
if (WaitingForClientCheck && MySession.Static.LocalHumanPlayer != null)
|
||||
WaitingForClientCheck = false;
|
||||
|
||||
if (isSeamlessSwitching || WaitingForClientCheck)
|
||||
{
|
||||
//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 - 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Patch(Harmony patcher)
|
||||
{
|
||||
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 });
|
||||
MySessionLayer = PatchUtils.GetProperty(typeof(MySession), "SyncLayer");
|
||||
|
||||
@@ -74,8 +100,51 @@ namespace SeamlessClient.Components
|
||||
InitVirtualClients = PatchUtils.GetMethod(PatchUtils.VirtualClientsType, "Init");
|
||||
VirtualClients = PatchUtils.GetField(typeof(MySession), "VirtualClients");
|
||||
|
||||
patcher.Patch(onJoin, postfix: new HarmonyMethod(Get(typeof(ServerSwitcherComponentOLD), nameof(OnUserJoined))));
|
||||
base.Patch(patcher);
|
||||
patcher.Patch(onJoin, postfix: new HarmonyMethod(Get(typeof(ServerSwitcherComponentOLD), nameof(OnUserJoined))));
|
||||
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -85,13 +154,30 @@ namespace SeamlessClient.Components
|
||||
//SeamlessClient.TryShow("User Joined! Result: " + msg.JoinResult.ToString());
|
||||
|
||||
//Invoke the switch event
|
||||
|
||||
SwitchingText = "Server Responded! Removing Old Entities and forcing client connection!";
|
||||
RemoveOldEntities();
|
||||
ForceClientConnection();
|
||||
ModAPI.ServerSwitched();
|
||||
|
||||
|
||||
|
||||
|
||||
MySession.Static.LocalHumanPlayer?.Character?.Stand();
|
||||
isSeamlessSwitching = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartBackendSwitch(MyGameServerItem _TargetServer, MyObjectBuilder_World _TargetWorld)
|
||||
{
|
||||
|
||||
if (MySession.Static.LocalCharacter != null)
|
||||
{
|
||||
var viewMatrix = MySession.Static.LocalCharacter.GetViewMatrix();
|
||||
MySpectator.Static.SetViewMatrix(viewMatrix);
|
||||
}
|
||||
|
||||
SwitchingText = "Starting Seamless Switch... Please wait!";
|
||||
isSeamlessSwitching = true;
|
||||
OldArmorSkin = MySession.Static.LocalHumanPlayer.BuildArmorSkin;
|
||||
TargetServer = _TargetServer;
|
||||
@@ -99,13 +185,18 @@ namespace SeamlessClient.Components
|
||||
|
||||
MySandboxGame.Static.Invoke(delegate
|
||||
{
|
||||
//Pause the game/update thread while we load
|
||||
MySandboxGame.IsPaused = true;
|
||||
|
||||
//Set camera controller to fixed spectator
|
||||
MySession.Static.SetCameraController(MyCameraControllerEnum.SpectatorFixed);
|
||||
UnloadCurrentServer();
|
||||
SetNewMultiplayerClient();
|
||||
//SeamlessClient.IsSwitching = false;
|
||||
|
||||
ModAPI.StartModSwitching();
|
||||
|
||||
//SeamlessClient.IsSwitching = false;
|
||||
|
||||
SwitchingText = "Waiting for server response...";
|
||||
}, "SeamlessClient");
|
||||
|
||||
}
|
||||
@@ -129,12 +220,13 @@ namespace SeamlessClient.Components
|
||||
// Set the new SyncLayer to the MySession.Static.SyncLayer
|
||||
MySessionLayer.SetValue(MySession.Static, MyMultiplayer.Static.SyncLayer);
|
||||
|
||||
SwitchingText = "New Multiplayer Session Set";
|
||||
Seamless.TryShow("Successfully set MyMultiplayer.Static");
|
||||
|
||||
MySandboxGame.IsPaused = true;
|
||||
|
||||
Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName);
|
||||
Sync.Players.RegisterEvents();
|
||||
|
||||
SwitchingText = "Registering Player Events";
|
||||
}
|
||||
|
||||
|
||||
@@ -142,12 +234,14 @@ namespace SeamlessClient.Components
|
||||
private static void ForceClientConnection()
|
||||
{
|
||||
|
||||
|
||||
|
||||
//Set World Settings
|
||||
SetWorldSettings();
|
||||
|
||||
//Load force load any connected players
|
||||
LoadConnectedClients();
|
||||
|
||||
SwitchingText = "Loaded Connected Clients";
|
||||
|
||||
|
||||
MySector.InitEnvironmentSettings(TargetWorld.Sector.Environment);
|
||||
@@ -159,10 +253,8 @@ namespace SeamlessClient.Components
|
||||
|
||||
MyModAPIHelper.Initialize();
|
||||
MySession.Static.LoadDataComponents();
|
||||
|
||||
//MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents);
|
||||
MyModAPIHelper.Initialize();
|
||||
// MySession.Static.LoadObjectBuildersComponents(TargetWorld.Checkpoint.SessionComponents);
|
||||
|
||||
|
||||
|
||||
//MethodInfo A = typeof(MySession).GetMethod("LoadGameDefinition", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
@@ -171,22 +263,31 @@ namespace SeamlessClient.Components
|
||||
|
||||
|
||||
MyMultiplayer.Static.OnSessionReady();
|
||||
|
||||
SwitchingText = "Session Ready";
|
||||
|
||||
UpdateWorldGenerator();
|
||||
|
||||
StartEntitySync();
|
||||
|
||||
//Resume the game/update thread
|
||||
MySandboxGame.IsPaused = false;
|
||||
|
||||
MyHud.Chat.RegisterChat(MyMultiplayer.Static);
|
||||
GpsRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static });
|
||||
|
||||
SwitchingText = "Registered Chat";
|
||||
|
||||
// Allow the game to start proccessing incoming messages in the buffer
|
||||
MyMultiplayer.Static.StartProcessingClientMessages();
|
||||
|
||||
//Recreate all controls... Will fix weird gui/paint/crap
|
||||
MyGuiScreenHudSpace.Static.RecreateControls(true);
|
||||
SwitchingText = "Client Registered. Waiting for entities from server...";
|
||||
|
||||
|
||||
Seamless.TryShow($"LocalHumanPlayer = {MySession.Static.LocalHumanPlayer == null}");
|
||||
|
||||
|
||||
|
||||
//MySession.Static.LocalHumanPlayer.BuildArmorSkin = OldArmorSkin;
|
||||
}
|
||||
|
||||
@@ -351,6 +452,8 @@ namespace SeamlessClient.Components
|
||||
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 });
|
||||
|
||||
|
||||
@@ -441,8 +544,7 @@ namespace SeamlessClient.Components
|
||||
throw new Exception("MyMultiplayer.Static is null on unloading? dafuq?");
|
||||
|
||||
|
||||
RemoveOldEntities();
|
||||
|
||||
SwitchingText = "Unloading Local Server Components";
|
||||
//Try and close the quest log
|
||||
MySessionComponentIngameHelp component = MySession.Static.GetComponent<MySessionComponentIngameHelp>();
|
||||
component?.TryCancelObjective();
|
||||
@@ -463,25 +565,39 @@ namespace SeamlessClient.Components
|
||||
MyMultiplayer.Static.ReplicationLayer.Dispose();
|
||||
MyMultiplayer.Static.Dispose();
|
||||
MyMultiplayer.Static = null;
|
||||
SwitchingText = "Local Multiplayer Disposed";
|
||||
|
||||
//Clear grid coord systems
|
||||
ResetCoordinateSystems();
|
||||
|
||||
//Close any respawn screens that are open
|
||||
MyGuiScreenMedicals.Close();
|
||||
|
||||
//MySession.Static.UnloadDataComponents();
|
||||
//Unload any lingering updates queued
|
||||
MyEntities.Orchestrator.Unload();
|
||||
|
||||
}
|
||||
|
||||
private void RemoveOldEntities()
|
||||
private static void RemoveOldEntities()
|
||||
{
|
||||
foreach (var ent in MyEntities.GetEntities())
|
||||
{
|
||||
if (ent is MyPlanet)
|
||||
{
|
||||
//Re-Add planet updates
|
||||
MyEntities.RegisterForUpdate(ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
ent.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResetCoordinateSystems()
|
||||
{
|
||||
AccessTools.Field(typeof(MyCoordinateSystem), "m_lastCoordSysId").SetValue(MyCoordinateSystem.Static, 1L);
|
||||
AccessTools.Field(typeof(MyCoordinateSystem), "m_localCoordSystems").SetValue(MyCoordinateSystem.Static, new Dictionary<long, MyLocalCoordSys>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -113,7 +113,7 @@ namespace SeamlessClient.GUI.Screens
|
||||
m_isTopMostScreen = true;
|
||||
|
||||
object instance = PatchUtils.GetProperty(PatchUtils.MyLoadingPerformance, "Instance").GetValue(null);
|
||||
if(instance != null)
|
||||
if (instance != null)
|
||||
PatchUtils.GetMethod(PatchUtils.MyLoadingPerformance, "StartTiming").Invoke(instance, null);
|
||||
|
||||
//MyLoadingPerformance.Instance.StartTiming();
|
||||
@@ -160,7 +160,7 @@ namespace SeamlessClient.GUI.Screens
|
||||
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.TextBoxAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM;
|
||||
Controls.Add(m_wheel);
|
||||
|
||||
|
||||
|
||||
|
||||
RefreshText();
|
||||
}
|
||||
|
||||
@@ -235,12 +235,12 @@ namespace SeamlessClient.GUI.Screens
|
||||
MySandboxGame.Log.DecreaseIndent();
|
||||
MySandboxGame.Log.WriteLine("MyGuiScreenLoading.LoadContent - END");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static string GetRandomBackgroundTexture()
|
||||
{
|
||||
|
||||
|
||||
|
||||
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";
|
||||
@@ -531,9 +531,9 @@ namespace SeamlessClient.GUI.Screens
|
||||
MyGuiManager.GetSafeHeightFullScreenPictureSize(MyGuiConstants.LOADING_BACKGROUND_TEXTURE_REAL_SIZE, out outRect);
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -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, 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))
|
||||
{
|
||||
string font = m_font;
|
||||
@@ -590,7 +590,7 @@ namespace SeamlessClient.GUI.Screens
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void BackgroundTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
|
@@ -24,7 +24,7 @@ namespace SeamlessClient.Messages
|
||||
[ProtoMember(3)] public string PlayerName;
|
||||
[ProtoMember(4)] public byte[] WorldData;
|
||||
|
||||
[ProtoMember(5)] public MyObjectBuilder_Gps GpsCollection;
|
||||
[ProtoMember(5)] public MyObjectBuilder_Gps GpsCollection { get; set; }
|
||||
|
||||
public WorldRequest()
|
||||
{
|
||||
@@ -37,7 +37,7 @@ namespace SeamlessClient.Messages
|
||||
this.IdentityID = playerIdentity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void SerializeWorldData(MyObjectBuilder_World WorldData)
|
||||
{
|
||||
|
@@ -385,8 +385,6 @@ namespace SeamlessClient.OnlinePlayersWindow
|
||||
Controls.Add(m_playersTable);
|
||||
|
||||
|
||||
string servername = PlayersWindowComponent.onlineServer?.ServerName ?? "thisServer";
|
||||
|
||||
foreach (MyPlayer onlinePlayer in Sync.Players.GetOnlinePlayers())
|
||||
{
|
||||
if (onlinePlayer.Id.SerialId != 0)
|
||||
@@ -403,16 +401,14 @@ namespace SeamlessClient.OnlinePlayersWindow
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AddPlayer(onlinePlayer.Id.SteamId, servername);
|
||||
AddPlayer(onlinePlayer.Id.SteamId, $"{MyMultiplayer.Static.HostName ?? "thisServer"}*");
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -796,7 +792,7 @@ namespace SeamlessClient.OnlinePlayersWindow
|
||||
|
||||
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)
|
||||
@@ -962,7 +958,7 @@ namespace SeamlessClient.OnlinePlayersWindow
|
||||
{
|
||||
Seamless.TryShow("Requesting Refresh Pings!");
|
||||
MyMultiplayer.RaiseStaticEvent((IMyEventOwner s) => MyGuiScreenPlayers.RequestPingsAndRefresh);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -33,5 +33,5 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyVersion("2.0.0.6")] //Set these both to the same
|
||||
[assembly: AssemblyFileVersion("2.0.0.6")]
|
||||
[assembly: AssemblyVersion("3.0.0.10")] //Set these both to the same
|
||||
[assembly: AssemblyFileVersion("3.0.0.10")]
|
||||
|
18
README.md
18
README.md
@@ -13,9 +13,21 @@ With Nexus servers, all data is shared between servers. (Factions, Identities, P
|
||||
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
||||
|
||||
|
45
Seamless.cs
45
Seamless.cs
@@ -1,6 +1,8 @@
|
||||
using HarmonyLib;
|
||||
using CringePlugins.Utils;
|
||||
using HarmonyLib;
|
||||
using NLog.Fluent;
|
||||
using Sandbox;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Game.Localization;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.ModAPI;
|
||||
@@ -37,9 +39,8 @@ namespace SeamlessClient
|
||||
private bool Initilized = false;
|
||||
public static bool isSeamlessServer { get; private set; } = false;
|
||||
public static bool isDebug = false;
|
||||
public static bool UseNewVersion = true;
|
||||
public static bool UseNewVersion = false;
|
||||
|
||||
|
||||
|
||||
|
||||
public void Init(object gameInstance)
|
||||
@@ -47,21 +48,24 @@ namespace SeamlessClient
|
||||
TryShow($"Running Seamless Client Plugin v[{SeamlessVersion}]");
|
||||
SeamlessPatcher = new Harmony("SeamlessClientPatcher");
|
||||
GetComponents();
|
||||
|
||||
|
||||
PatchComponents(SeamlessPatcher);
|
||||
MySession.LoadingStep += SessionLoaded;
|
||||
}
|
||||
|
||||
|
||||
private void SessionLoaded(LoadingProgress progress)
|
||||
{
|
||||
if (progress >= LoadingProgress.PROGRESS_STEP8)
|
||||
SendSeamlessVersion();
|
||||
}
|
||||
|
||||
private void GetComponents()
|
||||
{
|
||||
int failedCount = 0;
|
||||
foreach (Type type in thisAssembly.GetTypes())
|
||||
foreach (Type type in IntrospectionContext.Global.CollectDerivedTypes<ComponentBase>(typeof(Seamless).Module))
|
||||
{
|
||||
|
||||
if (type.BaseType != typeof(ComponentBase))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
ComponentBase s = (ComponentBase)Activator.CreateInstance(type);
|
||||
@@ -95,23 +99,25 @@ namespace SeamlessClient
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void InitilizeComponents()
|
||||
{
|
||||
foreach(ComponentBase component in allComps)
|
||||
foreach (ComponentBase component in allComps)
|
||||
{
|
||||
try
|
||||
{
|
||||
component.Initilized();
|
||||
TryShow($"Initilized {component.GetType()}");
|
||||
|
||||
}catch(Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TryShow(ex, $"Failed to initialize {component.GetType()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void MessageHandler(ushort packetID, byte[] data, ulong sender, bool fromServer)
|
||||
{
|
||||
//Ignore anything except dedicated server
|
||||
@@ -129,23 +135,20 @@ namespace SeamlessClient
|
||||
isSeamlessServer = true;
|
||||
switch (msg.MessageType)
|
||||
{
|
||||
case ClientMessageType.FirstJoin:
|
||||
Seamless.TryShow("Sending First Join!");
|
||||
SendSeamlessVersion();
|
||||
break;
|
||||
|
||||
case ClientMessageType.TransferServer:
|
||||
StartSwitch(msg.GetTransferData());
|
||||
break;
|
||||
|
||||
case ClientMessageType.OnlinePlayers:
|
||||
//Not implemented yet
|
||||
var playerData = msg.GetOnlinePlayers();
|
||||
PlayersWindowComponent.ApplyRecievedPlayers(playerData.OnlineServers, playerData.currentServerID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static void SendSeamlessVersion()
|
||||
{
|
||||
ClientMessage response = new ClientMessage(SeamlessVersion.ToString());
|
||||
@@ -157,10 +160,14 @@ namespace SeamlessClient
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public void Update()
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
allComps.ForEach(x => x.Update());
|
||||
|
||||
if (MyAPIGateway.Multiplayer == null)
|
||||
@@ -216,8 +223,6 @@ namespace SeamlessClient
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static void TryShow(string message)
|
||||
{
|
||||
if (MySession.Static?.LocalHumanPlayer != null && isDebug)
|
||||
|
@@ -1,141 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{883B492D-823E-4CC3-BD35-07FEF06F8359}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SeamlessClient</RootNamespace>
|
||||
<AssemblyName>SeamlessClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony, Version=2.3.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Lib.Harmony.2.3.3\lib\net48\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog">
|
||||
<HintPath>GameBinaries\NLog.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ProtoBuf.Net">
|
||||
<HintPath>GameBinaries\ProtoBuf.Net.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ProtoBuf.Net.Core, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>GameBinaries\ProtoBuf.Net.Core.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Common">
|
||||
<HintPath>GameBinaries\Sandbox.Common.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Game">
|
||||
<HintPath>GameBinaries\Sandbox.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Game.XmlSerializers">
|
||||
<HintPath>GameBinaries\Sandbox.Game.XmlSerializers.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Graphics">
|
||||
<HintPath>GameBinaries\Sandbox.Graphics.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SpaceEngineers.Game">
|
||||
<HintPath>GameBinaries\SpaceEngineers.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="VRage">
|
||||
<HintPath>GameBinaries\VRage.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Game">
|
||||
<HintPath>GameBinaries\VRage.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Input">
|
||||
<HintPath>GameBinaries\VRage.Input.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Library">
|
||||
<HintPath>GameBinaries\VRage.Library.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Math">
|
||||
<HintPath>GameBinaries\VRage.Math.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Render">
|
||||
<HintPath>GameBinaries\VRage.Render.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Components\EntityPerformanceImprovements.cs" />
|
||||
<Compile Include="Components\LoadingScreenComponent.cs" />
|
||||
<Compile Include="Components\MyGUIScreenMedicalsPatch.cs" />
|
||||
<Compile Include="Components\MyHudTimeTracker.cs" />
|
||||
<Compile Include="Components\ServerSwitcherComponentOLD.cs" />
|
||||
<Compile Include="GUI\Screens\GUILoadingScreen.cs" />
|
||||
<Compile Include="Messages\OnlinePlayerData.cs" />
|
||||
<Compile Include="Utilities\UtilExtensions.cs" />
|
||||
<Compile Include="Utilities\PatchUtils.cs" />
|
||||
<Compile Include="Messages\ClientMessage.cs" />
|
||||
<Compile Include="Messages\TransferData.cs" />
|
||||
<Compile Include="Messages\WorldRequestData.cs" />
|
||||
<Compile Include="OnlinePlayersWindow\OnlineNexusPlayersWindow.cs" />
|
||||
<Compile Include="Components\PlayersWindowComponent.cs" />
|
||||
<Compile Include="Seamless.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Components\ServerSwitcherComponent.cs" />
|
||||
<Compile Include="Utilities\AsyncInvoke.cs" />
|
||||
<Compile Include="Utilities\MessageUtils.cs" />
|
||||
<Compile Include="Utilities\ComponentBase.cs" />
|
||||
<Compile Include="Utilities\Types.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="SetupSolution.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="ServerSwitching\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="SeamlessClient.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<Nullable>disable</Nullable>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<PackageType>CringePlugin</PackageType>
|
||||
<RestoreAdditionalProjectSources>https://ng.zznty.ru/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Authors>Casimir</Authors>
|
||||
<PackageId>Plugin.Casimir255.SeamlessClient</PackageId>
|
||||
<AssemblyName>Plugin.Casimir255.SeamlessClient</AssemblyName>
|
||||
<Title>Nexus Seamless Switcher</Title>
|
||||
<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>
|
||||
<PackageProjectUrl>https://git.zznty.ru/PvE/SeamlessClient</PackageProjectUrl>
|
||||
<RepositoryUrl>https://git.zznty.ru/PvE/SeamlessClient</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CringePlugins" Version="*" ExcludeAssets="runtime; native"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" ExcludeAssets="runtime; native" PrivateAssets="all"/>
|
||||
<PackageReference Include="Steamworks.NET" Version="20.1.0" ExcludeAssets="runtime; native" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="CopyFiles" AfterTargets="PostBuildEvent">
|
||||
<PropertyGroup>
|
||||
<AppdataPath>$([System.Environment]::GetFolderPath(SpecialFolder.ApplicationData))</AppdataPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<OutputFiles Include="$(OutputPath)\*"/>
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(OutputFiles)" DestinationFolder="$(AppdataPath)\CringeLauncher\plugins\$(ProjectName)" OverwriteReadOnlyFiles="true"/>
|
||||
</Target>
|
||||
|
||||
|
||||
</Project>
|
@@ -1,23 +1,23 @@
|
||||
<?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">
|
||||
<!-- 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>
|
||||
<!-- 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>
|
||||
|
||||
<!-- Optional tag that specifies the group this plugin belongs to. Only one plugin from a given group can be enabled. -->
|
||||
<GroupId>NexusSeamless</GroupId>
|
||||
<!-- Optional tag that specifies the group this plugin belongs to. Only one plugin from a given group can be enabled. -->
|
||||
<GroupId>NexusSeamless</GroupId>
|
||||
|
||||
<!-- The name of your plugin that will appear in the list. -->
|
||||
<FriendlyName>SeamlessClient</FriendlyName>
|
||||
<!-- The name of your plugin that will appear in the list. -->
|
||||
<FriendlyName>SeamlessClient</FriendlyName>
|
||||
|
||||
<!-- The author name that you want to appear in the list. -->
|
||||
<Author>Casimir</Author>
|
||||
<!-- The author name that you want to appear in the list. -->
|
||||
<Author>Casimir</Author>
|
||||
|
||||
<!-- Optional tag that adds a tooltip to the plugin in-game. -->
|
||||
<Tooltip>Allows transferring between Nexus enabled servers seamlessly</Tooltip>
|
||||
<!-- Optional tag that adds a tooltip to the plugin in-game. -->
|
||||
<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. -->
|
||||
<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>
|
||||
<!-- 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>
|
||||
|
||||
<!-- The commit id. You can find this in the commits list: https://github.com/austinvaness/ToolSwitcherPlugin/commits/main -->
|
||||
<Commit>7a5ff795fba108309810a4cde7f414c1ffb1ba73</Commit>
|
||||
<!-- The commit id. You can find this in the commits list: https://github.com/austinvaness/ToolSwitcherPlugin/commits/main -->
|
||||
<Commit>7a5ff795fba108309810a4cde7f414c1ffb1ba73</Commit>
|
||||
</PluginData>
|
@@ -70,7 +70,7 @@ Type.GetType("Sandbox.Game.Screens.Helpers.MyLoadingScreenText, Sandbox.Game");
|
||||
|
||||
/* Static MethodInfos */
|
||||
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)
|
||||
{
|
||||
|
||||
|
||||
MySessionConstructor = GetConstructor(MySessionType, new[] { typeof(MySyncLayer), typeof(bool) });
|
||||
MyMultiplayerClientBaseConstructor = GetConstructor(MyMultiplayerClientBase, new[] { typeof(MySyncLayer) });
|
||||
|
||||
@@ -92,12 +92,12 @@ Type.GetType("Sandbox.Game.Screens.Helpers.MyLoadingScreenText, Sandbox.Game");
|
||||
|
||||
/* Get Methods */
|
||||
LoadPlayerInternal = GetMethod(typeof(MyPlayerCollection), "LoadPlayerInternal");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//MethodInfo ConnectToServer = GetMethod(typeof(MyGameService), "ConnectToServer", BindingFlags.Static | BindingFlags.Public);
|
||||
|
||||
|
||||
|
||||
|
||||
base.Patch(patcher);
|
||||
}
|
||||
|
||||
|
7
global.json
Normal file
7
global.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "9.0.0",
|
||||
"rollForward": "latestFeature",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user