diff --git a/scripts/client/nodes/PlanetNode.as b/scripts/client/nodes/PlanetNode.as index df364e91..14146288 100644 --- a/scripts/client/nodes/PlanetNode.as +++ b/scripts/client/nodes/PlanetNode.as @@ -262,6 +262,19 @@ class DynTex { return; } + // Try to fail more gracefully than causing a CTD if the + // grid size is wrong + // If the netcode messes up this can sometimes be way larger than any + // actual grid size. In that scenario, trying to create the Image + // can easily cause a Crash To Desktop and completely stop the game. + if (size.x > 3000 || size.y > 3000) { + print("Read grid size that is way too high, aborting texture cache to avoid CTD"); + print(string(size.x)+"x"+string(size.y)); + print("Has the netcode or PlanetSurface gone haywire?"); + @this.obj = null; + return; + } + Image img(size, 4); uint shown = obj.getSurfaceData(img); diff --git a/scripts/server/planets/SurfaceComponent.as b/scripts/server/planets/SurfaceComponent.as index 3d9482e0..ed69e5d6 100644 --- a/scripts/server/planets/SurfaceComponent.as +++ b/scripts/server/planets/SurfaceComponent.as @@ -2591,6 +2591,17 @@ tidy class SurfaceComponent : Component_SurfaceComponent, Savable { msg.write0(); } msg.writeBit(needsPopulationForLevel); + // Tell the client the LevelChainId before it tries to use it, fixes + // bug where the client was reading the max level of a planet before + // it found out the level chain of that planet. This meant that any + // planet with a level chain that had a different max level to the + // level chain with an id of 0 would be decoded incorrectly, and offset + // the rest of the message by some number of bits, completely breaking + // all decoding that followed. In the worst case, the broken decoding + // would cause a Crash To Desktop as the PlanetNode tried to create + // an Image with a ludicrous size, or the PlanetSurface tried to + // create an array for a ludicrous grid size that ran out of memory. + msg.writeLimited(LevelChainId,getLevelChainCount()); msg.writeLimited(ResourceLevel,maxLevel); msg.writeBit(isSendingColonizers); } diff --git a/scripts/shadow/planets/SurfaceComponent.as b/scripts/shadow/planets/SurfaceComponent.as index 6b79b76e..59ee8a78 100644 --- a/scripts/shadow/planets/SurfaceComponent.as +++ b/scripts/shadow/planets/SurfaceComponent.as @@ -435,6 +435,17 @@ tidy class SurfaceComponent : Component_SurfaceComponent { growthRate = 1.0; needsPopulationForLevel = msg.readBit(); + // Tell the client the LevelChainId before it tries to use it, fixes + // bug where the client was reading the max level of a planet before + // it found out the level chain of that planet. This meant that any + // planet with a level chain that had a different max level to the + // level chain with an id of 0 would be decoded incorrectly, and offset + // the rest of the message by some number of bits, completely breaking + // all decoding that followed. In the worst case, the broken decoding + // would cause a Crash To Desktop as the PlanetNode tried to create + // an Image with a ludicrous size, or the PlanetSurface tried to + // create an array for a ludicrous grid size that ran out of memory. + LevelChainId = msg.readLimited(getLevelChainCount()); int maxLevel = getLevelChain(LevelChainId).levels.length-1; ResourceLevel = msg.readLimited(maxLevel);