1- using BepInEx . Logging ;
1+ using System . Collections . Generic ;
2+ using System . Net . Http ;
23using System . Text . Json ;
4+ using BepInEx . Logging ;
5+ using HarmonyLib ;
6+ using Polytopia . Data ;
7+ using Il2CppSystem . IO ;
8+ using BinaryReader = Il2CppSystem . IO . BinaryReader ;
9+ using EndOfStreamException = System . IO . EndOfStreamException ;
310
411namespace DystopiaPolyScript ;
512
613public class ServerConfig
714{
8- public string ServerUrl { get ; init ; } = "http ://localhost:5051 " ;
15+ public string ServerUrl { get ; init ; } = "https ://dev.polydystopia.xyz " ;
916}
1017
1118public static class Main
1219{
1320 private const string CONFIG_FILE_NAME = "polydystopia_server_config.json" ;
14- private const string DEFAULT_SERVER_URL = "http://localhost:5051" ;
21+ private const string DEFAULT_SERVER_URL = "https://dev.polydystopia.xyz" ;
22+ private const string GldMarker = "##GLD:" ;
23+
24+ private static string _serverUrl = DEFAULT_SERVER_URL ;
25+ private static ManualLogSource _logger = null ! ;
26+
27+ // Cache parsed GLD by game Seed to handle rewinds/reloads
28+ private static readonly Dictionary < int , GameLogicData > _gldCache = new ( ) ;
29+ private static readonly Dictionary < int , int > _versionCache = new ( ) ; // Seed -> modGldVersion
1530
1631 public static void Load ( ManualLogSource logger )
1732 {
18- var serverUrl = LoadServerUrlFromFile ( logger ) ;
33+ _logger = logger ;
34+ _serverUrl = LoadServerUrlFromFile ( logger ) ;
1935
2036 BuildConfigHelper . GetSelectedBuildConfig ( ) . buildServerURL = BuildServerURL . Custom ;
21- BuildConfigHelper . GetSelectedBuildConfig ( ) . customServerURL = serverUrl ;
37+ BuildConfigHelper . GetSelectedBuildConfig ( ) . customServerURL = _serverUrl ;
2238
23- logger . LogInfo ( $ "Polydystopia> Server URL set to: { serverUrl } ") ;
39+ // Apply Harmony patches
40+ Harmony . CreateAndPatchAll ( typeof ( Main ) ) ;
41+
42+ logger . LogInfo ( $ "Polydystopia> Server URL set to: { _serverUrl } ") ;
43+ logger . LogInfo ( "Polydystopia> GLD patches applied" ) ;
44+ }
45+
46+ /// <summary>
47+ /// After GameState deserialization, check for trailing GLD version ID and set mockedGameLogicData.
48+ /// The server appends "##GLD:" + modGldVersion (int) after the normal serialized data.
49+ /// </summary>
50+ [ HarmonyPostfix ]
51+ [ HarmonyPatch ( typeof ( GameState ) , nameof ( GameState . Deserialize ) ) ]
52+ private static void Deserialize_Postfix ( GameState __instance , BinaryReader __0 )
53+ {
54+ _logger ? . LogDebug ( "Deserialize_Postfix: Entered" ) ;
55+
56+ try
57+ {
58+ var reader = __0 ;
59+ if ( reader == null )
60+ {
61+ _logger ? . LogWarning ( "Deserialize_Postfix: reader is null" ) ;
62+ return ;
63+ }
64+
65+ var position = reader . BaseStream . Position ;
66+ var length = reader . BaseStream . Length ;
67+ var remaining = length - position ;
68+
69+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Stream position={ position } , length={ length } , remaining={ remaining } ") ;
70+
71+ // Check if there's more data after normal deserialization
72+ if ( position >= length )
73+ {
74+ _logger ? . LogDebug ( "Deserialize_Postfix: No trailing data (position >= length)" ) ;
75+
76+ var sd = __instance . Seed ;
77+ if ( _gldCache . TryGetValue ( sd , out var cachedGld ) )
78+ {
79+ __instance . mockedGameLogicData = cachedGld ;
80+ var cachedVersion = _versionCache . GetValueOrDefault ( sd , - 1 ) ;
81+ _logger ? . LogInfo ( $ "Deserialize_Postfix: Applied cached GLD for Seed={ sd } , ModGldVersion={ cachedVersion } ") ;
82+ }
83+ return ;
84+ }
85+
86+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Found { remaining } bytes of trailing data, attempting to read marker") ;
87+
88+ var marker = reader . ReadString ( ) ;
89+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Read marker string: '{ marker } '") ;
90+
91+ if ( marker != GldMarker )
92+ {
93+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Marker mismatch - expected '{ GldMarker } ', got '{ marker } '") ;
94+ return ;
95+ }
96+
97+ _logger ? . LogInfo ( $ "Deserialize_Postfix: Found GLD marker '{ GldMarker } '") ;
98+
99+ var modGldVersion = reader . ReadInt32 ( ) ;
100+ _logger ? . LogInfo ( $ "Deserialize_Postfix: Found embedded ModGldVersion: { modGldVersion } ") ;
101+
102+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Fetching GLD from server for version { modGldVersion } ") ;
103+ var gldJson = FetchGldById ( modGldVersion ) ;
104+ if ( string . IsNullOrEmpty ( gldJson ) )
105+ {
106+ _logger ? . LogError ( $ "Deserialize_Postfix: Failed to fetch GLD for ModGldVersion: { modGldVersion } ") ;
107+ return ;
108+ }
109+
110+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Parsing GLD JSON ({ gldJson . Length } chars)") ;
111+
112+ var customGld = new GameLogicData ( ) ;
113+ customGld . Parse ( gldJson ) ;
114+ __instance . mockedGameLogicData = customGld ;
115+
116+ // Cache for subsequent deserializations (rewinds, reloads)
117+ var seed = __instance . Seed ;
118+ _gldCache [ seed ] = customGld ;
119+ _versionCache [ seed ] = modGldVersion ;
120+
121+ _logger ? . LogInfo ( $ "Deserialize_Postfix: Successfully set mockedGameLogicData from ModGldVersion: { modGldVersion } , cached for Seed={ seed } ") ;
122+ }
123+ catch ( EndOfStreamException )
124+ {
125+ _logger ? . LogDebug ( "Deserialize_Postfix: EndOfStreamException - no trailing data" ) ;
126+ }
127+ catch ( Exception ex )
128+ {
129+ _logger ? . LogError ( $ "Deserialize_Postfix: Exception: { ex . GetType ( ) . Name } : { ex . Message } ") ;
130+ _logger ? . LogDebug ( $ "Deserialize_Postfix: Stack trace: { ex . StackTrace } ") ;
131+ }
132+ }
133+
134+ /// <summary>
135+ /// Fetch GLD from server using ModGldVersion ID
136+ /// </summary>
137+ private static string ? FetchGldById ( int modGldVersion )
138+ {
139+ try
140+ {
141+ using var client = new HttpClient ( ) ;
142+ var url = $ "{ _serverUrl . TrimEnd ( '/' ) } /api/mods/gld/{ modGldVersion } ";
143+ _logger ? . LogDebug ( $ "FetchGldById: Requesting URL: { url } ") ;
144+
145+ var response = client . GetAsync ( url ) . Result ;
146+ _logger ? . LogDebug ( $ "FetchGldById: Response status: { response . StatusCode } ") ;
147+
148+ if ( response . IsSuccessStatusCode )
149+ {
150+ var gld = response . Content . ReadAsStringAsync ( ) . Result ;
151+ _logger ? . LogInfo ( $ "FetchGldById: Successfully fetched mod GLD ({ gld . Length } chars)") ;
152+ return gld ;
153+ }
154+
155+ var errorContent = response . Content . ReadAsStringAsync ( ) . Result ;
156+ _logger ? . LogError ( $ "FetchGldById: Failed with status { response . StatusCode } : { errorContent } ") ;
157+ }
158+ catch ( Exception ex )
159+ {
160+ _logger ? . LogError ( $ "FetchGldById: Exception: { ex . GetType ( ) . Name } : { ex . Message } ") ;
161+ if ( ex . InnerException != null )
162+ {
163+ _logger ? . LogError ( $ "FetchGldById: Inner exception: { ex . InnerException . Message } ") ;
164+ }
165+ }
166+ return null ;
24167 }
25168
26169 private static string LoadServerUrlFromFile ( ManualLogSource logger )
27170 {
28171 try
29172 {
30- if ( File . Exists ( CONFIG_FILE_NAME ) )
173+ if ( System . IO . File . Exists ( CONFIG_FILE_NAME ) )
31174 {
32- var jsonContent = File . ReadAllText ( CONFIG_FILE_NAME ) ;
175+ var jsonContent = System . IO . File . ReadAllText ( CONFIG_FILE_NAME ) ;
33176 var config = JsonSerializer . Deserialize < ServerConfig > ( jsonContent ) ;
34177
35178 if ( config != null && ! string . IsNullOrEmpty ( config . ServerUrl ) )
36179 {
37- logger . LogInfo ( $ "Loaded server URL from { CONFIG_FILE_NAME } : { config . ServerUrl } ") ;
180+ logger . LogInfo ( $ "Polydystopia> Loaded server URL from { CONFIG_FILE_NAME } : { config . ServerUrl } ") ;
38181 return config . ServerUrl ;
39182 }
40183 }
41184
42185 var defaultConfig = new ServerConfig { ServerUrl = DEFAULT_SERVER_URL } ;
43- var defaultJson =
44- JsonSerializer . Serialize ( defaultConfig , new JsonSerializerOptions { WriteIndented = true } ) ;
45- File . WriteAllText ( CONFIG_FILE_NAME , defaultJson ) ;
186+ var defaultJson = JsonSerializer . Serialize ( defaultConfig , new JsonSerializerOptions { WriteIndented = true } ) ;
187+ System . IO . File . WriteAllText ( CONFIG_FILE_NAME , defaultJson ) ;
46188 logger . LogInfo ( $ "Polydystopia> Created default config file { CONFIG_FILE_NAME } with URL: { DEFAULT_SERVER_URL } ") ;
47189
48190 return DEFAULT_SERVER_URL ;
49191 }
50192 catch ( Exception ex )
51193 {
52194 logger . LogError ( $ "Polydystopia> Error reading config file: { ex . Message } . Using default URL: { DEFAULT_SERVER_URL } ") ;
53-
54195 return DEFAULT_SERVER_URL ;
55196 }
56197 }
57- }
198+ }
0 commit comments