fixes for nexus v3
This commit is contained in:
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
|
@@ -1,77 +1,67 @@
|
||||
using ProtoBuf;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.ModAPI;
|
||||
using SeamlessClientPlugin.SeamlessTransfer;
|
||||
using SeamlessClientPlugin.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SeamlessClientPlugin.Messages
|
||||
namespace SeamlessClientPlugin.Messages;
|
||||
|
||||
public enum ClientMessageType
|
||||
{
|
||||
public enum ClientMessageType
|
||||
{
|
||||
FirstJoin,
|
||||
TransferServer,
|
||||
OnlinePlayers,
|
||||
}
|
||||
OnlinePlayers
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class ClientMessage
|
||||
{
|
||||
[ProtoMember(1)] public ClientMessageType MessageType;
|
||||
|
||||
[ProtoContract]
|
||||
public class ClientMessage
|
||||
[ProtoMember(2)] public byte[] MessageData;
|
||||
|
||||
[ProtoMember(3)] public long IdentityId;
|
||||
|
||||
[ProtoMember(4)] public ulong SteamId;
|
||||
|
||||
[ProtoMember(5)] public string PluginVersion = "0";
|
||||
|
||||
[ProtoMember(6)] public string NexusVersion;
|
||||
|
||||
public ClientMessage(ClientMessageType type)
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public ClientMessageType MessageType;
|
||||
[ProtoMember(2)]
|
||||
public byte[] MessageData;
|
||||
[ProtoMember(3)]
|
||||
public long IdentityID;
|
||||
[ProtoMember(4)]
|
||||
public ulong SteamID;
|
||||
[ProtoMember(5)]
|
||||
public string PluginVersion = "0";
|
||||
MessageType = type;
|
||||
|
||||
public ClientMessage(ClientMessageType Type)
|
||||
{
|
||||
MessageType = Type;
|
||||
|
||||
if (MyAPIGateway.Multiplayer != null && !MyAPIGateway.Multiplayer.IsServer)
|
||||
{
|
||||
if (MyAPIGateway.Session.LocalHumanPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IdentityID = MySession.Static?.LocalHumanPlayer?.Identity?.IdentityId ?? 0;
|
||||
SteamID = MySession.Static?.LocalHumanPlayer?.Id.SteamId ?? 0;
|
||||
IdentityId = MySession.Static?.LocalHumanPlayer?.Identity?.IdentityId ?? 0;
|
||||
SteamId = MyGameService.UserId;
|
||||
PluginVersion = SeamlessClient.Version;
|
||||
}
|
||||
|
||||
public ClientMessage()
|
||||
{
|
||||
}
|
||||
|
||||
public ClientMessage() { }
|
||||
|
||||
public void SerializeData<T>(T Data)
|
||||
public void SerializeData<T>(T data)
|
||||
{
|
||||
MessageData = Utility.Serialize(Data);
|
||||
MessageData = Utility.Serialize(data);
|
||||
}
|
||||
|
||||
|
||||
public Transfer GetTransferData()
|
||||
{
|
||||
if (MessageData == null)
|
||||
return default(Transfer);
|
||||
return null;
|
||||
|
||||
return Utility.Deserialize<Transfer>(MessageData);
|
||||
|
||||
}
|
||||
|
||||
public OnlinePlayersMessage GetOnlinePlayers()
|
||||
{
|
||||
if (MessageData == null)
|
||||
return default(OnlinePlayersMessage);
|
||||
return null;
|
||||
|
||||
|
||||
OnlinePlayersMessage msg = Utility.Deserialize<OnlinePlayersMessage>(MessageData);
|
||||
var msg = Utility.Deserialize<OnlinePlayersMessage>(MessageData);
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,73 +1,48 @@
|
||||
using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SeamlessClientPlugin.Messages
|
||||
namespace SeamlessClientPlugin.Messages;
|
||||
|
||||
[ProtoContract]
|
||||
public class OnlinePlayersMessage
|
||||
{
|
||||
[ProtoMember(12)] public int CurrentServerId;
|
||||
|
||||
[ProtoContract]
|
||||
public class OnlinePlayersMessage
|
||||
{
|
||||
[ProtoMember(10)]
|
||||
public List<OnlineServer> OnlineServers = new List<OnlineServer>();
|
||||
|
||||
[ProtoMember(12)]
|
||||
public int currentServerID;
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class OnlineServer
|
||||
{
|
||||
|
||||
[ProtoMember(2)]
|
||||
public List<OnlinePlayer> Players = new List<OnlinePlayer>();
|
||||
|
||||
[ProtoMember(3)]
|
||||
public bool ServerRunning = false;
|
||||
|
||||
[ProtoMember(10)]
|
||||
public int ServerID;
|
||||
|
||||
[ProtoMember(11)]
|
||||
public string ServerName;
|
||||
|
||||
public OnlineServer() { }
|
||||
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class OnlinePlayer
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public string PlayerName;
|
||||
|
||||
[ProtoMember(2)]
|
||||
public ulong SteamID;
|
||||
|
||||
[ProtoMember(3)]
|
||||
public long IdentityID;
|
||||
|
||||
[ProtoMember(4)]
|
||||
public int OnServer;
|
||||
|
||||
public OnlinePlayer(string PlayerName, ulong SteamID, long IdentityID, int OnServer)
|
||||
{
|
||||
this.PlayerName = PlayerName;
|
||||
this.SteamID = SteamID;
|
||||
this.IdentityID = IdentityID;
|
||||
this.OnServer = OnServer;
|
||||
}
|
||||
|
||||
|
||||
public OnlinePlayer() { }
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[ProtoMember(10)] public List<OnlineServer> OnlineServers = [];
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class OnlineServer
|
||||
{
|
||||
[ProtoMember(2)] public List<OnlinePlayer> Players = [];
|
||||
|
||||
[ProtoMember(10)] public int ServerId;
|
||||
|
||||
[ProtoMember(11)] public string ServerName;
|
||||
|
||||
[ProtoMember(3)] public bool ServerRunning = false;
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class OnlinePlayer
|
||||
{
|
||||
[ProtoMember(3)] public long IdentityId;
|
||||
|
||||
[ProtoMember(4)] public int OnServer;
|
||||
|
||||
[ProtoMember(1)] public string PlayerName;
|
||||
|
||||
[ProtoMember(2)] public ulong SteamId;
|
||||
|
||||
public OnlinePlayer(string playerName, ulong steamId, long identityId, int onServer)
|
||||
{
|
||||
this.PlayerName = playerName;
|
||||
this.SteamId = steamId;
|
||||
this.IdentityId = identityId;
|
||||
this.OnServer = onServer;
|
||||
}
|
||||
|
||||
|
||||
public OnlinePlayer()
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,63 +1,33 @@
|
||||
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 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.Messages
|
||||
namespace SeamlessClientPlugin.Messages;
|
||||
|
||||
[ProtoContract]
|
||||
public class Transfer
|
||||
{
|
||||
[ProtoMember(2)] public string IpAdress;
|
||||
|
||||
[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(9)]
|
||||
public MyObjectBuilder_Toolbar PlayerToolbar;
|
||||
[ProtoMember(7)] public string PlayerName;
|
||||
|
||||
[ProtoMember(10)]
|
||||
public string ServerName;
|
||||
[ProtoMember(9)] public MyObjectBuilder_Toolbar PlayerToolbar;
|
||||
|
||||
public Transfer(ulong ServerID, string IPAdress)
|
||||
[ProtoMember(10)] public string ServerName;
|
||||
|
||||
[ProtoMember(1)] public ulong TargetServerId;
|
||||
|
||||
[ProtoMember(6)] public WorldRequest WorldRequest;
|
||||
|
||||
public Transfer(ulong serverId, string ipAdress)
|
||||
{
|
||||
/* This is only called serverside
|
||||
*/
|
||||
|
||||
this.IPAdress = IPAdress;
|
||||
TargetServerID = ServerID;
|
||||
this.IpAdress = ipAdress;
|
||||
TargetServerId = serverId;
|
||||
}
|
||||
|
||||
public Transfer() { }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public Transfer()
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,72 +1,55 @@
|
||||
using NLog;
|
||||
using System.Reflection;
|
||||
using NLog;
|
||||
using ProtoBuf;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VRage.Game;
|
||||
using VRage.ObjectBuilders;
|
||||
using VRage.ObjectBuilders.Private;
|
||||
|
||||
namespace SeamlessClientPlugin.Messages
|
||||
namespace SeamlessClientPlugin.Messages;
|
||||
|
||||
[ProtoContract]
|
||||
public class WorldRequest
|
||||
{
|
||||
[ProtoContract]
|
||||
public class WorldRequest
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
[ProtoMember(1)]
|
||||
public ulong PlayerID;
|
||||
[ProtoMember(2)]
|
||||
public long IdentityID;
|
||||
[ProtoMember(3)]
|
||||
public string PlayerName;
|
||||
[ProtoMember(4)]
|
||||
public byte[] WorldData;
|
||||
[ProtoMember(5)] public MyObjectBuilder_Gps GpsCollection;
|
||||
|
||||
[ProtoMember(5)]
|
||||
public MyObjectBuilder_Gps gpsCollection;
|
||||
[ProtoMember(2)] public long IdentityId;
|
||||
|
||||
public WorldRequest(ulong PlayerID,long PlayerIdentity, string Name)
|
||||
[ProtoMember(1)] public ulong PlayerId;
|
||||
|
||||
[ProtoMember(3)] public string PlayerName;
|
||||
|
||||
[ProtoMember(4)] public byte[] WorldData;
|
||||
|
||||
public WorldRequest(ulong playerId, long playerIdentity, string name)
|
||||
{
|
||||
this.PlayerID = PlayerID;
|
||||
this.PlayerName = Name;
|
||||
this.IdentityID = PlayerIdentity;
|
||||
this.PlayerId = playerId;
|
||||
PlayerName = name;
|
||||
IdentityId = playerIdentity;
|
||||
}
|
||||
|
||||
public WorldRequest() { }
|
||||
public WorldRequest()
|
||||
{
|
||||
}
|
||||
|
||||
public void SerializeWorldData(MyObjectBuilder_World WorldData)
|
||||
public void SerializeWorldData(MyObjectBuilder_World worldData)
|
||||
{
|
||||
MethodInfo CleanupData = typeof(MyMultiplayerServerBase).GetMethod("CleanUpData", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[3]
|
||||
{
|
||||
typeof(MyObjectBuilder_World),
|
||||
typeof(ulong),
|
||||
typeof(long),
|
||||
}, null);
|
||||
object[] Data = new object[] { WorldData, PlayerID, IdentityID };
|
||||
CleanupData.Invoke(null, Data);
|
||||
WorldData = (MyObjectBuilder_World)Data[0];
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
MyObjectBuilderSerializer.SerializeXML(memoryStream, WorldData, MyObjectBuilderSerializer.XmlCompression.Gzip);
|
||||
this.WorldData = memoryStream.ToArray();
|
||||
MyMultiplayerServerBase.CleanUpData(worldData, PlayerId, IdentityId);
|
||||
using var memoryStream = new MemoryStream();
|
||||
MyObjectBuilderSerializerKeen.SerializeXML(memoryStream, worldData,
|
||||
MyObjectBuilderSerializerKeen.XmlCompression.Gzip);
|
||||
WorldData = memoryStream.ToArray();
|
||||
Log.Warn("Successfully Converted World");
|
||||
}
|
||||
}
|
||||
|
||||
public MyObjectBuilder_World DeserializeWorldData()
|
||||
{
|
||||
MyObjectBuilderSerializer.DeserializeGZippedXML<MyObjectBuilder_World>(new MemoryStream(WorldData), out var objectBuilder);
|
||||
objectBuilder.Checkpoint.Gps.Dictionary.Add(IdentityID, gpsCollection);
|
||||
|
||||
MyObjectBuilderSerializerKeen.DeserializeGZippedXML<MyObjectBuilder_World>(new MemoryStream(WorldData),
|
||||
out var objectBuilder);
|
||||
objectBuilder.Checkpoint.Gps.Dictionary.Add(IdentityId, GpsCollection);
|
||||
|
||||
|
||||
return objectBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SeamlessClientPlugin")]
|
||||
[assembly: AssemblyDescription("A seamless client plugin for Nexus compatible servers")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Casimir")]
|
||||
[assembly: AssemblyProduct("SeamlessClientPlugin")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("102a3d80-b588-43ba-b686-000fa8ff1a0c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.4.02.0")]
|
||||
[assembly: AssemblyFileVersion("1.4.02.0")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
30
README.md
30
README.md
@@ -1,21 +1,33 @@
|
||||
# SeamlessClientPlugin
|
||||
The seamless client plugin lets you switch between SE servers without a loading screen. This currently *only* works with Nexus compatible servers as all data is shared and synced between them.
|
||||
|
||||
The main load time is the time it takes for your client to ping the destination server, and the client to recieve the go-ahead. Any extra time is contributed to entities syncing to the client similar to if you were respawning at the grid. (sometimes it takes forever). I will be looking into pre-loading synced entities to the client in the near future, but atm this was the easier solution.
|
||||
|
||||
This has taken countless hours of testing and debugging to get right. Not to mention the countless hours implementing the server plugin Nexus. If you enjoy this kind of work, please donate [here](https://se-nexus.net/en/Contribute) to help keep this project alive.
|
||||
The seamless client plugin lets you switch between SE servers without a loading screen. This currently *only* works with
|
||||
Nexus compatible servers as all data is shared and synced between them.
|
||||
|
||||
The main load time is the time it takes for your client to ping the destination server, and the client to recieve the
|
||||
go-ahead. Any extra time is contributed to entities syncing to the client similar to if you were respawning at the
|
||||
grid. (sometimes it takes forever). I will be looking into pre-loading synced entities to the client in the near future,
|
||||
but atm this was the easier solution.
|
||||
|
||||
This has taken countless hours of testing and debugging to get right. Not to mention the countless hours implementing
|
||||
the server plugin Nexus. If you enjoy this kind of work, please donate [here](https://se-nexus.net/en/Contribute) to
|
||||
help keep this project alive.
|
||||
|
||||
## How it works
|
||||
With Nexus servers, all data is shared between servers. (Factions, Identities, Players, Econ etc) This is a huge benefit as we dont have to go in and reload all identities and factions etc. The next thing that happens is that the server tells the client to switch to the proper server. It then goes in and just re-applies the MyMultiplayerClient to the target server. Of course there is a few other things that must happen to fix any errors or bugs, but that is the main rundown.
|
||||
|
||||
|
||||
With Nexus servers, all data is shared between servers. (Factions, Identities, Players, Econ etc) This is a huge benefit
|
||||
as we dont have to go in and reload all identities and factions etc. The next thing that happens is that the server
|
||||
tells the client to switch to the proper server. It then goes in and just re-applies the MyMultiplayerClient to the
|
||||
target server. Of course there is a few other things that must happen to fix any errors or bugs, but that is the main
|
||||
rundown.
|
||||
|
||||
## 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 plguin loader, and check this plugins 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 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.
|
||||
|
@@ -1,40 +1,23 @@
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Game;
|
||||
using Sandbox.Game.Entities;
|
||||
using Sandbox.Game.Gui;
|
||||
using Sandbox.Game.Multiplayer;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CringePlugins.Ui;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.Graphics.GUI;
|
||||
using Sandbox.ModAPI;
|
||||
using SeamlessClientPlugin.Messages;
|
||||
using SeamlessClientPlugin.SeamlessTransfer;
|
||||
using SeamlessClientPlugin.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows.Forms;
|
||||
using VRage.Game.ModAPI;
|
||||
using VRage.Input;
|
||||
using VRage.Plugins;
|
||||
using VRage.Utils;
|
||||
using VRageMath;
|
||||
using VRageRender;
|
||||
|
||||
[assembly: IgnoresAccessChecksTo("Sandbox.Game")]
|
||||
[assembly: IgnoresAccessChecksTo("Sandbox.Graphics")]
|
||||
|
||||
namespace SeamlessClientPlugin;
|
||||
|
||||
namespace SeamlessClientPlugin
|
||||
//SendAllMembersDataToClient
|
||||
|
||||
public class SeamlessClient : IPlugin
|
||||
{
|
||||
|
||||
//SendAllMembersDataToClient
|
||||
|
||||
public class SeamlessClient : IPlugin
|
||||
{
|
||||
public const ushort SeamlessClientNetId = 2936;
|
||||
/* First Step. How does a player join a game?
|
||||
* First JoinGameInternal is called with the ServersLobbyID.
|
||||
* In this method, MySessionLoader.UnloadAndExitToMenu() is called. Ultimatley we want to prevent this as we dont want to unload the entire game. Just the basic neccessities.
|
||||
@@ -109,29 +92,26 @@ namespace SeamlessClientPlugin
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public static string Version = "1.4.01";
|
||||
// pretend to be the latest one
|
||||
public static string Version = "3.0.0.10";
|
||||
public static bool Debug = true;
|
||||
private static bool Initilized = false;
|
||||
|
||||
|
||||
|
||||
public const ushort SeamlessClientNetID = 2936;
|
||||
private static bool _initilized;
|
||||
|
||||
public static bool IsSwitching = false;
|
||||
public static bool RanJoin = false;
|
||||
|
||||
|
||||
|
||||
public void Init(object gameInstance)
|
||||
{
|
||||
TryShow($"Running Seamless Client Plugin v[{Version}]");
|
||||
MySession.LoadingStep += LoadingProgressStep;
|
||||
}
|
||||
|
||||
TryShow("Running Seamless Client Plugin v[" + Version + "]");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static void LoadingProgressStep(LoadingProgress step)
|
||||
{
|
||||
// i copied it from the new one no guarantee it works properly
|
||||
if (step >= LoadingProgress.PROGRESS_STEP8)
|
||||
SendFirstJoin();
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +121,7 @@ namespace SeamlessClientPlugin
|
||||
return;
|
||||
|
||||
|
||||
if (!Initilized)
|
||||
if (!_initilized)
|
||||
{
|
||||
Patches.GetPatches();
|
||||
OnlinePlayers.Patch();
|
||||
@@ -151,19 +131,22 @@ namespace SeamlessClientPlugin
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeInitilizations();
|
||||
}
|
||||
|
||||
|
||||
public static void RunInitilizations()
|
||||
{
|
||||
|
||||
|
||||
MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(SeamlessClientNetID, MessageHandler);
|
||||
Initilized = true;
|
||||
MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(SeamlessClientNetId, MessageHandler);
|
||||
_initilized = true;
|
||||
}
|
||||
|
||||
public static void DisposeInitilizations()
|
||||
{
|
||||
MyAPIGateway.Multiplayer?.UnregisterSecureMessageHandler(SeamlessClientNetID, MessageHandler);
|
||||
Initilized = false;
|
||||
|
||||
MyAPIGateway.Multiplayer?.UnregisterSecureMessageHandler(SeamlessClientNetId, MessageHandler);
|
||||
_initilized = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -171,26 +154,32 @@ namespace SeamlessClientPlugin
|
||||
{
|
||||
try
|
||||
{
|
||||
ClientMessage Recieved = Utilities.Utility.Deserialize<ClientMessage>(obj2);
|
||||
var recieved = Utility.Deserialize<ClientMessage>(obj2);
|
||||
|
||||
if(Recieved.MessageType == ClientMessageType.FirstJoin)
|
||||
switch (recieved.MessageType)
|
||||
{
|
||||
//Server sent a first join message! Send a reply back so the server knows what version we are on
|
||||
ClientMessage PingServer = new ClientMessage(ClientMessageType.FirstJoin);
|
||||
MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetID, Utilities.Utility.Serialize(PingServer));
|
||||
// was removed in newer versions, but we leave it here for backwards compatability
|
||||
case ClientMessageType.FirstJoin:
|
||||
{
|
||||
SendFirstJoin();
|
||||
break;
|
||||
}
|
||||
else if (Recieved.MessageType == ClientMessageType.TransferServer)
|
||||
case ClientMessageType.TransferServer:
|
||||
{
|
||||
//Server sent a transfer message! Begin transfer via seamless
|
||||
Transfer TransferMessage = Recieved.GetTransferData();
|
||||
ServerPing.StartServerPing(TransferMessage);
|
||||
}else if(Recieved.MessageType == ClientMessageType.OnlinePlayers)
|
||||
var transferMessage = recieved.GetTransferData();
|
||||
ServerPing.StartServerPing(transferMessage);
|
||||
break;
|
||||
}
|
||||
case ClientMessageType.OnlinePlayers:
|
||||
{
|
||||
var p = Recieved.GetOnlinePlayers();
|
||||
var p = recieved.GetOnlinePlayers();
|
||||
OnlinePlayers.AllServers = p.OnlineServers;
|
||||
OnlinePlayers.currentServer = p.currentServerID;
|
||||
OnlinePlayers.CurrentServer = p.CurrentServerId;
|
||||
|
||||
//TryShow("Recieved Players! "+OnlinePlayers.AllServers.Count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -199,20 +188,16 @@ namespace SeamlessClientPlugin
|
||||
}
|
||||
}
|
||||
|
||||
private static void SendFirstJoin()
|
||||
{
|
||||
var pingServer = new ClientMessage(ClientMessageType.FirstJoin);
|
||||
MyAPIGateway.Multiplayer?.SendMessageToServer(SeamlessClientNetId, Utility.Serialize(pingServer));
|
||||
}
|
||||
|
||||
|
||||
public static void TryShow(string message)
|
||||
{
|
||||
if (MySession.Static?.LocalHumanPlayer != null && Debug)
|
||||
MyAPIGateway.Utilities?.ShowMessage("NetworkClient", message);
|
||||
|
||||
NotificationsComponent.SpawnNotification(5f, message);
|
||||
MyLog.Default?.WriteLineAndConsole($"SeamlessClient: {message}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeInitilizations();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,162 +1,49 @@
|
||||
<?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')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{102A3D80-B588-43BA-B686-000FA8FF1A0C}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SeamlessClientPlugin</RootNamespace>
|
||||
<AssemblyName>SeamlessClientPlugin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>F:\SteamLibrary\steamapps\common\SpaceEngineers\Plugins\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</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>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<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>
|
||||
<Publicize Include="Sandbox.Game;Sandbox.Graphics" IncludeVirtualMembers="false" IncludeCompilerGeneratedMembers="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CringePlugins" Version="*" ExcludeAssets="runtime; native"/>
|
||||
<PackageReference Include="Krafs.Publicizer" Version="2.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<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>
|
||||
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
|
||||
<AppdataPath>$([System.Environment]::GetFolderPath(SpecialFolder.ApplicationData))</AppdataPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony, Version=2.2.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\Nexus\packages\Lib.Harmony.2.2.1\lib\net48\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\NLog.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ProtoBuf.Net">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\ProtoBuf.Net.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ProtoBuf.Net.Core">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\ProtoBuf.Net.Core.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Common">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\Sandbox.Common.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Game">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\Sandbox.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Graphics">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\Sandbox.Graphics.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SpaceEngineers.Game">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\SpaceEngineers.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SpaceEngineers.ObjectBuilders.XmlSerializers">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\SpaceEngineers.ObjectBuilders.XmlSerializers.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Core">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\Nexus\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\Nexus\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Runtime.Serialization.Json" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\VRage.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Game">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\VRage.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Library">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\VRage.Library.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Math">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\VRage.Math.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Render">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\VRage.Render.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Steam">
|
||||
<HintPath>..\..\..\Desktop\TorchServers\torch-server1\DedicatedServer64\VRage.Steam.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<OutputFiles Include="$(OutputPath)\*"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Messages\ClientMessages.cs" />
|
||||
<Compile Include="Messages\OnlinePlayersMessage.cs" />
|
||||
<Compile Include="Messages\WorldRequest.cs" />
|
||||
<Compile Include="SeamlessClient.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SeamlessTransfer\ModLoader.cs" />
|
||||
<Compile Include="SeamlessTransfer\MyScriptManagerLoader.cs" />
|
||||
<Compile Include="SeamlessTransfer\PingServer.cs" />
|
||||
<Compile Include="Messages\Transfer.cs" />
|
||||
<Compile Include="Utilities\OnlinePlayers.cs" />
|
||||
<Compile Include="Utilities\Patches.cs" />
|
||||
<Compile Include="SeamlessTransfer\SwitchServers.cs" />
|
||||
<Compile Include="Utilities\Utility.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Copy SourceFiles="@(OutputFiles)" DestinationFolder="$(AppdataPath)\CringeLauncher\plugins\$(ProjectName)" OverwriteReadOnlyFiles="true"/>
|
||||
</Target>
|
||||
|
||||
|
||||
</Project>
|
@@ -1,21 +1,13 @@
|
||||
using Sandbox.Definitions;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.ModAPI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using VRage.Game;
|
||||
using VRage.Game.GUI;
|
||||
using VRage.GameServices;
|
||||
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer;
|
||||
|
||||
public static class ModLoader
|
||||
{
|
||||
public static class ModLoader
|
||||
{
|
||||
/* Mod loader should download and load missing mods for target server, and unload ones that arent needed
|
||||
*
|
||||
* Sandbox.Game.World.MyScriptManager.LoadData() is where modded scripts get loaded and added
|
||||
@@ -32,107 +24,88 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
|
||||
//Mods that are currently loaded in this instance.
|
||||
private static List<MyObjectBuilder_Checkpoint.ModItem> CurrentLoadedMods = new List<MyObjectBuilder_Checkpoint.ModItem>();
|
||||
|
||||
|
||||
private static List<MyObjectBuilder_Checkpoint.ModItem> _currentLoadedMods = [];
|
||||
|
||||
|
||||
//Mods that we need to Load
|
||||
private static List<MyObjectBuilder_Checkpoint.ModItem> TargetLoadMods = new List<MyObjectBuilder_Checkpoint.ModItem>();
|
||||
private static readonly List<MyObjectBuilder_Checkpoint.ModItem> TargetLoadMods = [];
|
||||
|
||||
//Mods that we need to UnLoad
|
||||
private static List<MyObjectBuilder_Checkpoint.ModItem> TargetUnLoadMods = new List<MyObjectBuilder_Checkpoint.ModItem>();
|
||||
private static readonly List<MyObjectBuilder_Checkpoint.ModItem> TargetUnLoadMods = [];
|
||||
|
||||
|
||||
private static bool FinishedDownloadingMods = false;
|
||||
private static bool DownloadSuccess = false;
|
||||
private static bool _finishedDownloadingMods;
|
||||
private static bool _downloadSuccess;
|
||||
|
||||
private static DateTime DownloadTimeout;
|
||||
|
||||
private static MethodInfo PrepareBaseSession = typeof(MySession).GetMethod("PreloadModels", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
private static FieldInfo ScriptManager = typeof(MySession).GetField("ScriptManager", BindingFlags.Instance | BindingFlags.Public);
|
||||
private static DateTime _downloadTimeout;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static void DownloadNewMods(List<MyObjectBuilder_Checkpoint.ModItem> Target)
|
||||
public static void DownloadNewMods(List<MyObjectBuilder_Checkpoint.ModItem> target)
|
||||
{
|
||||
CurrentLoadedMods = MySession.Static.Mods;
|
||||
|
||||
_currentLoadedMods = MySession.Static.Mods;
|
||||
|
||||
|
||||
//Loop through our current mods
|
||||
foreach(var mod in CurrentLoadedMods)
|
||||
{
|
||||
if (!Target.Contains(mod))
|
||||
foreach (var mod in _currentLoadedMods)
|
||||
if (!target.Contains(mod))
|
||||
TargetUnLoadMods.Add(mod);
|
||||
}
|
||||
|
||||
|
||||
//Loop through our TargetMods
|
||||
foreach(var mod in Target)
|
||||
{
|
||||
if (!CurrentLoadedMods.Contains(mod))
|
||||
foreach (var mod in target)
|
||||
if (!_currentLoadedMods.Contains(mod))
|
||||
TargetLoadMods.Add(mod);
|
||||
}
|
||||
|
||||
|
||||
DownloadTimeout = DateTime.Now + TimeSpan.FromMinutes(5);
|
||||
_downloadTimeout = DateTime.Now + TimeSpan.FromMinutes(5);
|
||||
SeamlessClient.TryShow("Downloading New Mods");
|
||||
MyWorkshop.DownloadModsAsync(TargetLoadMods, ModDownloadingFinished);
|
||||
|
||||
}
|
||||
|
||||
private static void ModDownloadingFinished(bool Success)
|
||||
private static void ModDownloadingFinished(MyGameServiceCallResult result)
|
||||
{
|
||||
if (Success)
|
||||
if (result == MyGameServiceCallResult.OK)
|
||||
{
|
||||
SeamlessClient.TryShow("Mod Downloading Finished!");
|
||||
FinishedDownloadingMods = true;
|
||||
DownloadSuccess = true;
|
||||
_finishedDownloadingMods = true;
|
||||
_downloadSuccess = true;
|
||||
//May need to wait seamless loading if mods have yet to finish downloading
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadSuccess = false;
|
||||
FinishedDownloadingMods = true;
|
||||
_downloadSuccess = false;
|
||||
_finishedDownloadingMods = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void ReadyModSwitch(MyObjectBuilder_Checkpoint checkpoint, MyObjectBuilder_Sector sector)
|
||||
{
|
||||
|
||||
while (!FinishedDownloadingMods)
|
||||
while (!_finishedDownloadingMods)
|
||||
{
|
||||
|
||||
//Break out of loop
|
||||
if (DownloadTimeout < DateTime.Now)
|
||||
if (_downloadTimeout < DateTime.Now)
|
||||
break;
|
||||
|
||||
|
||||
Thread.Sleep(20);
|
||||
}
|
||||
|
||||
FinishedDownloadingMods = false;
|
||||
_finishedDownloadingMods = false;
|
||||
|
||||
//Skip mod switch
|
||||
if (!DownloadSuccess)
|
||||
if (!_downloadSuccess)
|
||||
return;
|
||||
|
||||
|
||||
|
||||
//Create new script manager?
|
||||
ScriptManager.SetValue(MySession.Static, new MyScriptManager());
|
||||
MySession.Static.ScriptManager = new();
|
||||
|
||||
|
||||
MyGuiTextures.Static.Unload();
|
||||
MySession.Static.ScriptManager.Init(checkpoint.ScriptManagerData);
|
||||
//MyDefinitionManager.Static.LoadData(TargetServerMods);
|
||||
PrepareBaseSession.Invoke(null, new object[] { sector });
|
||||
MySession.PreloadModels(sector);
|
||||
|
||||
|
||||
MyLocalCache.PreloadLocalInventoryConfig();
|
||||
@@ -142,32 +115,22 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
|
||||
// PrepareBaseSession.Invoke(MySession.Static, new object[] { TargetServerMods, null });
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void UnloadOldScripts()
|
||||
{
|
||||
// MySandboxGame.Log.WriteLine(string.Format("Script loaded: {0}", value.FullName));
|
||||
int amount = 0;
|
||||
var amount = 0;
|
||||
foreach (var mod in TargetUnLoadMods)
|
||||
{
|
||||
var val = MySession.Static.ScriptManager.Scripts.FirstOrDefault(x => x.Value.FullName.Contains(mod.PublishedFileId.ToString()));
|
||||
var val = MySession.Static.ScriptManager.Scripts.FirstOrDefault(x =>
|
||||
x.Value.FullName.Contains(mod.PublishedFileId.ToString()));
|
||||
MySession.Static.ScriptManager.Scripts.Remove(val.Key);
|
||||
|
||||
amount++;
|
||||
}
|
||||
|
||||
SeamlessClient.TryShow($"Removed {amount} old scripts!");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -1,15 +1,7 @@
|
||||
using Sandbox;
|
||||
using Sandbox.Game.World;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer;
|
||||
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
public class MyScriptManagerLoader
|
||||
{
|
||||
public class MyScriptManagerLoader
|
||||
{
|
||||
/*
|
||||
public void LoadData(MyScriptManager __instance)
|
||||
{
|
||||
@@ -78,6 +70,4 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
MySandboxGame.Log.WriteLine("MyScriptManager.LoadData() - END");
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
@@ -1,51 +1,41 @@
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Game.Multiplayer;
|
||||
using SeamlessClientPlugin.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SeamlessClientPlugin.Messages;
|
||||
using VRage.GameServices;
|
||||
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer;
|
||||
|
||||
public class ServerPing
|
||||
{
|
||||
public class ServerPing
|
||||
{
|
||||
private static Transfer _transfer;
|
||||
|
||||
private static WorldRequest Request { get { return Transfer.WorldRequest; } }
|
||||
private static Transfer Transfer;
|
||||
private static WorldRequest Request => _transfer.WorldRequest;
|
||||
|
||||
|
||||
public static void StartServerPing(Transfer ClientTransfer)
|
||||
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
|
||||
Transfer = ClientTransfer;
|
||||
_transfer = clientTransfer;
|
||||
|
||||
|
||||
if (Transfer.TargetServerID == 0)
|
||||
if (_transfer.TargetServerId == 0)
|
||||
{
|
||||
SeamlessClient.TryShow("This is not a valid server!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MyGameServerItem E = new MyGameServerItem();
|
||||
E.ConnectionString = Transfer.IPAdress;
|
||||
E.SteamID = Transfer.TargetServerID;
|
||||
E.Name = Transfer.ServerName;
|
||||
var e = new MyGameServerItem();
|
||||
e.ConnectionString = _transfer.IpAdress;
|
||||
e.SteamID = _transfer.TargetServerId;
|
||||
e.Name = _transfer.ServerName;
|
||||
|
||||
|
||||
|
||||
SeamlessClient.TryShow("Beginning Redirect to server: " + Transfer.TargetServerID);
|
||||
SeamlessClient.TryShow($"Beginning Redirect to server: {_transfer.TargetServerId}");
|
||||
|
||||
|
||||
var world = Request.DeserializeWorldData();
|
||||
|
||||
|
||||
SwitchServers Switcher = new SwitchServers(E, world);
|
||||
Switcher.BeginSwitch();
|
||||
}
|
||||
var switcher = new SwitchServers(e, world);
|
||||
switcher.BeginSwitch();
|
||||
}
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
using Sandbox;
|
||||
using Sandbox.Definitions;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Game;
|
||||
@@ -10,51 +9,36 @@ using Sandbox.Game.Multiplayer;
|
||||
using Sandbox.Game.SessionComponents;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.Game.World.Generator;
|
||||
using Sandbox.Graphics.GUI;
|
||||
using Sandbox.ModAPI;
|
||||
using SeamlessClientPlugin.Utilities;
|
||||
using SpaceEngineers.Game.GUI;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VRage;
|
||||
using VRage.Collections;
|
||||
using VRage.Game;
|
||||
using VRage.Game.Components;
|
||||
using VRage.Game.ModAPI;
|
||||
using VRage.GameServices;
|
||||
using VRage.Steam;
|
||||
using VRage.Network;
|
||||
using VRage.Utils;
|
||||
using VRageMath;
|
||||
using VRageRender;
|
||||
using VRageRender.Messages;
|
||||
using Game = Sandbox.Engine.Platform.Game;
|
||||
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer;
|
||||
|
||||
public class SwitchServers
|
||||
{
|
||||
public class SwitchServers
|
||||
public SwitchServers(MyGameServerItem targetServer, MyObjectBuilder_World targetWorld)
|
||||
{
|
||||
this.TargetServer = targetServer;
|
||||
this.TargetWorld = targetWorld;
|
||||
|
||||
//ModLoader.DownloadNewMods(TargetWorld.Checkpoint.Mods);
|
||||
}
|
||||
|
||||
public MyGameServerItem TargetServer { get; }
|
||||
public MyObjectBuilder_World TargetWorld { get; }
|
||||
|
||||
private string OldArmorSkin { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public SwitchServers(MyGameServerItem TargetServer, MyObjectBuilder_World TargetWorld)
|
||||
{
|
||||
this.TargetServer = TargetServer;
|
||||
this.TargetWorld = TargetWorld;
|
||||
|
||||
//ModLoader.DownloadNewMods(TargetWorld.Checkpoint.Mods);
|
||||
}
|
||||
|
||||
|
||||
public void BeginSwitch()
|
||||
{
|
||||
OldArmorSkin = MySession.Static.LocalHumanPlayer.BuildArmorSkin;
|
||||
@@ -66,8 +50,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
UnloadCurrentServer();
|
||||
SetNewMultiplayerClient();
|
||||
SeamlessClient.IsSwitching = false;
|
||||
|
||||
|
||||
}, "SeamlessClient");
|
||||
}
|
||||
|
||||
@@ -77,35 +59,28 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
// Following is called when the multiplayer is set successfully to target server
|
||||
Patches.OnJoinEvent += OnJoinEvent;
|
||||
|
||||
|
||||
MySandboxGame.Static.SessionCompatHelper.FixSessionComponentObjectBuilders(TargetWorld.Checkpoint, TargetWorld.Sector);
|
||||
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 });
|
||||
var layerInstance = new MyTransportLayer(MyMultiplayer.GAME_EVENT_CHANNEL);
|
||||
var syncInstance = new MySyncLayer(layerInstance);
|
||||
var instance = new MyMultiplayerClient(TargetServer, syncInstance);
|
||||
|
||||
|
||||
MyMultiplayer.Static = Utility.CastToReflected(instance, Patches.ClientType);
|
||||
MyMultiplayer.Static = instance;
|
||||
MyMultiplayer.Static.ExperimentalMode = true;
|
||||
|
||||
|
||||
|
||||
// Set the new SyncLayer to the MySession.Static.SyncLayer
|
||||
Patches.MySessionLayer.SetValue(MySession.Static, MyMultiplayer.Static.SyncLayer);
|
||||
MySession.Static.SyncLayer = MyMultiplayer.Static.SyncLayer;
|
||||
|
||||
SeamlessClient.TryShow("Successfully set MyMultiplayer.Static");
|
||||
|
||||
|
||||
Sync.Clients.SetLocalSteamId(Sync.MyId, false, MyGameService.UserName);
|
||||
Sync.Players.RegisterEvents();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void OnJoinEvent(object sender, VRage.Network.JoinResultMsg e)
|
||||
private void OnJoinEvent(object sender, JoinResultMsg e)
|
||||
{
|
||||
ForceClientConnection();
|
||||
|
||||
@@ -114,10 +89,8 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ForceClientConnection()
|
||||
{
|
||||
|
||||
//Set World Settings
|
||||
SetWorldSettings();
|
||||
|
||||
@@ -125,13 +98,13 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
LoadConnectedClients();
|
||||
|
||||
|
||||
|
||||
MySector.InitEnvironmentSettings(TargetWorld.Sector.Environment);
|
||||
|
||||
|
||||
|
||||
string text = ((!string.IsNullOrEmpty(TargetWorld.Checkpoint.CustomSkybox)) ? TargetWorld.Checkpoint.CustomSkybox : MySector.EnvironmentDefinition.EnvironmentTexture);
|
||||
MyRenderProxy.PreloadTextures(new string[1] { text }, TextureType.CubeMap);
|
||||
var text = !string.IsNullOrEmpty(TargetWorld.Checkpoint.CustomSkybox)
|
||||
? TargetWorld.Checkpoint.CustomSkybox
|
||||
: MySector.EnvironmentDefinition.EnvironmentTexture;
|
||||
MyRenderProxy.PreloadTextures([text], TextureType.CubeMap);
|
||||
|
||||
MyModAPIHelper.Initialize();
|
||||
MySession.Static.LoadDataComponents();
|
||||
@@ -145,7 +118,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
// A.Invoke(MySession.Static, new object[] { TargetWorld.Checkpoint });
|
||||
|
||||
|
||||
|
||||
MyMultiplayer.Static.OnSessionReady();
|
||||
|
||||
|
||||
@@ -155,7 +127,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
|
||||
MyHud.Chat.RegisterChat(MyMultiplayer.Static);
|
||||
Patches.GPSRegisterChat.Invoke(MySession.Static.Gpss, new object[] { MyMultiplayer.Static });
|
||||
MySession.Static.Gpss.RegisterChat(MyMultiplayer.Static);
|
||||
|
||||
|
||||
// Allow the game to start proccessing incoming messages in the buffer
|
||||
@@ -164,14 +136,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
//Recreate all controls... Will fix weird gui/paint/crap
|
||||
MyGuiScreenHudSpace.Static.RecreateControls(true);
|
||||
//MySession.Static.LocalHumanPlayer.BuildArmorSkin = OldArmorSkin;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void LoadOnlinePlayers()
|
||||
{
|
||||
//Get This players ID
|
||||
@@ -182,10 +149,12 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
SeamlessClient.TryShow("SavingPlayerID is null! Creating Default!");
|
||||
savingPlayerId = new MyPlayer.PlayerId(Sync.MyId);
|
||||
}
|
||||
SeamlessClient.TryShow("Saving PlayerID: " + savingPlayerId.ToString());
|
||||
|
||||
SeamlessClient.TryShow($"Saving PlayerID: {savingPlayerId}");
|
||||
|
||||
Sync.Players.LoadConnectedPlayers(TargetWorld.Checkpoint, savingPlayerId);
|
||||
Sync.Players.LoadControlledEntities(TargetWorld.Checkpoint.ControlledEntities, TargetWorld.Checkpoint.ControlledObject, savingPlayerId);
|
||||
Sync.Players.LoadControlledEntities(TargetWorld.Checkpoint.ControlledEntities,
|
||||
TargetWorld.Checkpoint.ControlledObject, savingPlayerId);
|
||||
/*
|
||||
|
||||
|
||||
@@ -221,7 +190,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
private void SetWorldSettings()
|
||||
@@ -231,9 +199,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
//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();
|
||||
|
||||
MySession.Static.RemoteAdminSettings.Clear();
|
||||
|
||||
|
||||
// Set new world settings
|
||||
@@ -242,7 +208,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
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.CurrentPath =
|
||||
MyLocalCache.GetSessionSavesPath(MyUtils.StripInvalidChars(TargetWorld.Checkpoint.SessionName), false,
|
||||
false);
|
||||
MySession.Static.WorldBoundaries = TargetWorld.Checkpoint.WorldBoundaries;
|
||||
MySession.Static.InGameTime = MyObjectBuilder_Checkpoint.DEFAULT_DATE;
|
||||
MySession.Static.ElapsedGameTime = new TimeSpan(TargetWorld.Checkpoint.ElapsedGameTime);
|
||||
@@ -259,11 +227,11 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
{
|
||||
MySession.Static.Gpss = new MyGpsCollection();
|
||||
MySession.Static.Gpss.LoadGpss(TargetWorld.Checkpoint);
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
SeamlessClient.TryShow($"An error occured while loading GPS points! You will have an empty gps list! \n {ex.ToString()}");
|
||||
SeamlessClient.TryShow(
|
||||
$"An error occured while loading GPS points! You will have an empty gps list! \n {ex}");
|
||||
}
|
||||
|
||||
|
||||
@@ -275,25 +243,18 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
// 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))
|
||||
foreach (var item in TargetWorld.Checkpoint.AllPlayersData.Dictionary)
|
||||
{
|
||||
var clientId = item.Key.GetClientId();
|
||||
var 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;
|
||||
@@ -301,56 +262,33 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
}
|
||||
|
||||
|
||||
AdminSettingsList[clientId] = adminSettingsEnum;
|
||||
MySession.Static.RemoteAdminSettings[clientId] = adminSettingsEnum;
|
||||
if (!Sync.IsDedicated && clientId == Sync.MyId)
|
||||
{
|
||||
Patches.AdminSettings.SetValue(MySession.Static, adminSettingsEnum);
|
||||
MySession.Static.AdminSettings = 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;
|
||||
}
|
||||
var value2 = MySession.Static.PromotedUsers.GetValueOrDefault(clientId, 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()
|
||||
{
|
||||
|
||||
Patches.LoadMembersFromWorld.Invoke(MySession.Static, new object[] { TargetWorld, MyMultiplayer.Static });
|
||||
|
||||
MySession.Static.LoadMembersFromWorld(TargetWorld, MyMultiplayer.Static);
|
||||
|
||||
//Re-Initilize Virtual clients
|
||||
object VirtualClientsValue = Patches.VirtualClients.GetValue(MySession.Static);
|
||||
Patches.InitVirtualClients.Invoke(VirtualClientsValue, null);
|
||||
|
||||
MySession.Static.VirtualClients.Init();
|
||||
|
||||
//load online players
|
||||
LoadOnlinePlayers();
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
Sync.Players.RequestNewPlayer(Sync.MyId, 0, MyGameService.UserName, null, true, true);
|
||||
if (MySession.Static.ControlledEntity == null && Sync.IsServer && !Game.IsDedicated)
|
||||
{
|
||||
MyLog.Default.WriteLine("ControlledObject was null, respawning character");
|
||||
//m_cameraAwaitingEntity = true;
|
||||
@@ -358,7 +296,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
}
|
||||
|
||||
//Request client state batch
|
||||
(MyMultiplayer.Static as MyMultiplayerClientBase).RequestBatchConfirmation();
|
||||
((MyMultiplayerClientBase)MyMultiplayer.Static).RequestBatchConfirmation();
|
||||
MyMultiplayer.Static.PendingReplicablesDone += MyMultiplayer_PendingReplicablesDone;
|
||||
//typeof(MyGuiScreenTerminal).GetMethod("CreateTabs")
|
||||
|
||||
@@ -368,16 +306,13 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
MyRenderProxy.RebuildCullingStructure();
|
||||
MyRenderProxy.CollectGarbage();
|
||||
|
||||
SeamlessClient.TryShow("OnlinePlayers: " + MySession.Static.Players.GetOnlinePlayers().Count);
|
||||
SeamlessClient.TryShow($"OnlinePlayers: {MySession.Static.Players.GetOnlinePlayers().Count}");
|
||||
SeamlessClient.TryShow("Loading Complete!");
|
||||
}
|
||||
|
||||
private void MyMultiplayer_PendingReplicablesDone()
|
||||
{
|
||||
if (MySession.Static.VoxelMaps.Instances.Count > 0)
|
||||
{
|
||||
MySandboxGame.AreClipmapsReady = false;
|
||||
}
|
||||
if (MySession.Static.VoxelMaps.Instances.Count > 0) MySandboxGame.AreClipmapsReady = false;
|
||||
MyMultiplayer.Static.PendingReplicablesDone -= MyMultiplayer_PendingReplicablesDone;
|
||||
}
|
||||
|
||||
@@ -388,31 +323,24 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
|
||||
//This shoud never be null
|
||||
var Generator = MySession.Static.GetComponent<MyProceduralWorldGenerator>();
|
||||
var generator = MySession.Static.GetComponent<MyProceduralWorldGenerator>();
|
||||
|
||||
//Force component to unload
|
||||
Patches.UnloadProceduralWorldGenerator.Invoke(Generator, null);
|
||||
Patches.UnloadProceduralWorldGenerator.Invoke(generator, null);
|
||||
|
||||
//Re-call the generator init
|
||||
MyObjectBuilder_WorldGenerator GeneratorSettings = (MyObjectBuilder_WorldGenerator)TargetWorld.Checkpoint.SessionComponents.FirstOrDefault(x => x.GetType() == typeof(MyObjectBuilder_WorldGenerator));
|
||||
if (GeneratorSettings != null)
|
||||
{
|
||||
var generatorSettings = TargetWorld.Checkpoint.SessionComponents.OfType<MyObjectBuilder_WorldGenerator>().FirstOrDefault();
|
||||
if (generatorSettings != null)
|
||||
//Re-initilized this component (forces to update asteroid areas like not in planets etc)
|
||||
Generator.Init(GeneratorSettings);
|
||||
}
|
||||
generator.Init(generatorSettings);
|
||||
|
||||
//Force component to reload, re-syncing settings and seeds to the destination server
|
||||
Generator.LoadData();
|
||||
generator.LoadData();
|
||||
|
||||
//We need to go in and force planets to be empty areas in the generator. This is originially done on planet init.
|
||||
FieldInfo PlanetInitArgs = typeof(MyPlanet).GetField("m_planetInitValues", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
foreach (var Planet in MyEntities.GetEntities().OfType<MyPlanet>())
|
||||
foreach (var planet in MyEntities.GetEntities().OfType<MyPlanet>())
|
||||
{
|
||||
MyPlanetInitArguments args = (MyPlanetInitArguments)PlanetInitArgs.GetValue(Planet);
|
||||
|
||||
float MaxRadius = args.MaxRadius;
|
||||
|
||||
Generator.MarkEmptyArea(Planet.PositionComp.GetPosition(), MaxRadius);
|
||||
generator.MarkEmptyArea(planet.PositionComp.GetPosition(), planet.m_planetInitValues.MaxRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +354,7 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
RemoveOldEntities();
|
||||
|
||||
//Try and close the quest log
|
||||
MySessionComponentIngameHelp component = MySession.Static.GetComponent<MySessionComponentIngameHelp>();
|
||||
var component = MySession.Static.GetComponent<MySessionComponentIngameHelp>();
|
||||
component?.TryCancelObjective();
|
||||
|
||||
//Clear all old players and clients.
|
||||
@@ -437,8 +365,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
MyHud.Chat.UnregisterChat(MyMultiplayer.Static);
|
||||
|
||||
|
||||
|
||||
|
||||
MySession.Static.Gpss.RemovePlayerGpss(MySession.Static.LocalPlayerId);
|
||||
MyHud.GpsMarkers.Clear();
|
||||
MyMultiplayer.Static.ReplicationLayer.Disconnect();
|
||||
@@ -450,7 +376,6 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
MyGuiScreenMedicals.Close();
|
||||
|
||||
//MySession.Static.UnloadDataComponents();
|
||||
|
||||
}
|
||||
|
||||
private void RemoveOldEntities()
|
||||
@@ -463,6 +388,4 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
ent.Close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using HarmonyLib;
|
||||
using ProtoBuf;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Game;
|
||||
using Sandbox.Game.Gui;
|
||||
@@ -7,154 +8,47 @@ using Sandbox.Game.GUI;
|
||||
using Sandbox.Game.Localization;
|
||||
using Sandbox.Game.Multiplayer;
|
||||
using Sandbox.Game.SessionComponents;
|
||||
using Sandbox.Game.VoiceChat;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.Graphics.GUI;
|
||||
using SeamlessClientPlugin.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VRage;
|
||||
using VRage.Audio;
|
||||
using VRage.Game;
|
||||
using VRage.Game.ModAPI;
|
||||
using VRage.Utils;
|
||||
using VRageMath;
|
||||
|
||||
namespace SeamlessClientPlugin.Utilities
|
||||
{
|
||||
namespace SeamlessClientPlugin.Utilities;
|
||||
|
||||
public class OnlinePlayers
|
||||
{
|
||||
private static Harmony Patcher = new Harmony("OnlinePlayersPatcher");
|
||||
public static List<OnlineServer> AllServers = new List<OnlineServer>();
|
||||
public static int currentServer;
|
||||
public class OnlinePlayers
|
||||
{
|
||||
private static readonly Harmony Patcher = new("OnlinePlayersPatcher");
|
||||
public static List<OnlineServer> AllServers = [];
|
||||
public static int CurrentServer;
|
||||
private static string _currentServerName;
|
||||
|
||||
public static int totalPlayerCount = 0;
|
||||
public static int currentPlayerCount = 0;
|
||||
|
||||
|
||||
private static MethodInfo m_UpdateCaption;
|
||||
private static MethodInfo m_RefreshMuteIcons;
|
||||
private static MethodInfo m_OnToggleMutePressed;
|
||||
private static MethodInfo m_AddCaption;
|
||||
|
||||
|
||||
private static MethodInfo m_profileButton_ButtonClicked;
|
||||
private static MethodInfo m_promoteButton_ButtonClicked;
|
||||
private static MethodInfo m_demoteButton_ButtonClicked;
|
||||
private static MethodInfo m_kickButton_ButtonClicked;
|
||||
private static MethodInfo m_banButton_ButtonClicked;
|
||||
private static MethodInfo m_tradeButton_ButtonClicked;
|
||||
private static MethodInfo m_inviteButton_ButtonClicked;
|
||||
private static MethodInfo m_PlayersTable_ItemSelected;
|
||||
|
||||
private static MethodInfo m_UpdateButtonsEnabledState;
|
||||
|
||||
|
||||
private static FieldInfo m_playersTable;
|
||||
private static FieldInfo m_pings;
|
||||
private static FieldInfo m_PlayersTable;
|
||||
private static FieldInfo m_MaxPlayers;
|
||||
private static FieldInfo m_Warfare_timeRemainting_label;
|
||||
private static FieldInfo m_Warfare_timeRemainting_time;
|
||||
private static FieldInfo m_LastSelected;
|
||||
|
||||
/* Buttons */
|
||||
private static FieldInfo m_ProfileButton;
|
||||
private static FieldInfo m_PromoteButton;
|
||||
private static FieldInfo m_DemoteButton;
|
||||
private static FieldInfo m_KickButton;
|
||||
private static FieldInfo m_BanButton;
|
||||
private static FieldInfo m_TradeButton;
|
||||
private static FieldInfo m_InviteButton;
|
||||
|
||||
private static FieldInfo m_caption;
|
||||
private static FieldInfo m_LobbyTypeCombo;
|
||||
private static FieldInfo m_MaxPlayersSlider;
|
||||
|
||||
|
||||
public static int TotalPlayerCount;
|
||||
public static int CurrentPlayerCount;
|
||||
|
||||
public static void Patch()
|
||||
{
|
||||
m_playersTable = typeof(MyGuiScreenPlayers).GetField("m_playersTable", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_pings = typeof(MyGuiScreenPlayers).GetField("pings", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_UpdateCaption = typeof(MyGuiScreenPlayers).GetMethod("UpdateCaption", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_RefreshMuteIcons = typeof(MyGuiScreenPlayers).GetMethod("RefreshMuteIcons", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_OnToggleMutePressed = typeof(MyGuiScreenPlayers).GetMethod("OnToggleMutePressed", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var recreateControls =
|
||||
typeof(MyGuiScreenPlayers).GetMethod("RecreateControls", BindingFlags.Instance | BindingFlags.Public);
|
||||
var updateCaption =
|
||||
typeof(MyGuiScreenPlayers).GetMethod("UpdateCaption", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
m_profileButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("profileButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_promoteButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("promoteButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_demoteButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("demoteButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_kickButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("kickButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_banButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("banButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_tradeButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("tradeButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_inviteButton_ButtonClicked = typeof(MyGuiScreenPlayers).GetMethod("inviteButton_ButtonClicked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_UpdateButtonsEnabledState = typeof(MyGuiScreenPlayers).GetMethod("UpdateButtonsEnabledState", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_PlayersTable_ItemSelected = typeof(MyGuiScreenPlayers).GetMethod("playersTable_ItemSelected", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
//m_SetColumnName = typeof(MyGuiScreenPlayers).GetMethod("SetColumnName", BindingFlags.Instance | BindingFlags.se);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
m_caption = typeof(MyGuiScreenPlayers).GetField("m_caption", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_PlayersTable = typeof(MyGuiScreenPlayers).GetField("m_playersTable", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_MaxPlayers = typeof(MyGuiScreenPlayers).GetField("m_maxPlayers", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_Warfare_timeRemainting_label = typeof(MyGuiScreenPlayers).GetField("m_warfare_timeRemainting_label", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_Warfare_timeRemainting_time = typeof(MyGuiScreenPlayers).GetField("m_warfare_timeRemainting_time", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_LastSelected = typeof(MyGuiScreenPlayers).GetField("m_lastSelected", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_MaxPlayersSlider = typeof(MyGuiScreenPlayers).GetField("m_maxPlayersSlider", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
/* Buttons */
|
||||
m_ProfileButton = typeof(MyGuiScreenPlayers).GetField("m_profileButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_PromoteButton = typeof(MyGuiScreenPlayers).GetField("m_promoteButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_DemoteButton = typeof(MyGuiScreenPlayers).GetField("m_demoteButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_KickButton = typeof(MyGuiScreenPlayers).GetField("m_kickButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_BanButton = typeof(MyGuiScreenPlayers).GetField("m_banButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_TradeButton = typeof(MyGuiScreenPlayers).GetField("m_tradeButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_InviteButton = typeof(MyGuiScreenPlayers).GetField("m_inviteButton", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_LobbyTypeCombo = typeof(MyGuiScreenPlayers).GetField("m_lobbyTypeCombo", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
m_AddCaption = typeof(MyGuiScreenPlayers).GetMethod("AddCaption", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(MyStringId), typeof(Vector4?), typeof(Vector2?), typeof(float) }, null);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
MethodInfo recreateControls = typeof(MyGuiScreenPlayers).GetMethod("RecreateControls", BindingFlags.Instance | BindingFlags.Public);
|
||||
MethodInfo updateCaption = typeof(MyGuiScreenPlayers).GetMethod("UpdateCaption", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
|
||||
|
||||
Patcher.Patch(recreateControls, prefix: new HarmonyMethod(GetPatchMethod(nameof(RecreateControlsPrefix))));
|
||||
Patcher.Patch(updateCaption, prefix: new HarmonyMethod(GetPatchMethod(nameof(UpdateCaption))));
|
||||
Patcher.Patch(recreateControls, new HarmonyMethod(GetPatchMethod(nameof(RecreateControlsPrefix))));
|
||||
Patcher.Patch(updateCaption, new HarmonyMethod(GetPatchMethod(nameof(UpdateCaption))));
|
||||
//Patcher.Patch(recreateControls, postfix: new HarmonyMethod(GetPatchMethod(nameof(RecreateControlsSuffix))));
|
||||
}
|
||||
|
||||
|
||||
public static bool RecreateControlsPrefix(MyGuiScreenPlayers __instance, bool constructor)
|
||||
{
|
||||
|
||||
if (MyMultiplayer.Static != null && MyMultiplayer.Static.IsLobby)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (MyMultiplayer.Static != null && MyMultiplayer.Static.IsLobby) return true;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
__instance.Controls.Clear();
|
||||
__instance.Elements.Clear();
|
||||
//__instance.Elements.Add(m_cl);
|
||||
@@ -177,195 +71,213 @@ namespace SeamlessClientPlugin.Utilities
|
||||
//MyCommonTexts.ScreenCaptionPlayers
|
||||
|
||||
//MyStringId ID = MyStringId.GetOrCompute("Test Caption");
|
||||
m_caption.SetValue(__instance, m_AddCaption.Invoke(__instance, new object[4] { MyCommonTexts.ScreenCaptionPlayers, null, new Vector2(0f, 0.003f), 0.8f }));
|
||||
__instance.m_caption =
|
||||
__instance.AddCaption(MyCommonTexts.ScreenCaptionPlayers, null, new Vector2(0f, 0.003f));
|
||||
|
||||
|
||||
float StartX = -0.435f;
|
||||
float StartY = -0.36f;
|
||||
const float startX = -0.435f;
|
||||
const float startY = -0.36f;
|
||||
|
||||
MyGuiControlSeparatorList myGuiControlSeparatorList = new MyGuiControlSeparatorList();
|
||||
myGuiControlSeparatorList.AddHorizontal(new Vector2(StartX, StartY), .83f);
|
||||
var myGuiControlSeparatorList = new MyGuiControlSeparatorList();
|
||||
myGuiControlSeparatorList.AddHorizontal(new Vector2(startX, startY), .83f);
|
||||
|
||||
|
||||
|
||||
|
||||
Vector2 start = new Vector2(StartX, 0.358f);
|
||||
var start = new Vector2(startX, 0.358f);
|
||||
myGuiControlSeparatorList.AddHorizontal(start, 0.728f);
|
||||
myGuiControlSeparatorList.AddHorizontal(new Vector2(StartX, 0.05f), 0.17f);
|
||||
myGuiControlSeparatorList.AddHorizontal(new Vector2(startX, 0.05f), 0.17f);
|
||||
__instance.Controls.Add(myGuiControlSeparatorList);
|
||||
|
||||
|
||||
Vector2 Spacing = new Vector2(0f, 0.057f);
|
||||
Vector2 vector3 = new Vector2(StartX, StartY + 0.035f);
|
||||
var spacing = new Vector2(0f, 0.057f);
|
||||
var vector3 = new Vector2(startX, startY + 0.035f);
|
||||
|
||||
//SeamlessClient.TryShow("B");
|
||||
|
||||
MyGuiControlButton m_profileButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Profile));
|
||||
m_profileButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_profileButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_profileButton);
|
||||
vector3 += Spacing;
|
||||
m_ProfileButton.SetValue(__instance, m_profileButton);
|
||||
var mProfileButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
||||
MyTexts.Get(MyCommonTexts.ScreenPlayers_Profile));
|
||||
mProfileButton.ButtonClicked += __instance.profileButton_ButtonClicked;
|
||||
__instance.Controls.Add(mProfileButton);
|
||||
vector3 += spacing;
|
||||
__instance.m_profileButton = mProfileButton;
|
||||
|
||||
|
||||
MyGuiControlButton m_promoteButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Promote));
|
||||
m_promoteButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_promoteButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_promoteButton);
|
||||
vector3 += Spacing;
|
||||
m_PromoteButton.SetValue(__instance, m_promoteButton);
|
||||
var mPromoteButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
||||
MyTexts.Get(MyCommonTexts.ScreenPlayers_Promote));
|
||||
mPromoteButton.ButtonClicked += __instance.promoteButton_ButtonClicked;
|
||||
__instance.Controls.Add(mPromoteButton);
|
||||
vector3 += spacing;
|
||||
__instance.m_promoteButton = mPromoteButton;
|
||||
|
||||
MyGuiControlButton m_demoteButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Demote));
|
||||
m_demoteButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_demoteButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_demoteButton);
|
||||
vector3 += Spacing;
|
||||
m_DemoteButton.SetValue(__instance, m_demoteButton);
|
||||
var mDemoteButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
||||
MyTexts.Get(MyCommonTexts.ScreenPlayers_Demote));
|
||||
mDemoteButton.ButtonClicked += __instance.demoteButton_ButtonClicked;
|
||||
__instance.Controls.Add(mDemoteButton);
|
||||
vector3 += spacing;
|
||||
__instance.m_demoteButton = mDemoteButton;
|
||||
|
||||
|
||||
MyGuiControlButton m_kickButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Kick));
|
||||
m_kickButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_kickButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_kickButton);
|
||||
vector3 += Spacing;
|
||||
m_KickButton.SetValue(__instance, m_kickButton);
|
||||
var mKickButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
||||
MyTexts.Get(MyCommonTexts.ScreenPlayers_Kick));
|
||||
mKickButton.ButtonClicked += __instance.kickButton_ButtonClicked;
|
||||
__instance.Controls.Add(mKickButton);
|
||||
vector3 += spacing;
|
||||
__instance.m_kickButton = mKickButton;
|
||||
|
||||
MyGuiControlButton m_banButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Ban));
|
||||
m_banButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_banButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_banButton);
|
||||
vector3 += Spacing;
|
||||
m_BanButton.SetValue(__instance, m_banButton);
|
||||
var mBanButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
||||
MyTexts.Get(MyCommonTexts.ScreenPlayers_Ban));
|
||||
mBanButton.ButtonClicked += __instance.banButton_ButtonClicked;
|
||||
__instance.Controls.Add(mBanButton);
|
||||
vector3 += spacing;
|
||||
__instance.m_banButton = mBanButton;
|
||||
|
||||
|
||||
MyGuiControlButton m_tradeButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MySpaceTexts.PlayersScreen_TradeBtn));
|
||||
m_tradeButton.SetTooltip(MyTexts.GetString(MySpaceTexts.PlayersScreen_TradeBtn_TTP));
|
||||
m_tradeButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_tradeButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_tradeButton);
|
||||
m_TradeButton.SetValue(__instance, m_tradeButton);
|
||||
|
||||
var mTradeButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
||||
MyTexts.Get(MySpaceTexts.PlayersScreen_TradeBtn));
|
||||
mTradeButton.SetTooltip(MyTexts.GetString(MySpaceTexts.PlayersScreen_TradeBtn_TTP));
|
||||
mTradeButton.ButtonClicked += __instance.tradeButton_ButtonClicked;
|
||||
__instance.Controls.Add(mTradeButton);
|
||||
__instance.m_tradeButton = mTradeButton;
|
||||
|
||||
|
||||
//SeamlessClient.TryShow("C");
|
||||
|
||||
Vector2 vector4 = vector3 + new Vector2(-0.002f, m_tradeButton.Size.Y + 0.03f);
|
||||
MyGuiControlCombobox m_lobbyTypeCombo = new MyGuiControlCombobox(vector4, null, null, null, 3);
|
||||
m_LobbyTypeCombo.SetValue(__instance, m_lobbyTypeCombo);
|
||||
var vector4 = vector3 + new Vector2(-0.002f, mTradeButton.Size.Y + 0.03f);
|
||||
__instance.m_lobbyTypeCombo = new MyGuiControlCombobox(vector4, null, null, null, 3);
|
||||
|
||||
Vector2 vector5 = vector4 + new Vector2(0f, 0.05f);
|
||||
var vector5 = vector4 + new Vector2(0f, 0.05f);
|
||||
vector5 += new Vector2(0f, 0.03f);
|
||||
int m_maxPlayers = (Sync.IsServer ? MyMultiplayerLobby.MAX_PLAYERS : 16);
|
||||
m_MaxPlayers.SetValue(__instance, m_maxPlayers);
|
||||
MyGuiControlSlider m_maxPlayersSlider = new MyGuiControlSlider(vector5, 2f, Math.Max(m_maxPlayers, 3), 0.177f, Sync.IsServer ? MySession.Static.MaxPlayers : MyMultiplayer.Static.MemberLimit, null, null, 1, 0.8f, 0f, "White", null, MyGuiControlSliderStyleEnum.Default, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, intValue: true);
|
||||
m_MaxPlayersSlider.SetValue(__instance, m_maxPlayersSlider);
|
||||
__instance.m_maxPlayers = Sync.IsServer ? MyMultiplayerLobby.MAX_PLAYERS : 16;
|
||||
__instance.m_maxPlayersSlider = new MyGuiControlSlider(vector5, 2f, Math.Max(__instance.m_maxPlayers, 3), 0.177f,
|
||||
Sync.IsServer ? MySession.Static.MaxPlayers : MyMultiplayer.Static.MemberLimit, null, null, 1, 0.8f, 0f,
|
||||
"White", null, MyGuiControlSliderStyleEnum.Default, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP,
|
||||
true);
|
||||
|
||||
|
||||
MyGuiControlButton m_inviteButton = new MyGuiControlButton(new Vector2(StartX, 0.25000026f), MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Invite));
|
||||
m_inviteButton.ButtonClicked += delegate (MyGuiControlButton obj) { m_inviteButton_ButtonClicked.Invoke(__instance, new object[] { obj }); };
|
||||
__instance.Controls.Add(m_inviteButton);
|
||||
m_InviteButton.SetValue(__instance, m_inviteButton);
|
||||
var mInviteButton = new MyGuiControlButton(new Vector2(startX, 0.25000026f),
|
||||
MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP,
|
||||
null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Invite));
|
||||
mInviteButton.ButtonClicked += __instance.inviteButton_ButtonClicked;
|
||||
__instance.Controls.Add(mInviteButton);
|
||||
__instance.m_inviteButton = mInviteButton;
|
||||
|
||||
Vector2 vector6 = new Vector2(-StartX - 0.034f, StartY + 0.033f);
|
||||
Vector2 size = new Vector2(0.66f, 1.2f);
|
||||
int num2 = 18;
|
||||
float num3 = 0f;
|
||||
var vector6 = new Vector2(-startX - 0.034f, startY + 0.033f);
|
||||
var size = new Vector2(0.66f, 1.2f);
|
||||
var num2 = 18;
|
||||
var num3 = 0f;
|
||||
|
||||
|
||||
//SeamlessClient.TryShow("D");
|
||||
MySessionComponentMatch component = MySession.Static.GetComponent<MySessionComponentMatch>();
|
||||
var component = MySession.Static.GetComponent<MySessionComponentMatch>();
|
||||
if (component.IsEnabled)
|
||||
{
|
||||
Vector2 vector7 = __instance.GetPositionAbsolute() + vector6 + new Vector2(0f - size.X, 0f);
|
||||
MyGuiControlLabel m_warfare_timeRemainting_label = new MyGuiControlLabel(vector6 - new Vector2(size.X, 0f));
|
||||
m_warfare_timeRemainting_label.Text = MyTexts.GetString(MySpaceTexts.WarfareCounter_TimeRemaining).ToString() + ": ";
|
||||
__instance.Controls.Add(m_warfare_timeRemainting_label);
|
||||
m_Warfare_timeRemainting_label.SetValue(__instance, m_warfare_timeRemainting_label);
|
||||
|
||||
|
||||
TimeSpan timeSpan = TimeSpan.FromMinutes(component.RemainingMinutes);
|
||||
MyGuiControlLabel m_warfare_timeRemainting_time = new MyGuiControlLabel(vector6 - new Vector2(size.X, 0f) + new Vector2(m_warfare_timeRemainting_label.Size.X, 0f));
|
||||
m_warfare_timeRemainting_time.Text = timeSpan.ToString((timeSpan.TotalHours >= 1.0) ? "hh\\:mm\\:ss" : "mm\\:ss");
|
||||
__instance.Controls.Add(m_warfare_timeRemainting_time);
|
||||
m_Warfare_timeRemainting_time.SetValue(__instance, m_warfare_timeRemainting_label);
|
||||
|
||||
float num4 = 0.09f;
|
||||
float num5 = size.X / 3f - 2f * num3;
|
||||
int num6 = 0;
|
||||
MyFaction[] allFactions = MySession.Static.Factions.GetAllFactions();
|
||||
foreach (MyFaction myFaction in allFactions)
|
||||
var vector7 = __instance.GetPositionAbsolute() + vector6 + new Vector2(0f - size.X, 0f);
|
||||
var mWarfareTimeRemaintingLabel = new MyGuiControlLabel(vector6 - new Vector2(size.X, 0f))
|
||||
{
|
||||
if ((myFaction.Name.StartsWith("Red") || myFaction.Name.StartsWith("Green") || myFaction.Name.StartsWith("Blue")) && myFaction.Name.EndsWith("Faction"))
|
||||
Text = $"{MyTexts.GetString(MySpaceTexts.WarfareCounter_TimeRemaining)}: "
|
||||
};
|
||||
__instance.Controls.Add(mWarfareTimeRemaintingLabel);
|
||||
__instance.m_warfare_timeRemainting_label = mWarfareTimeRemaintingLabel;
|
||||
|
||||
|
||||
var timeSpan = TimeSpan.FromMinutes(component.RemainingMinutes);
|
||||
var mWarfareTimeRemaintingTime = new MyGuiControlLabel(vector6 - new Vector2(size.X, 0f) +
|
||||
new Vector2(
|
||||
mWarfareTimeRemaintingLabel.Size.X,
|
||||
0f))
|
||||
{
|
||||
__instance.Controls.Add(new MyGuiScreenPlayersWarfareTeamScoreTable(vector7 + new Vector2((float)num6 * (num5 + num3), m_warfare_timeRemainting_label.Size.Y + num3), num5, num4, myFaction.Name, myFaction.FactionIcon.Value.String, MyTexts.GetString(MySpaceTexts.WarfareCounter_EscapePod), myFaction.FactionId, drawOwnBackground: false, drawBorders: true, myFaction.IsMember(MySession.Static.LocalHumanPlayer.Identity.IdentityId)));
|
||||
Text = timeSpan.ToString(timeSpan.TotalHours >= 1.0 ? @"hh\:mm\:ss" : "mm\\:ss")
|
||||
};
|
||||
__instance.Controls.Add(mWarfareTimeRemaintingTime);
|
||||
__instance.m_warfare_timeRemainting_time = mWarfareTimeRemaintingTime;
|
||||
|
||||
var num4 = 0.09f;
|
||||
var num5 = size.X / 3f - 2f * num3;
|
||||
var num6 = 0;
|
||||
var allFactions = MySession.Static.Factions.GetAllFactions();
|
||||
foreach (var myFaction in allFactions)
|
||||
if ((myFaction.Name.StartsWith("Red") || myFaction.Name.StartsWith("Green") ||
|
||||
myFaction.Name.StartsWith("Blue")) && myFaction.Name.EndsWith("Faction"))
|
||||
{
|
||||
__instance.Controls.Add(new MyGuiScreenPlayersWarfareTeamScoreTable(
|
||||
vector7 + new Vector2(num6 * (num5 + num3), mWarfareTimeRemaintingLabel.Size.Y + num3),
|
||||
num5, num4, myFaction.Name, myFaction.FactionIcon.Value.String,
|
||||
MyTexts.GetString(MySpaceTexts.WarfareCounter_EscapePod), myFaction.FactionId, false, true,
|
||||
myFaction.IsMember(MySession.Static.LocalHumanPlayer.Identity.IdentityId)));
|
||||
num6++;
|
||||
}
|
||||
}
|
||||
vector6.Y += m_warfare_timeRemainting_label.Size.Y + num4 + num3 * 2f;
|
||||
|
||||
vector6.Y += mWarfareTimeRemaintingLabel.Size.Y + num4 + num3 * 2f;
|
||||
num2 -= 3;
|
||||
}
|
||||
//SeamlessClient.TryShow("E");
|
||||
|
||||
MyGuiControlTable m_playersTable = new MyGuiControlTable
|
||||
__instance.m_playersTable = new MyGuiControlTable
|
||||
{
|
||||
Position = vector6,
|
||||
Size = size,
|
||||
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_TOP,
|
||||
ColumnsCount = 7
|
||||
ColumnsCount = 7,
|
||||
//SeamlessClient.TryShow("F");
|
||||
GamepadHelpTextId = MySpaceTexts.PlayersScreen_Help_PlayersList,
|
||||
VisibleRowsCount = num2
|
||||
};
|
||||
|
||||
m_PlayersTable.SetValue(__instance, m_playersTable);
|
||||
const float playerNameWidth = 0.2f;
|
||||
const float rankWidth = 0.1f;
|
||||
const float pingWidth = 0.08f;
|
||||
const float mutedWidth = 0.1f;
|
||||
const float steamIconWidth = 0.04f;
|
||||
const float serverWidth = 0.20f;
|
||||
const float factionNameWidth = 1f - playerNameWidth - rankWidth - mutedWidth - pingWidth - steamIconWidth - serverWidth;
|
||||
|
||||
//SeamlessClient.TryShow("F");
|
||||
|
||||
m_playersTable.GamepadHelpTextId = MySpaceTexts.PlayersScreen_Help_PlayersList;
|
||||
m_playersTable.VisibleRowsCount = num2;
|
||||
float PlayerName = 0.2f;
|
||||
float Rank = 0.1f;
|
||||
float Ping = 0.08f;
|
||||
float Muted = 0.1f;
|
||||
float SteamIcon = 0.04f;
|
||||
float Server = 0.20f;
|
||||
float FactionName = 1f - PlayerName - Rank - Muted - Ping - SteamIcon - Server;
|
||||
|
||||
m_playersTable.SetCustomColumnWidths(new float[7]
|
||||
{
|
||||
SteamIcon,
|
||||
PlayerName,
|
||||
FactionName,
|
||||
Rank,
|
||||
Ping,
|
||||
Muted,
|
||||
Server,
|
||||
});
|
||||
__instance.m_playersTable.SetCustomColumnWidths([
|
||||
steamIconWidth,
|
||||
playerNameWidth,
|
||||
factionNameWidth,
|
||||
rankWidth,
|
||||
pingWidth,
|
||||
mutedWidth,
|
||||
serverWidth
|
||||
]);
|
||||
|
||||
//SeamlessClient.TryShow("G");
|
||||
|
||||
m_playersTable.SetColumnComparison(1, (MyGuiControlTable.Cell a, MyGuiControlTable.Cell b) => a.Text.CompareToIgnoreCase(b.Text));
|
||||
m_playersTable.SetColumnName(1, MyTexts.Get(MyCommonTexts.ScreenPlayers_PlayerName));
|
||||
m_playersTable.SetColumnComparison(2, (MyGuiControlTable.Cell a, MyGuiControlTable.Cell b) => a.Text.CompareToIgnoreCase(b.Text));
|
||||
m_playersTable.SetColumnName(2, MyTexts.Get(MyCommonTexts.ScreenPlayers_FactionName));
|
||||
m_playersTable.SetColumnName(5, new StringBuilder(MyTexts.GetString(MyCommonTexts.ScreenPlayers_Muted)));
|
||||
m_playersTable.SetColumnComparison(3, GameAdminCompare);
|
||||
m_playersTable.SetColumnName(3, MyTexts.Get(MyCommonTexts.ScreenPlayers_Rank));
|
||||
m_playersTable.SetColumnComparison(4, GamePingCompare);
|
||||
m_playersTable.SetColumnName(4, MyTexts.Get(MyCommonTexts.ScreenPlayers_Ping));
|
||||
__instance.m_playersTable.SetColumnComparison(1, (a, b) => a.Text.CompareToIgnoreCase(b.Text));
|
||||
__instance.m_playersTable.SetColumnName(1, MyTexts.Get(MyCommonTexts.ScreenPlayers_PlayerName));
|
||||
__instance.m_playersTable.SetColumnComparison(2, (a, b) => a.Text.CompareToIgnoreCase(b.Text));
|
||||
__instance.m_playersTable.SetColumnName(2, MyTexts.Get(MyCommonTexts.ScreenPlayers_FactionName));
|
||||
__instance.m_playersTable.SetColumnName(5, new StringBuilder(MyTexts.GetString(MyCommonTexts.ScreenPlayers_Muted)));
|
||||
__instance.m_playersTable.SetColumnComparison(3, GameAdminCompare);
|
||||
__instance.m_playersTable.SetColumnName(3, MyTexts.Get(MyCommonTexts.ScreenPlayers_Rank));
|
||||
__instance.m_playersTable.SetColumnComparison(4, GamePingCompare);
|
||||
__instance.m_playersTable.SetColumnName(4, MyTexts.Get(MyCommonTexts.ScreenPlayers_Ping));
|
||||
|
||||
|
||||
StringBuilder colName = new StringBuilder("Server");
|
||||
m_playersTable.SetColumnName(6, colName);
|
||||
m_playersTable.SetColumnComparison(6, (MyGuiControlTable.Cell a, MyGuiControlTable.Cell b) => a.Text.CompareToIgnoreCase(b.Text));
|
||||
var colName = new StringBuilder("Server");
|
||||
__instance.m_playersTable.SetColumnName(6, colName);
|
||||
__instance.m_playersTable.SetColumnComparison(6, (a, b) => a.Text.CompareToIgnoreCase(b.Text));
|
||||
|
||||
//SeamlessClient.TryShow("H");
|
||||
|
||||
|
||||
//m_PlayersTable_ItemSelected
|
||||
m_playersTable.ItemSelected += delegate (MyGuiControlTable i, MyGuiControlTable.EventArgs x) { m_PlayersTable_ItemSelected.Invoke(__instance, new object[] { i, x }); };
|
||||
m_playersTable.UpdateTableSortHelpText();
|
||||
__instance.Controls.Add(m_playersTable);
|
||||
__instance.m_playersTable.ItemSelected += __instance.playersTable_ItemSelected;
|
||||
__instance.m_playersTable.UpdateTableSortHelpText();
|
||||
__instance.Controls.Add(__instance.m_playersTable);
|
||||
|
||||
|
||||
string thisServerName = "thisServer";
|
||||
totalPlayerCount = 0;
|
||||
foreach(var server in AllServers)
|
||||
var thisServerName = "<this>";
|
||||
TotalPlayerCount = 0;
|
||||
foreach (var server in AllServers)
|
||||
{
|
||||
|
||||
string servername = server.ServerName;
|
||||
if (server.ServerID == currentServer)
|
||||
var servername = server.ServerName;
|
||||
if (server.ServerId == CurrentServer)
|
||||
{
|
||||
thisServerName = servername;
|
||||
_currentServerName = servername;
|
||||
@@ -374,168 +286,141 @@ namespace SeamlessClientPlugin.Utilities
|
||||
|
||||
foreach (var player in server.Players)
|
||||
{
|
||||
|
||||
AddPlayer(__instance, player.SteamID, servername, player.PlayerName, player.IdentityID);
|
||||
totalPlayerCount++;
|
||||
AddPlayer(__instance, player.SteamId, servername, player.PlayerName, player.IdentityId);
|
||||
TotalPlayerCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
currentPlayerCount = 0;
|
||||
foreach (MyPlayer onlinePlayer in Sync.Players.GetOnlinePlayers())
|
||||
CurrentPlayerCount = 0;
|
||||
foreach (var onlinePlayer in Sync.Players.GetOnlinePlayers())
|
||||
{
|
||||
if (onlinePlayer.Id.SerialId != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (onlinePlayer.Id.SerialId != 0) continue;
|
||||
|
||||
currentPlayerCount++;
|
||||
totalPlayerCount++;
|
||||
CurrentPlayerCount++;
|
||||
TotalPlayerCount++;
|
||||
AddPlayer(__instance, onlinePlayer.Id.SteamId, thisServerName);
|
||||
}
|
||||
|
||||
//SeamlessClient.TryShow("I");
|
||||
|
||||
ulong m_lastSelected = (ulong)m_LastSelected.GetValue(__instance);
|
||||
if (m_lastSelected != 0L)
|
||||
if (__instance.m_lastSelected != 0L)
|
||||
{
|
||||
MyGuiControlTable.Row row2 = m_playersTable.Find((MyGuiControlTable.Row r) => (ulong)r.UserData == m_lastSelected);
|
||||
if (row2 != null)
|
||||
{
|
||||
m_playersTable.SelectedRow = row2;
|
||||
}
|
||||
var row2 = __instance.m_playersTable.Find(r => (ulong)r.UserData == __instance.m_lastSelected);
|
||||
if (row2 != null) __instance.m_playersTable.SelectedRow = row2;
|
||||
}
|
||||
|
||||
m_UpdateButtonsEnabledState.Invoke(__instance, null);
|
||||
__instance.UpdateButtonsEnabledState();
|
||||
//UpdateButtonsEnabledState();
|
||||
|
||||
m_UpdateCaption.Invoke(__instance, null);
|
||||
__instance.UpdateCaption();
|
||||
|
||||
|
||||
|
||||
|
||||
Vector2 minSizeGui = MyGuiControlButton.GetVisualStyle(MyGuiControlButtonStyleEnum.Default).NormalTexture.MinSizeGui;
|
||||
MyGuiControlLabel myGuiControlLabel = new MyGuiControlLabel(new Vector2(start.X, start.Y + minSizeGui.Y / 2f));
|
||||
myGuiControlLabel.Name = MyGuiScreenBase.GAMEPAD_HELP_LABEL_NAME;
|
||||
var minSizeGui = MyGuiControlButton.GetVisualStyle(MyGuiControlButtonStyleEnum.Default).NormalTexture
|
||||
.MinSizeGui;
|
||||
var myGuiControlLabel = new MyGuiControlLabel(new Vector2(start.X, start.Y + minSizeGui.Y / 2f))
|
||||
{
|
||||
Name = MyGuiScreenBase.GAMEPAD_HELP_LABEL_NAME
|
||||
};
|
||||
__instance.Controls.Add(myGuiControlLabel);
|
||||
__instance.GamepadHelpTextId = MySpaceTexts.PlayersScreen_Help_Screen;
|
||||
__instance.FocusedControl = m_playersTable;
|
||||
__instance.FocusedControl = __instance.m_playersTable;
|
||||
|
||||
//SeamlessClient.TryShow("J");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SeamlessClient.TryShow(ex.ToString());
|
||||
__instance.Controls.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool AddPlayer(MyGuiScreenPlayers __instance, ulong userId, string server, string playername = null, long playerId = 0)
|
||||
private static bool AddPlayer(MyGuiScreenPlayers instance, ulong userId, string server, string playerName = null,
|
||||
long playerId = 0)
|
||||
{
|
||||
MyGuiControlTable table = (MyGuiControlTable)m_playersTable.GetValue(__instance);
|
||||
Dictionary<ulong, short> pings = (Dictionary<ulong, short>)m_pings.GetValue(__instance);
|
||||
var table = instance.m_playersTable;
|
||||
var pings = instance.pings;
|
||||
|
||||
if(playername == null)
|
||||
playername = MyMultiplayer.Static.GetMemberName(userId);
|
||||
playerName ??= MyMultiplayer.Static.GetMemberName(userId);
|
||||
|
||||
if (string.IsNullOrEmpty(playername))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(playerName)) return false;
|
||||
|
||||
|
||||
MyGuiControlTable.Row row = new MyGuiControlTable.Row(userId);
|
||||
string memberServiceName = MyMultiplayer.Static.GetMemberServiceName(userId);
|
||||
StringBuilder text = new StringBuilder();
|
||||
|
||||
var row = new MyGuiControlTable.Row(userId);
|
||||
var memberServiceName = MyMultiplayer.Static.GetMemberServiceName(userId);
|
||||
var text = new StringBuilder();
|
||||
|
||||
|
||||
MyGuiHighlightTexture? icon = new MyGuiHighlightTexture
|
||||
{
|
||||
Normal = "Textures\\GUI\\Icons\\Services\\" + memberServiceName + ".png",
|
||||
Highlight = "Textures\\GUI\\Icons\\Services\\" + memberServiceName + ".png",
|
||||
Normal = $@"Textures\GUI\Icons\Services\{memberServiceName}.png",
|
||||
Highlight = $@"Textures\GUI\Icons\Services\{memberServiceName}.png",
|
||||
SizePx = new Vector2(24f, 24f)
|
||||
};
|
||||
row.AddCell(new MyGuiControlTable.Cell(text, null, memberServiceName, Color.White, icon, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_CENTER));
|
||||
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(playername), playername));
|
||||
row.AddCell(new MyGuiControlTable.Cell(text, null, memberServiceName, Color.White, icon,
|
||||
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_CENTER));
|
||||
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(playerName), playerName));
|
||||
|
||||
|
||||
if(playerId == 0)
|
||||
if (playerId == 0)
|
||||
playerId = Sync.Players.TryGetIdentityId(userId);
|
||||
|
||||
|
||||
|
||||
MyFaction playerFaction = MySession.Static.Factions.GetPlayerFaction(playerId);
|
||||
string text2 = "";
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
var playerFaction = MySession.Static.Factions.GetPlayerFaction(playerId);
|
||||
var text2 = "";
|
||||
var stringBuilder = new StringBuilder();
|
||||
if (playerFaction != null)
|
||||
{
|
||||
text2 += playerFaction.Name;
|
||||
text2 = text2 + " | " + playername;
|
||||
foreach (KeyValuePair<long, MyFactionMember> member in playerFaction.Members)
|
||||
text2 = $"{text2} | {playerName}";
|
||||
foreach (var member in playerFaction.Members)
|
||||
if ((member.Value.IsLeader || member.Value.IsFounder) &&
|
||||
MySession.Static.Players.TryGetPlayerId(member.Value.PlayerId, out var result) &&
|
||||
MySession.Static.Players.TryGetPlayerById(result, out var player))
|
||||
{
|
||||
if ((member.Value.IsLeader || member.Value.IsFounder) && MySession.Static.Players.TryGetPlayerId(member.Value.PlayerId, out var result) && MySession.Static.Players.TryGetPlayerById(result, out var player))
|
||||
{
|
||||
text2 = text2 + " | " + player.DisplayName;
|
||||
text2 = $"{text2} | {player.DisplayName}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stringBuilder.Append(MyStatControlText.SubstituteTexts(playerFaction.Name));
|
||||
if (playerFaction.IsLeader(playerId))
|
||||
{
|
||||
stringBuilder.Append(" (").Append((object)MyTexts.Get(MyCommonTexts.Leader)).Append(")");
|
||||
if (!string.IsNullOrEmpty(playerFaction.Tag)) stringBuilder.Insert(0, $"[{playerFaction.Tag}] ");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(playerFaction.Tag))
|
||||
{
|
||||
stringBuilder.Insert(0, "[" + playerFaction.Tag + "] ");
|
||||
}
|
||||
}
|
||||
|
||||
row.AddCell(new MyGuiControlTable.Cell(stringBuilder, null, text2));
|
||||
StringBuilder stringBuilder2 = new StringBuilder();
|
||||
MyPromoteLevel userPromoteLevel = MySession.Static.GetUserPromoteLevel(userId);
|
||||
for (int i = 0; i < (int)userPromoteLevel; i++)
|
||||
{
|
||||
stringBuilder2.Append("*");
|
||||
}
|
||||
var stringBuilder2 = new StringBuilder();
|
||||
var userPromoteLevel = MySession.Static.GetUserPromoteLevel(userId);
|
||||
for (var i = 0; i < (int)userPromoteLevel; i++) stringBuilder2.Append('*');
|
||||
row.AddCell(new MyGuiControlTable.Cell(stringBuilder2));
|
||||
if (pings.ContainsKey(userId))
|
||||
{
|
||||
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(pings[userId].ToString())));
|
||||
}
|
||||
if (pings.TryGetValue(userId, out var ping))
|
||||
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(ping.ToString())));
|
||||
else
|
||||
{
|
||||
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder("----")));
|
||||
}
|
||||
MyGuiControlTable.Cell cell = new MyGuiControlTable.Cell(new StringBuilder(""));
|
||||
var cell = new MyGuiControlTable.Cell(new StringBuilder(""));
|
||||
row.AddCell(cell);
|
||||
if (userId != Sync.MyId)
|
||||
{
|
||||
MyGuiControlButton myGuiControlButton = new MyGuiControlButton();
|
||||
myGuiControlButton.CustomStyle = m_buttonSizeStyleUnMuted;
|
||||
myGuiControlButton.Size = new Vector2(0.03f, 0.04f);
|
||||
myGuiControlButton.CueEnum = GuiSounds.None;
|
||||
|
||||
|
||||
Action<MyGuiControlButton> btnClicked = delegate (MyGuiControlButton b)
|
||||
var myGuiControlButton = new MyGuiControlButton
|
||||
{
|
||||
m_OnToggleMutePressed.Invoke(__instance, new object[] { b });
|
||||
CustomStyle = instance.m_buttonSizeStyleSilent,
|
||||
Size = new Vector2(0.03f, 0.04f),
|
||||
CueEnum = GuiSounds.None
|
||||
};
|
||||
|
||||
|
||||
|
||||
myGuiControlButton.ButtonClicked += btnClicked;
|
||||
myGuiControlButton.ButtonClicked += instance.OnToggleMutePressed;
|
||||
myGuiControlButton.UserData = userId;
|
||||
cell.Control = myGuiControlButton;
|
||||
table.Controls.Add(myGuiControlButton);
|
||||
m_RefreshMuteIcons.Invoke(__instance, null);
|
||||
instance.RefreshMuteIcons();
|
||||
//RefreshMuteIcons();
|
||||
}
|
||||
|
||||
table.Add(row);
|
||||
m_UpdateCaption.Invoke(__instance, null);
|
||||
instance.UpdateCaption();
|
||||
|
||||
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(server), "Server Name"));
|
||||
|
||||
@@ -544,19 +429,12 @@ namespace SeamlessClientPlugin.Utilities
|
||||
|
||||
private static bool UpdateCaption(MyGuiScreenPlayers __instance)
|
||||
{
|
||||
if (MyMultiplayer.Static != null && MyMultiplayer.Static.IsLobby)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
MyGuiControlLabel mM_caption = (MyGuiControlLabel)m_caption.GetValue(__instance);
|
||||
MyGuiControlTable mm_playersTable = (MyGuiControlTable)m_playersTable.GetValue(__instance);
|
||||
|
||||
|
||||
if (MyMultiplayer.Static != null && MyMultiplayer.Static.IsLobby) return true;
|
||||
|
||||
//string s = $"{MyTexts.Get(MyCommonTexts.ScreenCaptionServerName).ToString()} - SectorPlayers: ({ mm_playersTable.RowsCount} / {MySession.Static.MaxPlayers}) TotalPlayers: ( {5} / 200 )";
|
||||
|
||||
mM_caption.Text = string.Concat("Server: ", _currentServerName, " - ", "Innstance Players", " (", currentPlayerCount, " / ", MySession.Static.MaxPlayers, ") TotalPlayers: ( ", totalPlayerCount, " )");
|
||||
__instance.m_caption.Text =
|
||||
$"Server: {_currentServerName} - Innstance Players ({CurrentPlayerCount} / {MySession.Static.MaxPlayers}) TotalPlayers: ({TotalPlayerCount})";
|
||||
|
||||
|
||||
return false;
|
||||
@@ -564,38 +442,22 @@ namespace SeamlessClientPlugin.Utilities
|
||||
|
||||
private static int GamePingCompare(MyGuiControlTable.Cell a, MyGuiControlTable.Cell b)
|
||||
{
|
||||
if (!int.TryParse(a.Text.ToString(), out var result))
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
if (!int.TryParse(b.Text.ToString(), out var result2))
|
||||
{
|
||||
result2 = -1;
|
||||
}
|
||||
if (!int.TryParse(a.Text.ToString(), out var result)) result = -1;
|
||||
if (!int.TryParse(b.Text.ToString(), out var result2)) result2 = -1;
|
||||
return result.CompareTo(result2);
|
||||
}
|
||||
|
||||
private static int GameAdminCompare(MyGuiControlTable.Cell a, MyGuiControlTable.Cell b)
|
||||
{
|
||||
ulong steamId = (ulong)a.Row.UserData;
|
||||
ulong steamId2 = (ulong)b.Row.UserData;
|
||||
int userPromoteLevel = (int)MySession.Static.GetUserPromoteLevel(steamId);
|
||||
int userPromoteLevel2 = (int)MySession.Static.GetUserPromoteLevel(steamId2);
|
||||
var steamId = (ulong)a.Row.UserData;
|
||||
var steamId2 = (ulong)b.Row.UserData;
|
||||
var userPromoteLevel = (int)MySession.Static.GetUserPromoteLevel(steamId);
|
||||
var userPromoteLevel2 = (int)MySession.Static.GetUserPromoteLevel(steamId2);
|
||||
return userPromoteLevel.CompareTo(userPromoteLevel2);
|
||||
}
|
||||
|
||||
|
||||
private static readonly MyGuiControlButton.StyleDefinition m_buttonSizeStyleUnMuted = new MyGuiControlButton.StyleDefinition
|
||||
{
|
||||
NormalFont = "White",
|
||||
HighlightFont = "White",
|
||||
NormalTexture = MyGuiConstants.TEXTURE_HUD_VOICE_CHAT,
|
||||
HighlightTexture = MyGuiConstants.TEXTURE_HUD_VOICE_CHAT
|
||||
};
|
||||
|
||||
private static MethodInfo GetPatchMethod(string v)
|
||||
{
|
||||
return typeof(OnlinePlayers).GetMethod(v, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,181 +1,152 @@
|
||||
using HarmonyLib;
|
||||
using Sandbox.Engine.Analytics;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Game;
|
||||
using Sandbox.Game.Entities;
|
||||
using Sandbox.Game.Gui;
|
||||
using Sandbox.Game.Multiplayer;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.Game.World.Generator;
|
||||
using Sandbox.Graphics;
|
||||
using Sandbox.Graphics.GUI;
|
||||
using Sandbox.ModAPI;
|
||||
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.Collections;
|
||||
using VRage.FileSystem;
|
||||
using VRage.Game;
|
||||
using VRage.Game.Entity;
|
||||
using VRage.GameServices;
|
||||
using VRage.Network;
|
||||
using VRage.Utils;
|
||||
using VRageMath;
|
||||
|
||||
namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
namespace SeamlessClientPlugin.Utilities;
|
||||
|
||||
public static class Patches
|
||||
{
|
||||
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");
|
||||
public static readonly Type MySteamServerDiscovery = Type.GetType("VRage.Steam.MySteamServerDiscovery, Vrage.Steam");
|
||||
|
||||
/* Harmony Patcher */
|
||||
private static Harmony Patcher = new Harmony("SeamlessClientPatcher");
|
||||
private static readonly Harmony Patcher = new("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 and PropertyInfos */
|
||||
public static PropertyInfo 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 MethodInfo GPSRegisterChat { get; private set; }
|
||||
|
||||
public static MethodInfo SendPlayerData;
|
||||
/* WorldGenerator */
|
||||
public static MethodInfo UnloadProceduralWorldGenerator { get; private set; }
|
||||
|
||||
|
||||
public static event EventHandler<JoinResultMsg> OnJoinEvent;
|
||||
|
||||
|
||||
|
||||
/* WorldGenerator */
|
||||
public static MethodInfo UnloadProceduralWorldGenerator;
|
||||
|
||||
|
||||
|
||||
private static FieldInfo MBuffer;
|
||||
|
||||
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 and Properties */
|
||||
MySessionLayer = GetProperty(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);
|
||||
|
||||
MBuffer = GetField(MyTransportLayerType, "m_buffer", 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);
|
||||
SendPlayerData = GetMethod(ClientType, "SendPlayerData", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
UnloadProceduralWorldGenerator = GetMethod(typeof(MyProceduralWorldGenerator), "UnloadData", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
GPSRegisterChat = GetMethod(typeof(MyGpsCollection), "RegisterChat", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
var onJoin = GetMethod(typeof(MyMultiplayerClient), "OnUserJoined", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var loadingAction = GetMethod(typeof(MySessionLoader), "LoadMultiplayerSession",
|
||||
BindingFlags.Public | BindingFlags.Static);
|
||||
UnloadProceduralWorldGenerator = GetMethod(typeof(MyProceduralWorldGenerator), "UnloadData",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
//MethodInfo ConnectToServer = GetMethod(typeof(MyGameService), "ConnectToServer", BindingFlags.Static | BindingFlags.Public);
|
||||
MethodInfo LoadingScreenDraw = GetMethod(typeof(MyGuiScreenLoading), "DrawInternal", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
var loadingScreenDraw = GetMethod(typeof(MyGuiScreenLoading), "DrawInternal",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
//Test patches
|
||||
//MethodInfo SetPlayerDed = GetMethod(typeof(MyPlayerCollection), "SetPlayerDeadInternal", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Patcher.Patch(LoadingScreenDraw, prefix: new HarmonyMethod(GetPatchMethod(nameof(DrawInternal))));
|
||||
Patcher.Patch(OnJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined))));
|
||||
Patcher.Patch(LoadingAction, prefix: new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession))));
|
||||
Patcher.Patch(loadingScreenDraw, new HarmonyMethod(GetPatchMethod(nameof(DrawInternal))));
|
||||
Patcher.Patch(onJoin, postfix: new HarmonyMethod(GetPatchMethod(nameof(OnUserJoined))));
|
||||
Patcher.Patch(loadingAction, new HarmonyMethod(GetPatchMethod(nameof(LoadMultiplayerSession))));
|
||||
//Patcher.Patch(SetPlayerDed, prefix: new HarmonyMethod(GetPatchMethod(nameof(SetPlayerDeadInternal))));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static MethodInfo GetPatchMethod(string v)
|
||||
{
|
||||
return typeof(Patches).GetMethod(v, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
|
||||
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 bool OnConnectToServer(MyGameServerItem server, Action<JoinResult> onDone)
|
||||
{
|
||||
if (SeamlessClient.IsSwitching)
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Patch Utils */
|
||||
|
||||
private static MethodInfo GetMethod(Type type, string methodName, BindingFlags flags)
|
||||
{
|
||||
var foundMethod = type.GetMethod(methodName, flags);
|
||||
|
||||
if (foundMethod == null)
|
||||
throw new NullReferenceException($"Method for {methodName} is null!");
|
||||
|
||||
|
||||
return foundMethod;
|
||||
}
|
||||
|
||||
private static FieldInfo GetField(Type type, string fieldName, BindingFlags flags)
|
||||
{
|
||||
var foundField = type.GetField(fieldName, flags);
|
||||
|
||||
if (foundField == null)
|
||||
throw new NullReferenceException($"Field for {fieldName} is null!");
|
||||
|
||||
|
||||
return foundField;
|
||||
}
|
||||
|
||||
private static PropertyInfo GetProperty(Type type, string propertyName, BindingFlags flags)
|
||||
{
|
||||
var foundProperty = type.GetProperty(propertyName, flags);
|
||||
|
||||
if (foundProperty == null)
|
||||
throw new NullReferenceException($"Property for {propertyName} is null!");
|
||||
|
||||
|
||||
return foundProperty;
|
||||
}
|
||||
|
||||
private static ConstructorInfo GetConstructor(Type type, BindingFlags flags, Type[] types)
|
||||
{
|
||||
var foundConstructor = type.GetConstructor(flags, null, types, null);
|
||||
|
||||
if (foundConstructor == null)
|
||||
throw new NullReferenceException($"Contructor for {type.Name} is null!");
|
||||
|
||||
|
||||
return foundConstructor;
|
||||
}
|
||||
|
||||
|
||||
#region LoadingScreen
|
||||
|
||||
/* Loading Screen Stuff */
|
||||
|
||||
private static string LoadingScreenTexture = null;
|
||||
private static string ServerName;
|
||||
private static string _loadingScreenTexture;
|
||||
private static string _serverName;
|
||||
|
||||
private static bool LoadMultiplayerSession(MyObjectBuilder_World world, MyMultiplayerBase multiplayerSession)
|
||||
{
|
||||
|
||||
//
|
||||
|
||||
|
||||
|
||||
MyLog.Default.WriteLine("LoadSession() - Start");
|
||||
if (!MyWorkshop.CheckLocalModsAllowed(world.Checkpoint.Mods, allowLocalMods: false))
|
||||
if (!MyWorkshop.CheckLocalModsAllowed(world.Checkpoint.Mods, false))
|
||||
{
|
||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Error, MyMessageBoxButtonsType.OK, messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MyCommonTexts.DialogTextLocalModsDisabledInMultiplayer)));
|
||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(
|
||||
messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError),
|
||||
messageText: MyTexts.Get(MyCommonTexts.DialogTextLocalModsDisabledInMultiplayer)));
|
||||
MyLog.Default.WriteLine("LoadSession() - End");
|
||||
return false;
|
||||
}
|
||||
@@ -183,10 +154,9 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
MyLog.Default.WriteLine("Seamless Downloading mods!");
|
||||
|
||||
|
||||
|
||||
MyWorkshop.DownloadModsAsync(world.Checkpoint.Mods, delegate (bool success)
|
||||
MyWorkshop.DownloadModsAsync(world.Checkpoint.Mods, result =>
|
||||
{
|
||||
if (success)
|
||||
if (result == MyGameServiceCallResult.OK)
|
||||
{
|
||||
MyScreenManager.CloseAllScreensNowExcept(null);
|
||||
MyGuiSandbox.Update(16);
|
||||
@@ -196,32 +166,33 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
MySession.Static = null;
|
||||
}
|
||||
|
||||
ServerName = multiplayerSession.HostName;
|
||||
GetCustomLoadingScreenPath(world.Checkpoint.Mods, out LoadingScreenTexture);
|
||||
_serverName = multiplayerSession.HostName;
|
||||
GetCustomLoadingScreenPath(world.Checkpoint.Mods, out _loadingScreenTexture);
|
||||
|
||||
|
||||
MySessionLoader.StartLoading(delegate
|
||||
{
|
||||
|
||||
LoadMultiplayer.Invoke(null, new object[] { world, multiplayerSession });
|
||||
//MySession.LoadMultiplayer(world, multiplayerSession);
|
||||
}, null, null, null);
|
||||
MySession.LoadMultiplayer(world, multiplayerSession);
|
||||
});
|
||||
}
|
||||
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)));
|
||||
}
|
||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(
|
||||
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))));
|
||||
}
|
||||
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(
|
||||
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();
|
||||
@@ -232,34 +203,37 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
|
||||
private static bool DrawInternal(MyGuiScreenLoading __instance)
|
||||
{
|
||||
|
||||
//If we dont have a custom loading screen texture, do not do the special crap below
|
||||
if (string.IsNullOrEmpty(LoadingScreenTexture))
|
||||
if (string.IsNullOrEmpty(_loadingScreenTexture))
|
||||
return true;
|
||||
|
||||
|
||||
float m_transitionAlpha = (float)typeof(MyGuiScreenBase).GetField("m_transitionAlpha", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance);
|
||||
string m_font = "LoadingScreen";
|
||||
//MyGuiControlMultilineText m_multiTextControl = (MyGuiControlMultilineText)typeof(MyGuiScreenLoading).GetField("m_multiTextControl", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance);
|
||||
|
||||
|
||||
Color color = new Color(255, 255, 255, 250);
|
||||
color.A = (byte)((float)(int)color.A * m_transitionAlpha);
|
||||
Rectangle fullscreenRectangle = MyGuiManager.GetFullscreenRectangle();
|
||||
MyGuiManager.DrawSpriteBatch("Textures\\GUI\\Blank.dds", fullscreenRectangle, Color.Black, false, true);
|
||||
Rectangle outRect;
|
||||
MyGuiManager.GetSafeHeightFullScreenPictureSize(MyGuiConstants.LOADING_BACKGROUND_TEXTURE_REAL_SIZE, out outRect);
|
||||
MyGuiManager.DrawSpriteBatch(LoadingScreenTexture, outRect, new Color(new Vector4(1f, 1f, 1f, m_transitionAlpha)), true, true);
|
||||
MyGuiManager.DrawSpriteBatch("Textures\\Gui\\Screens\\screen_background_fade.dds", outRect, new Color(new Vector4(1f, 1f, 1f, m_transitionAlpha)), true, true);
|
||||
var color = new Color(255, 255, 255, 250);
|
||||
color.A = (byte)(color.A * __instance.m_transitionAlpha);
|
||||
var fullscreenRectangle = MyGuiManager.GetFullscreenRectangle();
|
||||
MyGuiManager.DrawSpriteBatch(@"Textures\GUI\Blank.dds", fullscreenRectangle, Color.Black, false, true);
|
||||
MyGuiManager.GetSafeHeightFullScreenPictureSize(MyGuiConstants.LOADING_BACKGROUND_TEXTURE_REAL_SIZE,
|
||||
out var outRect);
|
||||
MyGuiManager.DrawSpriteBatch(_loadingScreenTexture, outRect,
|
||||
new Color(new Vector4(1f, 1f, 1f, __instance.m_transitionAlpha)), true, true);
|
||||
MyGuiManager.DrawSpriteBatch(@"Textures\Gui\Screens\screen_background_fade.dds", outRect,
|
||||
new Color(new Vector4(1f, 1f, 1f, __instance.m_transitionAlpha)), true, true);
|
||||
|
||||
//MyGuiSandbox.DrawGameLogoHandler(m_transitionAlpha, MyGuiManager.ComputeFullscreenGuiCoordinate(MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, 44, 68));
|
||||
|
||||
string LoadScreen = $"Loading into {ServerName}! Please wait!";
|
||||
var loadScreen = $"Loading into {_serverName}! Please wait!";
|
||||
|
||||
|
||||
MyGuiManager.DrawString(m_font, LoadScreen, new Vector2(0.5f, 0.95f), MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f, new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * m_transitionAlpha), MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM);
|
||||
MyGuiManager.DrawString(MyFontEnum.LoadingScreen, loadScreen, new Vector2(0.5f, 0.95f),
|
||||
MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f,
|
||||
new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * __instance.m_transitionAlpha),
|
||||
MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM);
|
||||
|
||||
MyGuiManager.DrawString(m_font, "Nexus & SeamlessClient Made by: Casimir", new Vector2(0.95f, 0.95f), MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f, new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * m_transitionAlpha), MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM);
|
||||
MyGuiManager.DrawString(MyFontEnum.LoadingScreen, "Nexus & SeamlessClient Made by: Casimir", new Vector2(0.95f, 0.95f),
|
||||
MyGuiSandbox.GetDefaultTextScaleWithLanguage() * 1.1f,
|
||||
new Color(MyGuiConstants.LOADING_PLEASE_WAIT_COLOR * __instance.m_transitionAlpha),
|
||||
MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM);
|
||||
|
||||
/*
|
||||
if (string.IsNullOrEmpty(m_customTextFromConstructor))
|
||||
@@ -279,38 +253,35 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static bool GetCustomLoadingScreenPath(List<MyObjectBuilder_Checkpoint.ModItem> Mods, out string File)
|
||||
private static bool GetCustomLoadingScreenPath(List<MyObjectBuilder_Checkpoint.ModItem> mods, out string file)
|
||||
{
|
||||
File = null;
|
||||
string WorkshopDir = MyFileSystem.ModsPath;
|
||||
List<string> backgrounds = new List<string>();
|
||||
Random r = new Random(DateTime.Now.Millisecond);
|
||||
SeamlessClient.TryShow(WorkshopDir);
|
||||
file = null;
|
||||
var workshopDir = MyFileSystem.ModsPath;
|
||||
var backgrounds = new List<string>();
|
||||
SeamlessClient.TryShow(workshopDir);
|
||||
try
|
||||
{
|
||||
SeamlessClient.TryShow("Installed Mods: " + Mods);
|
||||
foreach (var Mod in Mods)
|
||||
SeamlessClient.TryShow($"Installed Mods: ({mods.Count}) [{string.Join(", ", mods.Select(x => x.FriendlyName))}]");
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
string SearchDir = Mod.GetPath();
|
||||
var searchDir = mod.GetPath();
|
||||
|
||||
if (!Directory.Exists(SearchDir))
|
||||
if (!Directory.Exists(searchDir))
|
||||
continue;
|
||||
|
||||
|
||||
var files = Directory.GetFiles(SearchDir, "CustomLoadingBackground*.dds", SearchOption.TopDirectoryOnly);
|
||||
foreach (var file in files)
|
||||
var files = Directory.GetFiles(searchDir, "CustomLoadingBackground*.dds",
|
||||
SearchOption.TopDirectoryOnly);
|
||||
foreach (var filePath in files)
|
||||
{
|
||||
// Adds all files containing CustomLoadingBackground to a list for later randomisation
|
||||
SeamlessClient.TryShow(Mod.FriendlyName + " contains a custom loading background!");
|
||||
backgrounds.Add(file);
|
||||
|
||||
SeamlessClient.TryShow($"{mod.FriendlyName} contains a custom loading background!");
|
||||
backgrounds.Add(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Randomly pick a loading screen from the available backgrounds
|
||||
var rInt = r.Next(0, backgrounds.Count() - 1);
|
||||
File = backgrounds[rInt];
|
||||
file = backgrounds[Random.Shared.Next(0, backgrounds.Count - 1)];
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -323,117 +294,4 @@ namespace SeamlessClientPlugin.SeamlessTransfer
|
||||
}
|
||||
|
||||
#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 bool OnConnectToServer(MyGameServerItem server, Action<JoinResult> onDone)
|
||||
{
|
||||
if (SeamlessClient.IsSwitching)
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Patch Utils */
|
||||
|
||||
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 PropertyInfo GetProperty(Type type, string PropertyName, BindingFlags Flags)
|
||||
{
|
||||
try
|
||||
{
|
||||
PropertyInfo FoundProperty = type.GetProperty(PropertyName, Flags);
|
||||
|
||||
if (FoundProperty == null)
|
||||
throw new NullReferenceException($"Property for {PropertyName} is null!");
|
||||
|
||||
|
||||
return FoundProperty;
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,16 +1,9 @@
|
||||
using HarmonyLib;
|
||||
using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace SeamlessClientPlugin.Utilities
|
||||
namespace SeamlessClientPlugin.Utilities;
|
||||
|
||||
public static class Utility
|
||||
{
|
||||
public static class Utility
|
||||
{
|
||||
public static byte[] Serialize<T>(T instance)
|
||||
{
|
||||
if (instance == null)
|
||||
@@ -29,18 +22,11 @@ namespace SeamlessClientPlugin.Utilities
|
||||
public static T Deserialize<T>(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
return default(T);
|
||||
return default;
|
||||
|
||||
using (var m = new MemoryStream(data))
|
||||
{
|
||||
return Serializer.Deserialize<T>(m);
|
||||
}
|
||||
}
|
||||
|
||||
public static dynamic CastToReflected(this object o, Type type)
|
||||
{
|
||||
return Convert.ChangeType(o, type);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Lib.Harmony" version="2.2.1" targetFramework="net48" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net472" />
|
||||
</packages>
|
Reference in New Issue
Block a user