Conversation
Content patching moved out of GameState.patcher (DataPatcher) into GameState.data (DataManager) in build 159: patches are PatchAsset objects now, and apply(Seq<String>) became reloadPatches(Seq<PatchAsset>). The 'Mindurka Default Patch' name check still works -- DataPatcher keeps reading the 'name' key into PatchAsset.name. TerminalInput: the server jar now bundles JLine 4.0.0, whose TerminalBuilder has no jna() (providers are ffm/jni). Dropped the call; provider selection is automatic. build.gradle: jar.archivePath was removed in Gradle 9.
syncBuild sent Consts.syncStream.bytes. ReusableByteOutStream.getBytes() returns the backing buffer, whose length is the capacity, not the number of bytes written -- so every block snapshot carried the whole buffer (which only ever grows) instead of the ~30 bytes of the building. Vanilla uses toByteArray(); so do we now. syncBuilds(con, builds) batches to 800 bytes per packet like NetServer's own block snapshot loop, for callers that need to resync many buildings at once. Calling syncBuild in a loop overflows the UDP write buffer and arcnet drops the connection.
On join a timer re-sent the whole live ruleset: Call.setRules(con, Vars.state.rules). TypeIO.writeRules serializes Rules as one JSON blob, and arcnet serializes a single object into a 16384-byte buffer (ArcNetProvider: new Server(..., 16384, ...)). Castle keeps its turret/miner tables and 5x5 schematics in Rules.tags, so that blob did not fit: BufferOverflowException inside TcpConnection.send, arcnet closed the connection itself, the player saw 'connection closed' and the server log stayed clean -- arcnet reports that through ArcNet.errorHandler, which only prints at debug level. Now a copy is sent with tags cleared. Nothing in mindustry/core reads Rules.tags on the client, and the client already received them with the world; mdrk.* entries are server-side gamemode config. The serialized size is checked against a 15000-byte limit first, and going over logs a warning instead of silently dropping the player.
Previous commit cleared Rules.tags outright. Wrong: setRules replaces the client's Rules object wholesale, so that also wiped the mdrk.* tags the compat client reads and that the world had already delivered. Now tags are packed smallest-first until the ruleset reaches the packet limit, and anything left over is named in a warning. mdrk.format and mdrk.gamemode are a few bytes, so they always make it; what gets cut is the per-gamemode tables (castle turrets/miners, forts plot schematics).
Call.setRules is called from more than the join timer -- forts broadcasts it whenever a modifier is added or removed -- so the size guard has to live where every caller can reach it, not inside CorePlugin. syncRules(con) sends to one connection, syncRules() to everyone, and it now refuses to send at all when the ruleset is over the limit before tags are even added: dropping the refresh beats dropping every client.
Two things were wrong with syncRules. The budget was counted in String.length, but TypeIO.writeRules sends JsonIO.write(rules).getBytes(charset) and Vars.charset is UTF-8, so one Cyrillic character costs two of the bytes being budgeted. Between the 15000 limit and arcnet's 16384-byte object buffer there is 1384 bytes of slack, so about 690 non-ASCII characters in the surviving tags were enough for the guard to pass and the packet to still overflow -- the failure it exists to prevent. Sizes now go through utf8Size(), which counts without encoding into a throwaway array. The castle maps in the repo are pure ASCII (22193/17073/17622/55538 B, zero non-ASCII), so this was latent, not live. Rules.copy() was a JSON write plus a parse of the whole 7-22 kB ruleset on every call -- "Not efficient at all, do not use often", per Rules.java itself -- and forts calls this on every modifier toggle. The live ruleset is now borrowed and its tags put back in a finally, which is safe because Call.setRules serializes on the calling thread before it returns (Call -> Net.send -> ArcConnection.send -> Connection.sendTCP -> TcpConnection.send -> serialization.write). Three JSON passes and a parse drop to two passes and no copy. Tag costs are also computed once per tag instead of once per comparison. Three smaller things in the same file, all from the same review: - syncBuild(con, build) swallowed every exception with an empty catch; it now logs the building, like syncBuilds next to it. - syncBuilds used flush() where vanilla's writeBlockSnapshots and syncBuild use close(). - syncBuilds' doc now says vanilla only ever walks BlockFlag.synced blocks, so passing it all of Groups.build is thousands of buildings.
WorldLoadEvent dropped the previous "Mindurka Default Patch" by comparing PatchAsset.name. That name is not set by the constructor -- PatchAsset(String) only sets a random path, and DataAsset.setPath derives name from it. It is filled later by DataPatcher.apply from the patch's own "name" key (DataPatcher.java:253), and reset to "" when a patch throws (:261). So one broken patch -- a malformed patch.hjson in a gamemode -- makes the check stop matching for good, and every later world load prepends another copy of the default patch to state.data.patches, all of which patcher.apply then walks. The asset is now kept in a field and removed by identity.
Which tags reached the client was decided by whatever happened to fit: tags were packed smallest-first until the packet limit, so adding one tag to a map could silently push out a different one, and the only trace was a warning. Gamemode.syncedTags is now an explicit list of exact keys or `prefix.*` patterns. Anything not on it is never serialized. Anything on it that still does not fit is logged with Log.err, not warn -- the gamemode said it was needed, so not sending it is a fault, not housekeeping. The default is the four identity markers SpecialSettings parses: mdrk.format, mdrk.gamemode, mindurkaGamemode and mdrk.patch. The gamemode tables (mdrk.castle.*) are read by the server out of the map (CastleUtils.applyRules), and nothing in mindustry/core reads Rules.tags on a client, so they never needed to travel. On the four castle maps in the repo this takes the setRules packet from the 15000 B cap down to 7053-7806 B, which also halves its share of arcnet's 41000-byte per-connection write buffer.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.