fix: move client-only mixins to client array — fixes dedicated server crash (#28)#32
Open
ntman4real wants to merge 6 commits into
Open
Conversation
added 6 commits
March 19, 2026 18:09
ClientBlockBreakMixin targets MultiPlayerGameMode (client-only class) and PlayerCollidesWithEntityMixin imports LocalPlayer (client-only class). Both were incorrectly placed in the common 'mixins' array, causing dedicated servers to crash with ClassMetadataNotFoundException for net.minecraft.client.player.LocalPlayer. Moved both to the 'client' array so they only load on the client side. ClientConnectionAccessor remains in 'mixins' as it targets Connection which exists on both client and server. Fixes Goodbird-git#28
Some mods (e.g. ConstructionStick) access NeoForge config values in getMaxDamage() which may not be loaded yet during recipe deserialization. This causes IllegalStateException: Cannot get config value before config is loaded, crashing the server in a loop. Fall back to item.hashCode() without damage value when config is unavailable.
The previous fix only caught IllegalStateException, but Undergarden's slingshot item triggers loading client-only SoundInstance class during getDamageValue() -> getMaxDamage() on DEDICATED_SERVER, which throws RuntimeException from NeoForge's RuntimeDistCleaner. Widening to catch(Exception) handles both failure modes safely.
…m Silent Gear recursive loop getMaxDamage -> PartInstance -> ItemStack.copy -> ItemStack.<init> -> recalculateHash -> getDamageValue -> getMaxDamage causes StackOverflowError which extends Error, not Exception.
…loop The recursive cycle getMaxDamage -> PartInstance -> ItemStack.copy -> ItemStack.<init> -> recalculateHash -> getDamageValue -> getMaxDamage was spinning for 60+ seconds before StackOverflowError, triggering the Server Watchdog to kill the process. ThreadLocal guard detects re-entry and falls back to item.hashCode() without damage value, breaking the cycle immediately.
Architectury API issue #653: EventFactory$EventImpl uses a plain ArrayList for its listeners field, which is not thread-safe. When a mod registers a listener during event dispatch (e.g., during the first server tick), the ArrayList iterator throws ConcurrentModificationException, crashing the server. This mixin injects at the end of EventImpl's constructor and replaces the ArrayList with a SnapshotArrayList subclass whose iterator() returns an iterator over a snapshot copy. This makes concurrent registration during iteration safe without changing the field type (which must remain ArrayList). Fixes deterministic crash loop on server startup with ATM10 modpack.
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.
Problem
Dedicated servers crash on startup with:
Root Cause
Two client-only mixins are placed in the common
"mixins"array inplayerengine.mixins.json, causing them to load on dedicated servers where client classes don't exist:ClientBlockBreakMixin— targetsMultiPlayerGameMode(client-only class)PlayerCollidesWithEntityMixin— importsnet.minecraft.client.player.LocalPlayer(client-only class)Fix
Moved both mixins from the
"mixins"array to the"client"array inplayerengine.mixins.json. The Mixin framework will only load entries in the"client"array on the client side.ClientConnectionAccessorremains in"mixins"— it targetsnet.minecraft.network.Connectionwhich exists on both client and server.Testing
Fixes #28