-
Notifications
You must be signed in to change notification settings - Fork 106
Fabric #1128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop/1.21.1
Are you sure you want to change the base?
Fabric #1128
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds/expands Fabric platform support while refactoring client-only functionality into a separate service (IClientHelper) loaded via ServiceLoader, plus substantial Fabric-side rendering/model-loading/worldgen integration work.
Changes:
- Split client-only helpers out of
IMiscHelperinto newIClientHelper+ClientServicesservice loader wiring. - Implement Fabric client rendering/model loading (custom baked models, model loading plugin, falling tree model) and Fabric worldgen hooks (biome modifications + holder set utilities).
- Update build/publish configuration (Fabric publish plugin, NeoForge publish config changes) and access widener entries.
Reviewed changes
Copilot reviewed 74 out of 75 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| neoforge/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper | Registers NeoForge IClientHelper service implementation. |
| neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeMiscHelper.java | Removes client-only methods from misc helper. |
| neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeClientHelper.java | New NeoForge client helper implementing IClientHelper. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/ThickBranchBlockModelLoader.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/SurfaceRootBlockModelLoader.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/RootsBlockModelLoader.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/PalmLeavesModelLoader.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/geometry/BranchBlockModelGeometry.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SmallPalmLeavesBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/PalmLeavesBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/MediumPalmLeavesBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/LargePalmLeavesBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BakedModelBlockPottedSapling.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/model/QuadManipulator.java | Removes NeoForge dist marker annotation usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientModEventHandler.java | Import/style adjustments related to distmarker usage. |
| neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientGameEventHandler.java | Import/style adjustments related to distmarker usage. |
| neoforge/build.gradle | Publishing configuration changes (tokens commented out). |
| gradle.properties | Adds regutils_version property. |
| fabric/src/main/resources/fabric.mod.json | Adds client entrypoint and updates metadata/links/suggests. |
| fabric/src/main/resources/dynamictrees.fabric.mixins.json | Expands mixin list for Fabric behavior parity. |
| fabric/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper | Registers Fabric IClientHelper service implementation. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/TagsRegexMatchHolderSet.java | Adds tag-based regex holder set for Fabric. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/StreamBackedHolderSet.java | Adds base HolderSet implementation backed by streams. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/RegexMatchHolderSet.java | Adds regex matching holder set using registry lookup streams. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/OrHolderSet.java | Adds OR-composition holder set for Fabric. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/NameRegexMatchHolderSet.java | Adds name-based regex holder set for Fabric. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DelayedHolderSet.java | Adds lazy holder set wrapper for late-bound registries. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DTBiomeHolderSet.java | Implements Fabric IDTBiomeHolderSet behavior. |
| fabric/src/main/java/com/dtteam/dynamictrees/worldgen/FabricBiomeModifications.java | Adds Fabric biome modification hooks for adding/removing features. |
| fabric/src/main/java/com/dtteam/dynamictrees/treepack/FabricModFileContainer.java | Adjusts resource lookup strategy for Fabric loader containers. |
| fabric/src/main/java/com/dtteam/dynamictrees/registry/FabricRegistryHandler.java | Implements Fabric block/item registration and handler registration. |
| fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricMiscHelper.java | Removes client-only misc methods; adds server tracking + debug helper. |
| fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricInteractionHelper.java | Adds DT block-specific blockDestroyByPlayer delegation. |
| fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricEventHelper.java | Updates Fabric event helper surface for staged resource loader hooks. |
| fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricConfigHelper.java | Improves double config handling for float/double defaults. |
| fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricClientHelper.java | New Fabric IClientHelper implementation (pixel access + falling tree model). |
| fabric/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java | Adds Fabric renderer baked model for thick branches. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java | Adds Fabric renderer baked model for surface roots. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java | Adds Fabric renderer baked model for underground roots. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java | Adds Fabric renderer baked model for branches. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelFabric.java | Adds Fabric falling tree entity model generation. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/DTModelLoadingPlugin.java | Adds Fabric model loading plugin and baked model caching. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/BranchBlockUnbakedModel.java | Adds Fabric unbaked model implementation for branches. |
| fabric/src/main/java/com/dtteam/dynamictrees/model/BakedModelBlockPottedSapling.java | Adds Fabric wrapper for potted sapling baked model. |
| fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinSaplingBlock.java | Injects sapling growth to replace vanilla saplings with dynamic trees. |
| fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinMinecraftServer.java | Tracks current server instance for Fabric misc helper. |
| fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinDynamicTreeFeature.java | Adds instrumentation/logging around species selector selection. |
| fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinBushBlock.java | Adjusts survival checks for plants above covered roots. |
| fabric/src/main/java/com/dtteam/dynamictrees/event/handler/VanillaSaplingEventHandler.java | Adds right-click sapling replacement into dynamic saplings on Fabric. |
| fabric/src/main/java/com/dtteam/dynamictrees/event/handler/ModEventHandler.java | Reworks registry/type registration flow for Fabric. |
| fabric/src/main/java/com/dtteam/dynamictrees/event/handler/CommonEventHandler.java | Adds Fabric lifecycle hooks and player block break hook for DT blocks. |
| fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java | Adds new config entries and fixes numeric literal types. |
| fabric/src/main/java/com/dtteam/dynamictrees/DynamicTreesFabricClient.java | Adds Fabric client entrypoint: renderers, colors, model plugin registration. |
| fabric/src/main/java/com/dtteam/dynamictrees/DynamicTreesFabric.java | Updates Fabric init sequence and adds biome modifications + lifecycle hooks. |
| fabric/build.gradle | Adds mod-publish plugin and datagen run config; configures publishing. |
| common/src/main/resources/META-INF/dynamictrees.accesswidener | Expands access widener for sprite internals + tag provider/appender access. |
| common/src/main/java/com/dtteam/dynamictrees/tree/family/Family.java | Removes distmarker annotations from client-only color fields/methods (now comments). |
| common/src/main/java/com/dtteam/dynamictrees/platform/services/IMiscHelper.java | Removes client-only methods from misc helper interface. |
| common/src/main/java/com/dtteam/dynamictrees/platform/services/IClientHelper.java | Introduces new client helper interface. |
| common/src/main/java/com/dtteam/dynamictrees/platform/ClientServices.java | Adds ServiceLoader-based client service loading. |
| common/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelTrackerCache.java | Switches falling tree model creation to ClientServices. |
| common/src/main/java/com/dtteam/dynamictrees/entity/animation/VoidAnimationHandler.java | Removes distmarker annotations (now comments). |
| common/src/main/java/com/dtteam/dynamictrees/entity/animation/PhysicsAnimationHandler.java | Removes distmarker annotations (now comments). |
| common/src/main/java/com/dtteam/dynamictrees/entity/animation/FalloverAnimationHandler.java | Removes distmarker annotations (now comments). |
| common/src/main/java/com/dtteam/dynamictrees/entity/animation/AnimationHandler.java | Removes distmarker annotations (now comments). |
| common/src/main/java/com/dtteam/dynamictrees/client/ThickBranchRingsSprite.java | Updates to new SpriteContents.metadata() API usage. |
| common/src/main/java/com/dtteam/dynamictrees/client/TextureHelper.java | Switches pixel sampling to ClientServices.CLIENT. |
| common/src/main/java/com/dtteam/dynamictrees/client/SoundInstanceHandler.java | Removes distmarker annotation (now comment). |
| common/src/main/java/com/dtteam/dynamictrees/client/BlockColorMultipliers.java | Removes distmarker annotation (now comment). |
| common/src/main/java/com/dtteam/dynamictrees/block/leaves/LeavesProperties.java | Removes distmarker annotations (now comments) + client post-init remains. |
| build.gradle | Formatting-only change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| level.removeBlock(pos, false); | ||
| ci.cancel(); | ||
|
|
||
| if (species.isValid()) { | ||
| if (DynamicSaplingBlock.canSaplingStay(level, species, pos)) { | ||
| species.transitionToTree(level, pos); | ||
| } | ||
| } |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mixin removes the sapling block and cancels vanilla growth unconditionally once a replacer exists. If species is invalid or DynamicSaplingBlock.canSaplingStay is false, the sapling is still deleted and vanilla growth is prevented. Consider only removing/canceling when you are definitely going to transition to a dynamic tree; otherwise return without canceling so vanilla behavior remains intact.
| level.removeBlock(pos, false); | |
| ci.cancel(); | |
| if (species.isValid()) { | |
| if (DynamicSaplingBlock.canSaplingStay(level, species, pos)) { | |
| species.transitionToTree(level, pos); | |
| } | |
| } | |
| // Only interfere with vanilla behavior if we are definitely transitioning to a dynamic tree | |
| if (species == null || !species.isValid()) { | |
| return; | |
| } | |
| if (!DynamicSaplingBlock.canSaplingStay(level, species, pos)) { | |
| return; | |
| } | |
| level.removeBlock(pos, false); | |
| ci.cancel(); | |
| species.transitionToTree(level, pos); |
| if (face == Direction.UP || face == Direction.DOWN) { | ||
| if (connections[face.get3DDataValue()] < twigRadius && !branchesAround) { | ||
| List<BakedQuad> ringQuads = trunksTopRingsQuads[radiusIndex]; | ||
| if (ringQuads != null) { |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trunksBotRingsQuads is populated but never used. In emitBlockQuads, ring quads for Direction.DOWN are currently pulled from trunksTopRingsQuads, which will render the wrong UV/orientation for the bottom face. Select trunksTopRingsQuads for UP and trunksBotRingsQuads for DOWN (or compute the correct list based on face).
|
|
||
| curseforge { | ||
| projectId = "252818" | ||
| projectSlug = "dynamictrees" // Required for discord webhook |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CurseForge accessToken is now commented out. If the publishMods task is used in CI/release workflows, publishing will fail even when CURSEFORGE_API_KEY is set. Consider restoring this line or conditionally setting it only when a token is present.
| @Inject(method = "getSpeciesSelector", at = @At("RETURN"), remap = false) | ||
| private void onGetSpeciesSelector(BiomeDatabase.EntryReader biomeEntry, CallbackInfoReturnable<BiomePropertySelectors.SpeciesSelector> cir) { | ||
| if (dynamictrees$loggedCherrySelector) { | ||
| return; | ||
| } | ||
| if (biomeEntry != null && biomeEntry.getBiomeKey() != null) { | ||
| String biomeName = biomeEntry.getBiomeKey().location().toString(); | ||
| if (biomeName.contains("cherry")) { | ||
| dynamictrees$loggedCherrySelector = true; | ||
| BiomePropertySelectors.SpeciesSelector selector = cir.getReturnValue(); | ||
| DynamicTrees.LOG.info("Cherry biome species selector type: {} for biome {}", | ||
| selector.getClass().getSimpleName(), biomeName); | ||
|
|
||
| dynamictrees$debugRandom.setXOR(BlockPos.ZERO); | ||
| try { | ||
| BiomePropertySelectors.SpeciesSelection selection = selector.getSpecies( | ||
| BlockPos.ZERO, Blocks.DIRT.defaultBlockState(), dynamictrees$debugRandom); | ||
| Species species = selection.getSpecies(); | ||
| DynamicTrees.LOG.info("Cherry biome would select species: {} (valid: {}, handled: {})", | ||
| species.getRegistryName(), species.isValid(), selection.isHandled()); | ||
| } catch (Exception e) { | ||
| DynamicTrees.LOG.error("Failed to test species selection for cherry biome", e); | ||
| } | ||
|
|
||
| if (selector instanceof BiomePropertySelectors.RandomSpeciesSelector randomSelector) { | ||
| dynamictrees$logRandomSelectorContents(randomSelector); | ||
| } |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mixin adds production logging and reflective access into BiomePropertySelectors.RandomSpeciesSelector for cherry biomes. Even though it runs once, it still adds runtime overhead, log noise, and a brittle reflection dependency on private field names. Please remove this debug-only instrumentation or gate it behind an explicit debug config/flag so it never runs in normal releases.
| ServerLifecycleEvents.SERVER_STARTING.register(server -> { | ||
| VanillaSaplingEventHandler.updateEnabled(); | ||
| FabricMiscHelper.debugSpeciesRegistry(); | ||
| }); |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FabricMiscHelper.debugSpeciesRegistry() logs multiple INFO lines on every server start. This looks like temporary debugging and will add noise for all users/servers. Please remove it or gate it behind a debug config (e.g., IConfigHelper.DEBUG) / log-level check.
| public boolean blockDestroyByPlayer(BlockState state, Level level, BlockPos pos, Player player, boolean willHarvest, FluidState fluidState) { | ||
| return false; | ||
| Block block = state.getBlock(); | ||
| if (block instanceof BranchBlock branchBlock) { | ||
| return branchBlock.onDestroyedByPlayer(state, level, pos, player, willHarvest, fluidState); | ||
| } else if (block instanceof TrunkShellBlock trunkShellBlock) { | ||
| return trunkShellBlock.onDestroyedByPlayer(state, level, pos, player, willHarvest, fluidState); | ||
| } else if (block instanceof SoilBlock soilBlock) { | ||
| return soilBlock.onDestroyedByPlayer(state, level, pos, player, willHarvest, fluidState); | ||
| } else if (block instanceof PottedSaplingBlock pottedSaplingBlock) { | ||
| return pottedSaplingBlock.onDestroyedByPlayer(state, level, pos, player, willHarvest, fluidState); | ||
| } | ||
| return true; | ||
| } |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For blocks that aren’t one of the Dynamic Trees types, this method returns true without performing any destruction/removal logic. On NeoForge this helper delegates to state.onDestroyedByPlayer(...) for any block, so this behavior is inconsistent across platforms and can become a silent no-op if other code paths start calling it with vanilla/modded blocks. Consider implementing a generic fallback that mimics vanilla block breaking (e.g., calling playerWillDestroy and then replacing the block with the passed fluidState/air).
| optional("dynamictreesplus") | ||
| } | ||
| modrinth { | ||
| projectId = "vdjF5PL5" |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Modrinth accessToken is now commented out. If the publishMods task is used in CI/release workflows, publishing will fail even when MODRINTH_TOKEN is set. Consider restoring this line or conditionally setting it only when a token is present.
| public class MixinBushBlock { | ||
|
|
||
| @Shadow protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos){ return false; } |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Shadow methods should not provide an implementation body. Having return false; here can cause mixin application errors at runtime. Make this shadowed method abstract (or remove it and use an invoker/accessor pattern if needed).
| public class MixinBushBlock { | |
| @Shadow protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos){ return false; } | |
| public abstract class MixinBushBlock { | |
| @Shadow protected abstract boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos); |
|
|
||
| @Shadow protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos){ return false; } | ||
|
|
||
| @Inject(at = @At("HEAD"), cancellable = true, method = "canSurvive (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z") |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The injected method target string includes an extra space ("canSurvive (…"), which means the mixin will not find the target method and will fail to apply or silently do nothing (depending on mixin settings). Remove the space so the method signature matches exactly.
| @Inject(at = @At("HEAD"), cancellable = true, method = "canSurvive (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z") | |
| @Inject(at = @At("HEAD"), cancellable = true, method = "canSurvive(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z") |
No description provided.