forked from austinvaness/SeamlessClientPlugin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSeamlessClient.cs
More file actions
218 lines (177 loc) · 8.67 KB
/
SeamlessClient.cs
File metadata and controls
218 lines (177 loc) · 8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
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.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;
namespace SeamlessClientPlugin
{
//SendAllMembersDataToClient
public class SeamlessClient : IPlugin
{
/* 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.
* Then JoinLobby is called. This looks to be simply a check to see if the client gets a result from the server. If it does, it initilizes a new STATIC/Multiplayer base by: [Static = new MyMultiplayerLobbyClient(lobby, new MySyncLayer(new MyTransportLayer(2)))));]
* Once this above method is done and join is done, we begin the OnJoin()
*
* On join begins by checking join result. Success downloads world and failed sends you back to menu. (May need to use this to send players to menu)
* Download world Requires the multiplayerbase and MyGUIScreenProgress. Which is essentially checking that the user hasnt cliecked left or closed.
*
* StringBuilder text = MyTexts.Get(MyCommonTexts.DialogTextJoiningWorld);
* MyGuiScreenProgress progress = new MyGuiScreenProgress(text, MyCommonTexts.Cancel);
*
* This just looks to be like what happens still with the little GUI popupscreen before load starts
*
* DownloadWorld also contains a method to get the serversessionstate too. We will need to check this before load. Ultimatley once everything has passed join checks Downloadworld is called. (MyMultiplayerClientBase.DownloadWorld)
*
*
* MyMultiplayerClientBase.DownloadWorld simply rasies a static event to the server for world request. [return MyMultiplayerServerBase.WorldRequest;]
*
*
*
*
* MyMultiplayerServerBase.WorldRequest (WorldRequest) This is near the start of where the magic happens. THIS IS ALL RAN SERVERSIDE
* Checks to see if the client has been kicked or banned to prevent world requests. Not sure we really need to worry about this.
*
* Server gets world clears non important data such as player gps. Our player gps gets added on join so we can yeet this.
* Also theres a sendfluch via transport layer. Might need to keep this in mind and use this for our testings
* Theres a CleanUpData that gets called with world and playerid/identity ID. This is probably to limit things and only send whats neccessary
* CLEANUPDATA shows me how to send allplayers data synced on the server.
*
*
* Once we have everythings we use a MS to serialize everything to byte[] and via replication layer we send world to client.
*
*
* BACK TO CLIENT:
* RecieveWorld is called and packet is deserialized and then MyJoinGameHelper.WorldReceived(...,...) is called
*
* WorldReceived does some checks for extra version mismatches and to make sure the CheckPointObjectBuilder isnt null etc.
* Once it passes all these checks, CheckDx11AndJoin(world, MyMutliplayerBase) is called
*
* CheckDx11AndJoin just checks if its a scenario world or not. Forget about this. We can figure that out all later. Then it runs: MySessionLoader.LoadMultiplayerSession(world, multiplayer);
*
*
* MySessionLoader.LoadMultiplayerSession looks to be the start of the join code. It also checks for mod mismatches. (And Downloads them). However once it passes this, MySession.LoadMultiplayer is called.
*
*
*
*
*
*
*
* MySession.LoadMultiplayer (The most important step in world loading)
* Creates new MySession.
* Does settings stuff.
* LoadMembersFromWorld (Loads Clients)
* FixSessionComponentObjectBuilders
*
*
*
* PrepareBaseSession is something we need. Looks like it does some weird stuff to init fonts, Sector Enviroment settings, Loading datacomponents from world, and re-initilizes modAPI stuff
* DeserializeClusters
* Loads planets.
* RegistersChat
*
* LOADWORLD -----------
* Static.BeforeStartComponents
*
*
*
*
* -plugin "../Plugins/SeamlessClientPlugin.dll"
*/
public static string Version = "1.4.01";
public static bool Debug = true;
private static bool Initilized = false;
public const ushort SeamlessClientNetID = 2936;
public static bool IsSwitching = false;
public static bool RanJoin = false;
public void Init(object gameInstance)
{
TryShow("Running Seamless Client Plugin v[" + Version + "]");
}
public void Update()
{
if (MyAPIGateway.Multiplayer == null)
return;
if (!Initilized)
{
Patches.GetPatches();
OnlinePlayers.Patch();
TryShow("Initilizing Communications!");
RunInitilizations();
}
}
public static void RunInitilizations()
{
MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(SeamlessClientNetID, MessageHandler);
Initilized = true;
}
public static void DisposeInitilizations()
{
MyAPIGateway.Multiplayer?.UnregisterSecureMessageHandler(SeamlessClientNetID, MessageHandler);
Initilized = false;
}
private static void MessageHandler(ushort obj1, byte[] obj2, ulong obj3, bool obj4)
{
try
{
ClientMessage Recieved = Utilities.Utility.Deserialize<ClientMessage>(obj2);
if(Recieved.MessageType == ClientMessageType.FirstJoin)
{
//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));
}
else if (Recieved.MessageType == 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 p = Recieved.GetOnlinePlayers();
OnlinePlayers.AllServers = p.OnlineServers;
OnlinePlayers.currentServer = p.currentServerID;
//TryShow("Recieved Players! "+OnlinePlayers.AllServers.Count);
}
}
catch (Exception ex)
{
TryShow(ex.ToString());
}
}
public static void TryShow(string message)
{
if (MySession.Static?.LocalHumanPlayer != null && Debug)
MyAPIGateway.Utilities?.ShowMessage("NetworkClient", message);
MyLog.Default?.WriteLineAndConsole($"SeamlessClient: {message}");
}
public void Dispose()
{
DisposeInitilizations();
}
}
}