fabric: complete Minecraft 26.1.2 Fabric port (vibecoded) - #1221
Open
joaovictor-martins wants to merge 15 commits into
Open
fabric: complete Minecraft 26.1.2 Fabric port (vibecoded)#1221joaovictor-martins wants to merge 15 commits into
joaovictor-martins wants to merge 15 commits into
Conversation
…ic v5 API Upstream's e67a435 wired up forgeconfigapiport-fabric:26.1.5 but called through fuzs.forgeconfigapiport.fabric.impl.core.ConfigRegistryImpl, an internal implementation package. The jar also ships the intended public API, fuzs.forgeconfigapiport.fabric.api.v5.ConfigRegistry, with an identical register(String, ModConfig.Type, IConfigSpec) signature (verified via javap against the 26.1.5 jar) — switch both DynamicTreesFabric and DynamicTreesFabricClient to depend on that instead. Also drops a stale, no-longer-resolvable fuzs.forgeconfigapiport.fabric.api.neoforge.v4.* import left over from the pre-migration code in DynamicTreesFabricClient.java, which was itself causing a real "package does not exist" compile error.
Needed to see the full error count while working through the Fabric port plan instead of only the first 100. Per the plan, remove before the final PR (or keep, see Task 7).
…gistration Applies upstream PR DynamicTreesTeam#1208 verbatim (verified: applies cleanly against the current tree, and FabricEntityDataRegistry is confirmed present in the pinned fabric-api 0.145.3+26.1.1 via the fabric-object-builder-api-v1 submodule, and RegistryLoader.registerEntityDataSerializer's signature matches). - registerBlock/registerItem previously returned a Supplier that lazily called Registry.register(...) on first .get() — entries nobody ever polls during init (e.g. DIRT_BUCKET) never actually registered, breaking recipes referencing them. Now registers eagerly and returns a supplier over the already-registered instance. - Adds registerEntityDataSerializer, previously unimplemented (falling back to vanilla's EntityDataSerializers.registerSerializer, which Fabric API forbids at runtime for desync-safety reasons), via FabricEntityDataRegistry.register(...). Also removes the unused net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup import — that package doesn't exist in fabric-api 0.145.3+26.1.1, but registerCreativeTab already builds a plain vanilla CreativeModeTab.builder directly and never referenced FabricItemGroup, so this was dead code causing a live "package does not exist" compile error, not a real migration.
…Only Existing compat classes (compat/waila/*.java, compat/SereneSeasonsSeasonProvider.java, compat/continuity/*.java) import snownee.jade.*, sereneseasons.*, and me.pepperbell.continuity.* respectively, but fabric/build.gradle declared none of these — unlike neoforge/build.gradle, which already pulls in Jade and SereneSeasons (from CurseForge/Modrinth respectively). Versions picked by querying the Modrinth API for releases declaring compatibility with game version 26.1.2 and loader fabric: - jade:26.1.9+fabric (latest matching release) - continuity:3.0.1-beta.2+26.1 (only fabric/quilt releases available for this game version; no separate loader-specific pin needed) - serene-seasons:26.1.2.0.2, matching the exact version string neoforge/build.gradle already pins, for cross-loader consistency (a newer 26.1.2.0.4 exists but wasn't picked, to avoid unrelated version drift between loaders) Confirmed all three are compileOnly-appropriate: SereneSeasons's compat path is gated behind Services.PLATFORM.isModLoaded(...) before the sereneseasons-importing class is ever touched; Continuity's is gated the same way; Jade's only entry point (WailaCompat.java) is fully commented out already (dormant), so its handler classes only need to compile, not run. Also adds glitchcore as compileOnly — SereneSeasonsSeasonProvider.java references glitchcore.config.Config directly (a transitive dependency of SereneSeasons at compile time, same as neoforge/build.gradle's curse.maven:glitchcore-955399:8109770), which doesn't resolve merely by adding serene-seasons itself. Result: 508 -> 452 compile errors. Remaining errors in these files are real API-shape mismatches (Jade's IElement/ElementHelper, SereneSeasons's warmEnoughToRain signature, Continuity's dependency on the vanilla BakedModel rendering-API rewrite) — out of scope for this task, which only needed the packages to resolve on the classpath.
…odel API Ports upstream PR DynamicTreesTeam#1209's fabric/model/ rewrite (targets Minecraft 26.2) back onto this project's pinned 26.1.2 toolchain, per the plan's Task 5. Every referenced Fabric API class (FabricBlockStateModel, FabricBlockStateModelPart, QuadEmitter, CustomUnbakedBlockStateModel, WrapperBlockStateModel) and vanilla class (BlockStateModel, BlockStateModelPart, ModelState, ModelBaker, ResolvableModel, ResolvedModel, SimpleModelWrapper, Material, TextureSlots, BlockAndTintGetter, BakedQuad) was individually confirmed present at the exact same package path in this project's pinned fabric-api (0.145.3+26.1.1) and Minecraft (26.1.2) jars before porting any code, so despite the reference PR targeting a different Minecraft version, its model/ files needed no adaptation beyond what's described below. Restructures model/baked/ (old BakedModel-based approach) into a mix of updated model/baked/ (still used for procedural fallback baking) and a new model/blockstate/ package (codec-based blockstate JSON deserialization via CustomUnbakedBlockStateModel), mirroring NeoForge's existing BlockStateModel-based architecture. BakedModelBlockPottedSapling.java and BranchBlockUnbakedModel.java are deleted, superseded by blockstate/PottedSaplingBlockStateModel.java and blockstate/UnbakedBranchModel.java respectively. All actual geometry/quad-generation logic (branch rings, thick-branch trunks, surface roots, aerial roots) is unchanged — it already lived in loader-agnostic common/ helper classes (BranchMultiPartHolder, ModelHelper, ModelConnections, model/parts/*) used by NeoForge's already-working implementation; every method these ported files call against those helpers was individually confirmed present with a matching signature before porting. Only the Fabric-side API adapter code changes. common/ additions (needed by the above, not previously present): - New DynamicModelRegistry: records DT's own baked block state models as they're baked, so FallingTreeEntityModel's falling-tree geometry can find DT's real model even when another mod (e.g. Continuity) has wrapped/replaced what the model manager hands back for a state - without this, a wrapped model would silently fail DT's BlockStateModelWithConnectionData/BlockStateModelWithRadius instanceof checks and render the falling tree's trunk invisible. - FallingTreeEntityModel's three modelSet.get(state) call sites now go through DynamicModelRegistry.getOrFallback(state, modelSet) instead. Verified :neoforge:compileJava still succeeds after this shared-code change (no regression on the already-working loader). Also fixes compat/continuity/WrappedModelHandler.java and ContinuityWrappedModelHandler.java for the same rendering-API rewrite, found during Task 4 and folded into this task's scope: BakedModel -> BlockStateModel, and CtmBakedModel -> CtmBlockStateModel (Continuity's own class renamed to match). ContinuityWrappedModelHandler now reaches Continuity's wrapped model via a VarHandle into Fabric API's WrapperBlockStateModel#wrapped (protected, no public accessor) - verified via javap that the field exists with the expected name/type in the pinned fabric-api jar. This compat path has no live caller yet (WailaCompat-style dormant code), so this is a compile fix only, not yet exercised at runtime. Deliberately NOT ported: PR DynamicTreesTeam#1209 also fixes an unrelated alpha-channel bug in FallingTreeEntityModel#renderToBuffer's color packing (`0xFF000000 | ...`). Left out to keep this commit scoped to the API migration; worth a follow-up look separately. Result: 452 -> 102 compile errors. Confirmed zero errors remain in any file this task touches (model/baked, model/blockstate, DTModelLoadingPlugin, FabricDynamicBlockStateModel, FallingTreeEntityModelFabric, compat/continuity).
…ent Fabric+vanilla tint-source API ColorProviderRegistry and BlockRenderLayerMap no longer exist. Mirrors NeoForge's already-working ClientModEventHandler: block tint sources go through BlockColorRegistry with the existing common/ TintSources classes, item tint sources register by id via ItemTintSources.ID_MAPPER, and render-layer assignment is dropped entirely (NeoForge no longer registers it either - it's now declared elsewhere). Also fixes two adjacent dead/ renamed calls in the same file: AtlasSourceTypeRegistryImpl -> the current SpriteSourceRegistry, and LeavesProperties.postInitClient() (removed method, confirmed via a full-repo grep) is simply dropped.
…easonProvider signature drift, FabricRegistryLoader vanilla-API drift, and access-widener gaps for 26.1.2 - HolderSet gained an abstract isBound() in this MC version; added it to every custom HolderSet impl in fabric/.../worldgen/holderset (eagerly resolvable sets report true, wrappers delegate to what they wrap). Also fixed net.minecraft.Util -> net.minecraft.util.Util and ResourceKey.location() -> .identifier() (both renamed/moved). - FabricInteractionHelper: Branch/TrunkShell/PottedSaplingBlock's onDestroyedByPlayer gained an ItemStack toolStack param; pass player.getMainHandItem() (matches NeoForgeInteractionHelper's approach - vanilla BlockState.onDestroyedByPlayer() is a NeoForge-only extension that doesn't exist on Fabric's plain jar). Dropped a stray @OverRide on canToolAxeDig, which isn't on ICompatHelper and is dead code (its one common/ call site is already commented out). - FabricCompatHelper.registerSeasonProvider gained a modId param on the interface; switch on it like NeoForgeCompatHelper (only Serene Seasons has a Fabric dependency wired up - Ecliptic Seasons doesn't). - FabricRegistryLoader: LootItemConditionType/LootPoolEntryType/ LootItemFunctionType no longer exist - their registries now hold the MapCodec directly (ported NeoForgeRegistryLoader's already-correct shape). EntityType.Builder.build(String) -> build(ResourceKey). Dropped BlockEntityType's stale 3-arg constructor's trailing null. - javax.annotation.Nullable -> org.jetbrains.annotations.Nullable in the two files still using it (JSR-305 isn't on Fabric's classpath; every other file in the codebase already uses the JetBrains annotation). - Access widener: fixed craftingRemainingItem's descriptor (Item wraps it in ItemStackTemplate now), added the missing `accessible field` half for BlockEntity.type/blockState (only `mutable` was present, which is a no-op on an already-non-final private field), and added entries for newly-private/final members surfaced by this MC version: SpriteContents .additionalMetadata, MultiPartModel.models, CreakingHeartBlockEntity .ticksExisted and its now-private spreadResin() (extendable), Item .getCraftingRemainder() (now final - extendable), and BlockEntityType's 2-arg constructor (now private - accessible).
- CommonEventHandler: ServerWorldEvents -> ServerLevelEvents, START_WORLD_TICK -> START_LEVEL_TICK, level.getDayTime() -> getDefaultClockTime() (same rename family as Task 6/8's client-side fixes); PreparableReloadListener.reload(...) now takes (SharedState, Executor, PreparationBarrier, Executor) instead of the old 6-arg form - common/'s Resources.ReloadListener already has the correct signature, only this Fabric override needed updating; and the same onDestroyedByPlayer toolStack-arg fix as FabricInteractionHelper (Task 7). - FabricClientHelper: NativeImage.getPixelRGBA -> getPixel (confirmed via common/'s TextureHelper.PixelBuffer, which already uses getPixel for the same purpose on both loaders). - FabricBiomeModifications: BiomeSelectionContext.getBiomeRegistryEntry() -> getBiomeHolder(); PlacedFeature.getFeatures() now yields Holder<ConfiguredFeature<?,?>> instead of ConfiguredFeature<?,?> directly - unwrap with .value() at the call site. - DendroPotionRecipeHandler: Registry.getHolder(ResourceKey) -> the inherited HolderGetter.get(ResourceKey) (same return type). - SereneSeasonsSeasonProvider: Biome.warmEnoughToRain gained a sea-level int parameter; NeoForge's already-working SereneSeasonsProvider shows the value to pass (level.getSeaLevel()).
snownee.jade.api.ui.IElement and snownee.jade.impl.ui.ElementHelper don't exist in the pinned Jade version (26.1.9+fabric) - the UI API was restructured to snownee.jade.api.ui.Element (implements LayoutElement directly, so ITooltip's add/append overloads resolve unambiguously again) and the static factory methods moved to snownee.jade.api.ui.JadeUI (verified both via javap against the actual pinned jar). Also fixed CompoundTag.getString(String) returning Optional<String> instead of String.
Not MC-version drift: BasicRootsBlock already exposes getAerialFamily() (an (AerialRootsFamily) super.getFamily() cast, used throughout the rest of the class) precisely for this. The mixin was calling the untyped getFamily() instead - use the existing accessor.
Species.overrideSaplingReplacementWhenCrouching() does not exist anywhere
on this branch's common/ code (confirmed via full-repo grep) - its only
history is a single commit ("added override_sapling_replacement_when_
crouching to species") that is not an ancestor of develop/26.1.2, so the
Species field/accessor this call depended on was never present here to
begin with; this is not something the MC version bump removed.
NeoForge's VanillaSaplingEventHandler (the working, shipping behavior on
the other loader) never checks crouching at all in its equivalent code
path - it always proceeds to replace/plant regardless. Removing the gate
here makes Fabric match that existing NeoForge behavior exactly, rather
than inventing a guess at what "crouching" should do.
…ssWidener :fabric:compileJava never validates the AW file's entries against the real Minecraft classes - it just applies whatever's there for compile- time widening. :fabric:build's validateAccessWidener task does check, and failed on 5 entries whose target field/method/class no longer exists in this Minecraft version (RecipeManager.byType, WeightedStateProvider .weightedList's descriptor - the field's type changed from SimpleWeightedRandomList to WeightedList, IntrinsicHolderTagsProvider .IntrinsicTagAppender, SpriteContents.metadata(), SpriteSources.register). Confirmed via a full-repo grep that none of the 5 have any live caller in common/ or fabric/ (the field even the closest one, weightedList, is referenced by - is only used from a neoforge/-only datagen file, which doesn't consume this Fabric-only AW file at all). Rather than guess a plausible descriptor fix for entries nothing depends on, removed them.
…od init Runtime crash found during Task 9's server smoke test: FabricRegistryLoader .setup() called DendroPotionRecipeHandler.getAllDendroRecipes() directly from DynamicTreesFabric.onInitialize() (the main Fabric entrypoint, which runs very early). That method builds ItemStacks from vanilla item Holders (Items.CHARCOAL etc.), which aren't bound yet at that point - NullPointerException: "Components not bound yet" in Holder$Reference .components(). NeoForge never had this problem because its own DendroPotionRecipeHandler is only invoked later, from RegisterBrewingRecipesEvent. Fabric already has an equivalent lazy trigger: MixinPotionBrewing injects into vanilla PotionBrewing's instance methods and calls the same handler, which runs only when brewing is actually checked at runtime (well after registries are bound). getAllDendroRecipes() already caches its result on first call, so removing the premature eager call is enough - confirmed via a clean server startup afterward.
…rrs flag
Found during Task 9's client smoke test: every single Dynamic Trees block
(saplings, branches, leaves, roots - ~3000 warnings, not a handful) logged
"Missing model for variant" on launch, because none of common/'s datagen
output (src/generated/resources - blockstates, models, tags, everything
DTExtraModelGenerator etc. produce) was ever making it into fabric's
built jar. Not a Task 1-8 regression: this gap predates the whole plan.
Root cause: the shared commonResources Gradle configuration (defined in
common/build.gradle, consumed by both loaders via multiloader-loader
.gradle's processResources block) only publishes sourceSets.main
.resources - never src/generated/resources. neoforge/build.gradle already
works around this with its own extra
"sourceSets.main.resources { srcDir project(':common').file
('src/generated/resources') }" line; fabric/build.gradle never had the
equivalent. Added it.
Also removes the temporary -Xmaxerrs compiler flag (added early in this
port to see past javac's 100-error display cap) now that :fabric:build is
clean, per this task's own instruction.
…es at runtime) Two compounding bugs found via the client smoke test - the branches and roots of every tree rendered with no texture: 1. DTModelLoadingPlugin.registerModelTypes() (which calls CustomUnbakedBlockStateModel.register(...) for each of DT's 7 custom model types - branch, roots, surface_root, creaking_heart, etc.) was defined but never called from anywhere. DynamicTreesFabricClient .registerModelLoaders() only called ModelLoadingPlugin.register(new DTModelLoadingPlugin()), so Fabric's model-loading registry never learned what "dynamictrees:branch" et al. mean - every custom-typed blockstate variant failed to resolve to any model. 2. Separately, decompiling Fabric's own CustomUnbakedBlockStateModelRegistry (fabric-model-loading-api-v1) confirmed it dispatches custom model types on a "fabric:type" key, not NeoForge's "type" key. common/'s generated blockstate JSONs (produced by a NeoForge-only datagen tool - see BasicLoaderBuilder.java) only ever wrote "type", so even with issue 1 fixed, Fabric's codec had nothing to key its dispatch on. Patched the 31 already-generated blockstate JSON files to carry both keys side by side, matching what DTModelLoadingPlugin's own javadoc already assumed was true. Confirmed fixed via the actual client smoke test: sapling/tree/branch textures now render, trees can be chopped, and bonemeal growth produces correctly rendered branches. Server smoke test and :neoforge:build both still pass.
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.
So, I gotta be honest, I vibe coded the hell out of this. I kinda used it as an experiment to test my local AI Agent running on my local machine, but I turned out kind of well. Things are apparently working as I tested some of it on a multiplayer sessions with friends. It was done with a mix of NVIDIA-Nemotron-3.5-Lightning-30B-A3B-NVFP4 and some outsourcing remotely to Anthropic Sonnet.
Summary
Completes the Fabric port of
develop/26.1.2to Minecraft 26.1.2 — the Fabric loader now compiles and runs cleanly (:fabric:buildsucceeds, dedicated server boots without error, and the client was manually verified: saplings render, trees can be chopped, and bonemeal-grown trees render correctly at every branch/root thickness).This picks up from the point the branch was at (
e67a435e) and closes out every remaining Fabric compile error (587 → 0) plus 3 runtime-only bugs that only a real client/server run surfaced. #1209 (targeting 26.2, "offered for adoption") was used as a reference for the rendering-pipeline rewrite, but every referenced API was independently re-verified against this branch's actual pinnedfabric-apiversion and the real Minecraft 26.1.2 jar before use — nothing was ported blind.What changed
forgeconfigapiport-fabricusage to its current publicapi.v5.ConfigRegistry(the branch was on an internal, non-public class).registerEntityDataSerializer, and fixed vanilla API drift in loot-type/entity/block-entity registration (RegistryLoader's loot registries now holdMapCodecdirectly,EntityType.Builder.buildneeds aResourceKey, etc.).compileOnly, and fixed each one's own API drift against the pinned versions (Jade'sIElement→Element/ElementHelper→JadeUIrename, Serene Seasons'Biome.warmEnoughToRainnew parameter, Continuity's model-wrapping reflection).BlockStateModel/FabricBlockStateModelAPI replacing the removedBakedModelextension points, plus color/render-layer/sprite-source registration onto the current Fabric+vanilla tint-source system (BlockColorRegistry,ItemTintSources,SpriteSourceRegistry—BlockRenderLayerMaphas no replacement; render-layer assignment moved out of this responsibility entirely, matching NeoForge).common/:HolderSet.isBound()(new abstract method), several Mojang renames/moves (net.minecraft.Util→net.minecraft.util.Util,ResourceKey.location()→.identifier(),NativeImage.getPixelRGBA→getPixel,Registry.getHolder→get, etc.), and a batch of access-widener fixes (stale descriptors, wrong verb, and several newly-private/final vanilla members this MC version introduced).validateAccessWidenertask.ItemStacks off unbound itemHolders too early in mod init.fabric/build.gradlewas never pulling incommon/'s generated resources at all, and even after that, DT's custom branch/root model registration was never actually invoked and the generated blockstate JSON was missing the"fabric:type"key Fabric's model dispatch needs (only had NeoForge's"type").Full task-by-task rationale, including what was found to differ from initial assumptions and why, is written up in detail in the commit messages.
Test plan
./gradlew :fabric:build—BUILD SUCCESSFUL./gradlew :neoforge:build—BUILD SUCCESSFUL(confirmed no regression from the sharedcommon/fixes)./gradlew :fabric:runServer— boots cleanly, all species register, no crash./gradlew :fabric:runClient— manually verified: sapling renders, tree can be chopped, bonemeal growth renders branches/roots correctly at multiple thicknesses