Skip to content

Developer SpoiledZ Integration

Atlasroar edited this page Oct 3, 2026 · 2 revisions

SpoiledZ Integration — Methodology

This page documents why and how Globox1997/SpoiledZ was merged directly into WandererZ in v2.3.0, following the same playbook as the JobsAddon, RpgDifficulty, Tiered, and PartyAddon merges.

Why this merge was different

Every previous merge (JobsAddon, RpgDifficulty, Tiered, PartyAddon) was a LevelZ-specific addon with at least one compat point importing net.levelz.* classes that needed repointing to net.wandererz.*. SpoiledZ is different: it's a general-purpose food-spoilage mod by the same author with zero LevelZ/WandererZ references anywhere in its source tree (confirmed via a full-repo grep for levelz/LevelZ — zero matches). This made the merge mechanically simpler (no compat-point rewriting needed at all) but introduced new dependency-management considerations instead.

Both mods also:

  • target the same Minecraft version (1.20.1) and Yarn mappings
  • use a fully disjoint Java package (net.spoiledz.*) and resource namespace (assets/spoiledz, data/spoiledz), a clean sibling to the other four merged packages
  • SpoiledZ additionally ships vanilla resource overrides under assets/minecraft/* (a cake blockstate
    • 41 item-model predicate overrides adding "spoiled" variants) — the first merged addon to touch the minecraft namespace directly, verified to have zero collision with any prior merge's resources

Step-by-step methodology

  1. Inventory the tree. Cloned SpoiledZ's 1.20 branch (36 Java files: entrypoints, config, mixins, compat). Grepped for levelz — zero matches, confirming no compat rewrite was needed.
  2. Map the dependency graph. Three categories, same as Tiered's AutoTag/Reach Entity Attributes precedent but with a third flavor added:
    • Required, separately-installed: Fabric Seasons — used unconditionally (no isModLoaded guard) in SpoiledUtil and ServerWorldMixin for season-based spoilage timing. Declared only in fabric.mod.json's depends ("seasons": "*"), not bundled — matching upstream SpoiledZ's own modCompileOnly modRuntimeOnly (not include) Gradle declaration.
    • Bundled (shaded into the jar): Capsaicin — the food-eaten/food-properties-modification event library EventInit hooks into. Shipped inside the final jar via Loom's include(), same pattern as Tiered's Reach Entity Attributes. Required adding the maven.siphalor.de Maven repository (Capsaicin's Maven group de.siphalor isn't on Maven Central or the Fabric/Modrinth maven).
    • Optional soft-compat (gated by FabricLoader.isModLoaded(...) in SpoiledzMixinPlugin): Farmer's Delight (already present in WandererZ's own build.gradle at a matching version — no change needed), Expanded Delight, and Vinery (both newly added as modCompileOnly).
  3. Copy source wholesale, keeping net.spoiledz as the package name — no renames needed since there was no LevelZ coupling to rewrite.
  4. Extract the Mod Menu screen. Same single-entrypoint-per-id constraint as every previous merge. SpoiledZ's standalone config/ModMenuIntegration.java was deleted, and WandererZ's combined chooser screen gained a sixth button that opens AutoConfig.getConfigScreen(SpoiledZConfig.class, this).
  5. Merge the manifest. fabric.mod.json: appended SpoiledZ's main/client entrypoints, registered spoiledz.mixins.json alongside the existing four mixin configs, added "seasons": "*" to depends. Dropped the stray "suggests": {"another-mod": "*"} entry — a leftover from the unmodified fabric-example-mod template upstream SpoiledZ was scaffolded from (its contact.sources field even still points at the FabricMC example-mod repo) — rather than propagate a meaningless entry.
  6. Copy resources, verifying no collisions. Checked the main repo had zero pre-existing assets/minecraft/* content before copying SpoiledZ's cake blockstate + 41 item-model overrides — confirmed safe, since no prior merge had ever touched the vanilla namespace.
  7. Add Gradle dependencies. Added the maven.siphalor.de repository, Fabric Seasons as modCompileOnly modRuntimeOnly (not bundled), Capsaicin as bundled modImplementation(include(...)), and Expanded Delight + Vinery as optional modCompileOnly soft-compat.
  8. Validate. gradlew build on JDK 17 succeeded, producing wandererz-2.3.0.jar. Verified the jar contains the expected net/spoiledz/** classes (34), the merged fabric.mod.json (entrypoints + seasons depend entry present), and META-INF/jars/capsaicin-1.20-*.jar bundled alongside the pre-existing Reach Entity Attributes bundle.
  9. Version bump. mod_version went from 2.2.0 → 2.3.0 — a MINOR semver bump (additive functionality, no breaking changes).

Things deliberately not changed

  • compat/AppleSkinPlugin.java is fully commented-out dead code in upstream SpoiledZ (not wired to any entrypoint) — copied as-is for fidelity with upstream rather than deleted, since it compiles fine and matches the "copy wholesale" pattern used for other merged addons' similarly-inert code.
  • Farmer's Delight's existing build.gradle dependency — SpoiledZ uses the same version (1.4.3) WandererZ already depended on from the JobsAddon merge, so no version bump was needed.
  • Non-English SpoiledZ lang files — copied as-is; there was no WandererZ/LevelZ brand string to rebrand since SpoiledZ never referenced LevelZ in the first place.

Serene Seasons compat (added in a follow-up PR, not yet merged)

A later PR added Serene Seasons as an alternative season provider for Food Spoilage, alongside Fabric Seasons. Unlike the rest of this merge, that PR is intentionally kept open for review rather than merged, since it changes a previously hard dependency into an either/or choice and introduces a new reflection-based compat pattern worth scrutinizing before it ships. Key points:

  • A net.spoiledz.compat.season.SeasonProvider interface abstracts "what season is it / how long is a season" away from any specific mod. SeasonProviderInit picks FabricSeasonsProvider or SereneSeasonsProvider at startup based on FabricLoader.isModLoaded(...) (Fabric Seasons preferred if both are present), or disables spoilage timing (logging a warning) if neither is installed.
  • SereneSeasonsProvider calls Serene Seasons' SeasonHelper/ISeasonState API entirely via reflection rather than a compile-time dependency: Serene Seasons' Fabric artifact is compiled against Mojang's official mappings (not Yarn intermediary), so its public API types (e.g. Level) don't resolve in this Yarn-mapped project at compile time. Reflection sidesteps that since it resolves against actual runtime classes, which are identical regardless of which mapping set named them at compile time. FabricSeasonsProvider still calls Fabric Seasons directly, since that mod is a normal Yarn-mapped Fabric artifact.
  • fabric.mod.json's "seasons": "*" moved from depends to suggests, with sereneseasons and its required glitchcore library added alongside it — none of the three are hard requirements anymore.
  • Serene Seasons' GlitchCore dependency (Glitchfiend's cross-loader abstraction library) is published on Modrinth as maven.modrinth:glitchcore, so it's declared the same way as Serene Seasons itself (modRuntimeOnly, not modCompileOnly, for the same mapping-mismatch reason above).

Risk register (resolved)

Risk Resolution
Mod Menu only showing one config per button slot Added a sixth button to the existing combined chooser Screen
assets/minecraft/* overrides silently clobbering another mod's vanilla resource customization Verified zero pre-existing content at that path across all prior merges before copying
Capsaicin's Maven group (de.siphalor) not resolving Added the maven.siphalor.de repository to build.gradle
Fabric Seasons being a hard, unconditional dependency (not isModLoaded-gated) Declared as a required dependency in fabric.mod.json's depends, documented in the README's installation section
Stray template leftover ("another-mod" suggests entry) propagating into the merged manifest Dropped during the merge rather than carried forward
Hidden package/mixin-target/resource collisions Verified none exist via full file-tree review before copying — net.spoiledz is fully disjoint from all other merged packages

Clone this wiki locally