@@ -27,7 +27,7 @@ internal static void Init()
2727 Harmony . CreateAndPatchAll ( typeof ( Client ) ) ;
2828 BuildConfig buildConfig = BuildConfigHelper . GetSelectedBuildConfig ( ) ;
2929 buildConfig . buildServerURL = BuildServerURL . Custom ;
30- buildConfig . customServerURL = Plugin . config . backendUrl ;
30+ buildConfig . customServerURL = LOCAL_SERVER_URL ;
3131
3232 Plugin . logger . LogInfo ( $ "Multiplayer> Server URL set to: { Plugin . config . backendUrl } ") ;
3333 Plugin . logger . LogInfo ( "Multiplayer> GLD patches applied" ) ;
@@ -59,130 +59,203 @@ public static void SteamClient_get_SteamId(ref string __result)
5959 }
6060
6161
62- /// <summary>
63- /// After GameState deserialization, check for trailing GLD version ID and set mockedGameLogicData.
64- /// The server appends "##GLD:" + modGldVersion (int) after the normal serialized data.
65- /// </summary>
66- [ HarmonyPostfix ]
67- [ HarmonyPatch ( typeof ( GameState ) , nameof ( GameState . Deserialize ) ) ]
68- private static void Deserialize_Postfix ( GameState __instance , BinaryReader __0 )
69- {
70- if ( ! allowGldMods ) return ;
62+ // /// <summary>
63+ // /// After GameState deserialization, check for trailing GLD version ID and set mockedGameLogicData.
64+ // /// The server appends "##GLD:" + modGldVersion (int) after the normal serialized data.
65+ // /// </summary>
66+ // [HarmonyPostfix]
67+ // [HarmonyPatch(typeof(GameState), nameof(GameState.Deserialize))]
68+ // private static void Deserialize_Postfix(GameState __instance, BinaryReader __0)
69+ // {
70+ // if(!allowGldMods) return;
71+
72+ // Plugin.logger?.LogDebug("Deserialize_Postfix: Entered");
73+
74+ // try
75+ // {
76+ // var reader = __0;
77+ // if (reader == null)
78+ // {
79+ // Plugin.logger?.LogWarning("Deserialize_Postfix: reader is null");
80+ // return;
81+ // }
82+
83+ // var position = reader.BaseStream.Position;
84+ // var length = reader.BaseStream.Length;
85+ // var remaining = length - position;
86+
87+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Stream position={position}, length={length}, remaining={remaining}");
88+
89+ // // Check if there's more data after normal deserialization
90+ // if (position >= length)
91+ // {
92+ // Plugin.logger?.LogDebug("Deserialize_Postfix: No trailing data (position >= length)");
93+
94+ // var sd = __instance.Seed;
95+ // if (_gldCache.TryGetValue(sd, out var cachedGld))
96+ // {
97+ // __instance.mockedGameLogicData = cachedGld;
98+ // var cachedVersion = _versionCache.GetValueOrDefault(sd, -1);
99+ // Plugin.logger?.LogInfo($"Deserialize_Postfix: Applied cached GLD for Seed={sd}, ModGldVersion={cachedVersion}");
100+ // }
101+ // return;
102+ // }
103+
104+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Found {remaining} bytes of trailing data, attempting to read marker");
105+
106+ // var marker = reader.ReadString();
107+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Read marker string: '{marker}'");
108+
109+ // if (marker != GldMarker)
110+ // {
111+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Marker mismatch - expected '{GldMarker}', got '{marker}'");
112+ // return;
113+ // }
114+
115+ // Plugin.logger?.LogInfo($"Deserialize_Postfix: Found GLD marker '{GldMarker}'");
116+
117+ // var modGldVersion = reader.ReadInt32();
118+ // Plugin.logger?.LogInfo($"Deserialize_Postfix: Found embedded ModGldVersion: {modGldVersion}");
119+
120+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Fetching GLD from server for version {modGldVersion}");
121+ // var gldJson = FetchGldById(modGldVersion);
122+ // if (string.IsNullOrEmpty(gldJson))
123+ // {
124+ // Plugin.logger?.LogError($"Deserialize_Postfix: Failed to fetch GLD for ModGldVersion: {modGldVersion}");
125+ // return;
126+ // }
127+
128+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Parsing GLD JSON ({gldJson.Length} chars)");
129+
130+ // var customGld = new GameLogicData();
131+ // customGld.Parse(gldJson);
132+ // __instance.mockedGameLogicData = customGld;
133+
134+ // // Cache for subsequent deserializations (rewinds, reloads)
135+ // var seed = __instance.Seed;
136+ // _gldCache[seed] = customGld;
137+ // _versionCache[seed] = modGldVersion;
138+
139+ // Plugin.logger?.LogInfo($"Deserialize_Postfix: Successfully set mockedGameLogicData from ModGldVersion: {modGldVersion}, cached for Seed={seed}");
140+ // }
141+ // catch (EndOfStreamException)
142+ // {
143+ // Plugin.logger?.LogDebug("Deserialize_Postfix: EndOfStreamException - no trailing data");
144+ // }
145+ // catch (Exception ex)
146+ // {
147+ // Plugin.logger?.LogError($"Deserialize_Postfix: Exception: {ex.GetType().Name}: {ex.Message}");
148+ // Plugin.logger?.LogDebug($"Deserialize_Postfix: Stack trace: {ex.StackTrace}");
149+ // }
150+ // }
151+
152+ // /// <summary>
153+ // /// Fetch GLD from server using ModGldVersion ID
154+ // /// </summary>
155+ // private static string? FetchGldById(int modGldVersion)
156+ // {
157+ // if(!allowGldMods) return null;
158+ // try
159+ // {
160+ // using var client = new HttpClient();
161+ // var url = $"{Plugin.config.backendUrl.TrimEnd('/')}/api/mods/gld/{modGldVersion}";
162+ // Plugin.logger?.LogDebug($"FetchGldById: Requesting URL: {url}");
163+
164+ // var response = client.GetAsync(url).Result;
165+ // Plugin.logger?.LogDebug($"FetchGldById: Response status: {response.StatusCode}");
166+
167+ // if (response.IsSuccessStatusCode)
168+ // {
169+ // var gld = response.Content.ReadAsStringAsync().Result;
170+ // Plugin.logger?.LogInfo($"FetchGldById: Successfully fetched mod GLD ({gld.Length} chars)");
171+ // return gld;
172+ // }
173+
174+ // var errorContent = response.Content.ReadAsStringAsync().Result;
175+ // Plugin.logger?.LogError($"FetchGldById: Failed with status {response.StatusCode}: {errorContent}");
176+ // }
177+ // catch (Exception ex)
178+ // {
179+ // Plugin.logger?.LogError($"FetchGldById: Exception: {ex.GetType().Name}: {ex.Message}");
180+ // if (ex.InnerException != null)
181+ // {
182+ // Plugin.logger?.LogError($"FetchGldById: Inner exception: {ex.InnerException.Message}");
183+ // }
184+ // }
185+ // return null;
186+ // }
71187
72- Plugin . logger ? . LogDebug ( "Deserialize_Postfix: Entered" ) ;
73-
74- try
75- {
76- var reader = __0 ;
77- if ( reader == null )
78- {
79- Plugin . logger ? . LogWarning ( "Deserialize_Postfix: reader is null" ) ;
80- return ;
81- }
82-
83- var position = reader . BaseStream . Position ;
84- var length = reader . BaseStream . Length ;
85- var remaining = length - position ;
86-
87- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Stream position={ position } , length={ length } , remaining={ remaining } ") ;
188+ [ HarmonyPrefix ]
189+ [ HarmonyPatch ( typeof ( ClientBase ) , nameof ( ClientBase . SendCommand ) ) ]
190+ private static bool ClientBase_SendCommand (
191+ ClientBase __instance ,
192+ CommandBase command )
193+ {
88194
89- // Check if there's more data after normal deserialization
90- if ( position >= length )
91- {
92- Plugin . logger ? . LogDebug ( "Deserialize_Postfix: No trailing data (position >= length)" ) ;
195+ Plugin . logger . LogInfo ( "Multiplayer> ClientBase_SendCommand" ) ;
196+ Il2CppSystem . Threading . Tasks . Task < ServerResponse < BoolResponseViewModel > > task = new ( ) ;
197+ var taskCompletionSource = new Il2CppSystem . Threading . Tasks . TaskCompletionSource < ServerResponse < BoolResponseViewModel > > ( ) ;
93198
94- var sd = __instance . Seed ;
95- if ( _gldCache . TryGetValue ( sd , out var cachedGld ) )
96- {
97- __instance . mockedGameLogicData = cachedGld ;
98- var cachedVersion = _versionCache . GetValueOrDefault ( sd , - 1 ) ;
99- Plugin . logger ? . LogInfo ( $ "Deserialize_Postfix: Applied cached GLD for Seed={ sd } , ModGldVersion={ cachedVersion } ") ;
100- }
101- return ;
102- }
199+ _ = HandleSendCommandModded ( taskCompletionSource , __instance , command ) ;
103200
104- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Found { remaining } bytes of trailing data, attempting to read marker" ) ;
201+ task = taskCompletionSource . Task ;
105202
106- var marker = reader . ReadString ( ) ;
107- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Read marker string: ' { marker } '" ) ;
203+ return false ;
204+ }
108205
109- if ( marker != GldMarker )
206+ private static async System . Threading . Tasks . Task HandleSendCommandModded (
207+ Il2CppSystem . Threading . Tasks . TaskCompletionSource < ServerResponse < BoolResponseViewModel > > tcs ,
208+ ClientBase client ,
209+ CommandBase command )
210+ {
211+ try
212+ {
213+ if ( ! client . CurrentGameId . HasValue )
110214 {
111- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Marker mismatch - expected ' { GldMarker } ', got ' { marker } ' ") ;
215+ Console . Write ( "Tried to perform and send command but no GameId was set ") ;
112216 return ;
113217 }
114-
115- Plugin . logger ? . LogInfo ( $ "Deserialize_Postfix: Found GLD marker '{ GldMarker } '") ;
116-
117- var modGldVersion = reader . ReadInt32 ( ) ;
118- Plugin . logger ? . LogInfo ( $ "Deserialize_Postfix: Found embedded ModGldVersion: { modGldVersion } ") ;
119-
120- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Fetching GLD from server for version { modGldVersion } ") ;
121- var gldJson = FetchGldById ( modGldVersion ) ;
122- if ( string . IsNullOrEmpty ( gldJson ) )
218+ if ( ! ClientActionManager . CanReceiveCommand ( command , client . GameState ) )
123219 {
124- Plugin . logger ? . LogError ( $ "Deserialize_Postfix: Failed to fetch GLD for ModGldVersion: { modGldVersion } ") ;
220+ Console . Write ( "Tried to send invalid command ") ;
125221 return ;
126222 }
223+ uint currentResetId = client . resets ;
224+ int count = client . GameState . CommandStack . Count ;
225+ var list = new Il2CppSystem . Collections . Generic . List < CommandBase > ( ) ;
226+ list . Add ( command ) ;
227+ client . ActionManager . ExecuteCommands ( list ) ;
228+ await client . SendCommandToServer ( command , count ) ;
127229
128- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Parsing GLD JSON ( { gldJson . Length } chars)" ) ;
230+ var serializedGameState = SerializationHelpers . ToByteArray ( client . GameState , client . GameState . Version ) ;
129231
130- var customGld = new GameLogicData ( ) ;
131- customGld . Parse ( gldJson ) ;
132- __instance . mockedGameLogicData = customGld ;
232+ var succ = GameStateSummary . FromGameStateByteArray ( serializedGameState ,
233+ out GameStateSummary stateSummary , out var gameState ) ;
133234
134- // Cache for subsequent deserializations (rewinds, reloads)
135- var seed = __instance . Seed ;
136- _gldCache [ seed ] = customGld ;
137- _versionCache [ seed ] = modGldVersion ;
235+ var serializedGameSummary = SerializationHelpers . ToByteArray ( stateSummary , gameState . Version ) ;
138236
139- Plugin . logger ? . LogInfo ( $ "Deserialize_Postfix: Successfully set mockedGameLogicData from ModGldVersion: { modGldVersion } , cached for Seed={ seed } ") ;
140- }
141- catch ( EndOfStreamException )
142- {
143- Plugin . logger ? . LogDebug ( "Deserialize_Postfix: EndOfStreamException - no trailing data" ) ;
144- }
145- catch ( Exception ex )
146- {
147- Plugin . logger ? . LogError ( $ "Deserialize_Postfix: Exception: { ex . GetType ( ) . Name } : { ex . Message } ") ;
148- Plugin . logger ? . LogDebug ( $ "Deserialize_Postfix: Stack trace: { ex . StackTrace } ") ;
149- }
150- }
151-
152- /// <summary>
153- /// Fetch GLD from server using ModGldVersion ID
154- /// </summary>
155- private static string ? FetchGldById ( int modGldVersion )
156- {
157- if ( ! allowGldMods ) return null ;
158- try
159- {
160- using var client = new HttpClient ( ) ;
161- var url = $ "{ Plugin . config . backendUrl . TrimEnd ( '/' ) } /api/mods/gld/{ modGldVersion } ";
162- Plugin . logger ? . LogDebug ( $ "FetchGldById: Requesting URL: { url } ") ;
163-
164- var response = client . GetAsync ( url ) . Result ;
165- Plugin . logger ? . LogDebug ( $ "FetchGldById: Response status: { response . StatusCode } ") ;
166-
167- if ( response . IsSuccessStatusCode )
237+ var setupGameDataViewModel = new SetupGameStateViewModel
168238 {
169- var gld = response . Content . ReadAsStringAsync ( ) . Result ;
170- Plugin . logger ? . LogInfo ( $ "FetchGldById: Successfully fetched mod GLD ({ gld . Length } chars)") ;
171- return gld ;
172- }
239+ gameId = client . gameId . ToString ( ) ,
240+ serializedGameState = serializedGameState ,
241+ serializedGameSummary = serializedGameSummary ,
242+ gameSettingsJson = ""
243+ } ;
244+
245+ var setupData = System . Text . Json . JsonSerializer . Serialize ( setupGameDataViewModel ) ;
173246
174- var errorContent = response . Content . ReadAsStringAsync ( ) . Result ;
175- Plugin . logger ? . LogError ( $ "FetchGldById: Failed with status { response . StatusCode } : { errorContent } ") ;
247+ var serverResponse = await PolytopiaBackendAdapter . Instance . HubConnection . InvokeAsync < ServerResponse < BoolResponseViewModel > > (
248+ "UpdateGameStateModded" ,
249+ setupData ,
250+ Il2CppSystem . Threading . CancellationToken . None
251+ ) ;
252+ tcs . SetResult ( serverResponse ) ;
176253 }
177254 catch ( Exception ex )
178255 {
179- Plugin . logger ? . LogError ( $ "FetchGldById: Exception: { ex . GetType ( ) . Name } : { ex . Message } ") ;
180- if ( ex . InnerException != null )
181- {
182- Plugin . logger ? . LogError ( $ "FetchGldById: Inner exception: { ex . InnerException . Message } ") ;
183- }
256+ Plugin . logger . LogError ( "Multiplayer> Error during HandleSendCommandModded: " + ex . Message ) ;
257+ tcs . SetException ( new Il2CppSystem . Exception ( ex . Message ) ) ;
184258 }
185- return null ;
186259 }
187260
188261 [ HarmonyPrefix ]
@@ -226,10 +299,15 @@ private static async System.Threading.Tasks.Task HandleStartLobbyGameModded(
226299
227300 Plugin . logger . LogInfo ( "Multiplayer> GameState and Settiings created" ) ;
228301
229- var setupGameDataViewModel = new SetupGameDataViewModel
302+ var succ = GameStateSummary . FromGameStateByteArray ( serializedGameState ,
303+ out GameStateSummary stateSummary , out var gameState ) ;
304+
305+ var serializedGameSummary = SerializationHelpers . ToByteArray ( stateSummary , gameState . Version ) ;
306+ var setupGameDataViewModel = new SetupGameStateViewModel
230307 {
231308 lobbyId = lobbyGameViewModel . Id . ToString ( ) ,
232309 serializedGameState = serializedGameState ,
310+ serializedGameSummary = serializedGameSummary ,
233311 gameSettingsJson = gameSettingsJson
234312 } ;
235313
0 commit comments