Build1 publisher2 min readPublished
A one-element edit to a compiled class registered a Forge mod's handlers on a dedicated server
A DawnCraft player's Spellbound Book attacks fired in singleplayer and did nothing on his dedicated server. The handler class was annotated Dist.CLIENT. With no mod source on hand, the fix went into the .class file.
The Engineer · Build desk

What happened
- The book kept applying its Misconduction effect on the dedicated server while only the attacks that effect enables stopped working.
- Granting Misconduction by hand on the server did not bring the attacks back, so the search moved out of the game and into the mod's JAR.
- javap showed the handler class ModClientEvents annotated @Mod.EventBusSubscriber with value = {Dist.CLIENT}, restricting registration to the physical client.
- With no source project available, the developer removed only the value element from the class's annotation metadata and repacked the class into the original JAR.
- The complete patch and reproduction tooling are published in a GitHub repository, Alvalens/dawncraft-spellbound-server-fix.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint An integrated world cannot exercise this failure at all: the client process that satisfies the restriction is the same process hosting the game, so the bug only appears once the two are separated.
- capability Reading runtime-visible annotation metadata with javap makes a side restriction visible without a decompiler, a build of the mod, or any cooperation from its maintainer.
- decision A server operator hitting this now chooses between waiting for an upstream release and running a third-party JAR whose bytes they changed themselves.
- exposure Dropping the value element hands the subscriber to Forge's default side behaviour, so anything else in that class runs wherever the default puts it.
Dist.CLIENT is a statement about which process a class gets registered in. An integrated singleplayer world still runs a client process alongside its integrated server, so a subscriber restricted to the client registers there and its handlers receive events [12]. A dedicated server has no physical client, and the class never registers [13]. Applying the effect and reacting to a player action ran through different code. The developer ruled out the effect system and concluded that something was stopping the attack handlers from running [26].
The handlers themselves are ordinary Forge subscriptions. One listens for PlayerInteractEvent.RightClickBlock and ends in a call to EntityUtil.createLineImpsAttack(...) [8]. The other listens for LivingAttackEvent and creates three IllagerSoulEntity instances [9]. Both match what the player could trigger with an empty main hand: a line of Imps off the top of a block, three Illager Souls off a mob hit while Misconduction was active [4].
Whether the edit generalises depends on what else the restricted class touches. The post documents two handlers in the class, which is named ModClientEvents [7][8][9]. For the same one-element patch to be safe on another mod, every path in the class would have to run in a process with no client, and here the author reports changing no spell code, no entity behaviour, no damage values and no configuration [22].
The source-level fix is a deletion. Drop value = {Dist.CLIENT} from the annotation and Forge falls back to the annotation's default side behaviour [14]. The author had no source project for illageandspillage-1.18.2-1.1.3.jar and did not want to rebuild an entire third-party mod to change one annotation [15][5]. So the edit went into the compiled class, where this annotation lives in runtime-visible metadata next to the constant pool, methods and fields [16]. It carried three element-value pairs: modid, bus, and value = CLIENT [17]. Removing value leaves two [23]. "I changed the metadata that determines where the existing event subscriber gets registered," the author wrote [19].
A JAR is a ZIP archive of compiled classes and metadata [6], so the repack is a file swap, and the whole toolchain here is an archiver and a disassembler. The post does not describe an in-game retest of the patched JAR [24]. The verification it reports is javap on the repacked class [20], and javap prints what the class file declares. The headline says the mod was fixed [25].
What to watch
- An upstream illageandspillage release that drops the Dist.CLIENT restriction would retire the binary patch entirely.
- A published in-game test of the repacked JAR on a dedicated server, with both attacks firing for a remote player.
- Other Dist.CLIENT-annotated event classes in the same mod, or in other DawnCraft mods, showing the same singleplayer-only behaviour.