diff --git a/build.gradle b/build.gradle index d40685804..9b753970a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { // see https://fabricmc.net/develop/ for new versions - id 'fabric-loom' version '1.9-SNAPSHOT' apply false + id 'fabric-loom' version '1.13-SNAPSHOT' apply false // see https://projects.neoforged.net/neoforged/moddevgradle for new versions - id 'net.neoforged.moddev' version '2.0.49-beta' apply false -} \ No newline at end of file + id 'net.neoforged.moddev' version '2.0.140' apply false +} diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle index e2b0047fa..ad5ee49c8 100644 --- a/buildSrc/src/main/groovy/multiloader-common.gradle +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -42,6 +42,11 @@ repositories { name = 'BlameJared' url = 'https://maven.blamejared.com' } + + maven { + name = "Fuzs Mod Resources" + url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" + } } // Declare capabilities on the outgoing configurations. diff --git a/common/build.gradle b/common/build.gradle index ea7000a89..f96e37166 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -19,11 +19,14 @@ neoForge { } } + + dependencies { compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' // fabric and neoforge both bundle mixinextras, so it is safe to use it in common compileOnly group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' + compileOnly "fuzs.forgeconfigapiport:forgeconfigapiport-common-neoforgeapi:${project.forge_config_api_port_version}" } configurations { diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicBranchBlock.java b/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicBranchBlock.java index 1dd31bf24..ca44f9f99 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicBranchBlock.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicBranchBlock.java @@ -8,8 +8,7 @@ import com.dtteam.dynamictrees.block.leaves.DynamicLeavesBlock; import com.dtteam.dynamictrees.block.leaves.LeavesProperties; import com.dtteam.dynamictrees.block.pod.OffsetablePodBlock; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.systems.GrowSignal; import com.dtteam.dynamictrees.systems.cell.MetadataCell; import com.dtteam.dynamictrees.systems.growthlogic.context.DirectionSelectionContext; @@ -192,8 +191,8 @@ public boolean canPlaceLiquid(@Nullable Player player, BlockGetter level, BlockP public float getHardness(BlockState state, BlockGetter level, BlockPos pos) { final int radius = this.getRadius(level.getBlockState(pos)); final double hardness = this.getFamily().getPrimitiveLog().orElse(Blocks.AIR).defaultBlockState() - .getDestroySpeed(level, pos) * Services.CONFIG.getDoubleConfig(IConfigHelper.TREE_HARDNESS_MULTIPLIER) * (radius * radius) / 64.0f * 8.0f; - return (float) Math.min(hardness, Services.CONFIG.getDoubleConfig(IConfigHelper.MAX_TREE_HARDNESS)); // So many youtube let's plays start with "OMG, this is taking so long to break this tree!" + .getDestroySpeed(level, pos) * DTConfigs.SERVER.treeHardnessMultiplier.get() * (radius * radius) / 64.0f * 8.0f; + return (float) Math.min(hardness, DTConfigs.SERVER.maxTreeHardness.get()); } /** NeoForge override */ @@ -370,7 +369,7 @@ public GrowSignal growSignal(Level level, BlockPos pos, GrowSignal signal) { /** NeoForge Override */ @SuppressWarnings("unused") public boolean isLadder(BlockState state, LevelReader level, BlockPos pos, LivingEntity entity) { - return Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_BRANCH_CLIMBING) && + return DTConfigs.SERVER.enableBranchClimbing.get() && entity instanceof Player && getFamily().branchIsLadder() && (!state.hasProperty(WATERLOGGED) || !state.getValue(WATERLOGGED)); diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicRootsBlock.java b/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicRootsBlock.java index c6a90f54b..f3aaf7a55 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicRootsBlock.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/branch/BasicRootsBlock.java @@ -11,9 +11,8 @@ import com.dtteam.dynamictrees.block.soil.AerialRootsSoilProperties; import com.dtteam.dynamictrees.block.soil.SoilBlock; import com.dtteam.dynamictrees.entity.FallingTreeEntity; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.loot.LootTableSupplier; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.GrowSignal; import com.dtteam.dynamictrees.systems.growthlogic.context.DirectionSelectionContext; import com.dtteam.dynamictrees.systems.nodemapper.NetVolumeNode; @@ -411,8 +410,8 @@ public float getHardness(BlockState state, BlockGetter level, BlockPos pos) { if (isFullBlock(state)) return getFamily().getPrimitiveCoveredRoots().orElse(Blocks.AIR).defaultDestroyTime(); final int radius = this.getRadius(level.getBlockState(pos)); final double hardness = this.getFamily().getPrimitiveLog().orElse(Blocks.AIR).defaultBlockState() - .getDestroySpeed(level, pos) * Services.CONFIG.getDoubleConfig(IConfigHelper.TREE_HARDNESS_MULTIPLIER) * (radius * radius) / 64.0f * 8.0f; - return (float) Math.min(hardness, Services.CONFIG.getDoubleConfig(IConfigHelper.MAX_TREE_HARDNESS)); // So many youtube let's plays start with "OMG, this is taking so long to break this tree!" + .getDestroySpeed(level, pos) * DTConfigs.SERVER.treeHardnessMultiplier.get() * (radius * radius) / 64.0f * 8.0f; + return (float) Math.min(hardness, DTConfigs.SERVER.maxTreeHardness.get()); } //This is the state that will replace the root when the tree is felled. diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/branch/BranchBlock.java b/common/src/main/java/com/dtteam/dynamictrees/block/branch/BranchBlock.java index 0dee6fb8d..fe953ab91 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/branch/BranchBlock.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/branch/BranchBlock.java @@ -15,9 +15,9 @@ import com.dtteam.dynamictrees.block.soil.SoilBlock; import com.dtteam.dynamictrees.data.DTLootTableBuilder; import com.dtteam.dynamictrees.entity.FallingTreeEntity; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.loot.LootTableSupplier; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.platform.*; import com.dtteam.dynamictrees.systems.FutureBreak; import com.dtteam.dynamictrees.systems.nodemapper.DestroyerNode; import com.dtteam.dynamictrees.systems.nodemapper.NetVolumeNode; @@ -631,7 +631,7 @@ protected void sloppyBreak(Level level, BlockPos cutPos, FallingTreeEntity.Destr final List woodDropList = destroyData.species.getBranchesDrops(level, destroyData.woodVolume); // If sloppy break drops are off clear all drops. - if (!Services.CONFIG.getBoolConfig(IConfigHelper.SLOPPY_BREAK_DROPS)) { + if (!DTConfigs.SERVER.sloppyBreakDrops.get()) { destroyData.leavesDrops.clear(); woodDropList.clear(); } diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/fruit/Fruit.java b/common/src/main/java/com/dtteam/dynamictrees/block/fruit/Fruit.java index 5f701d79e..805d2bcfa 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/fruit/Fruit.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/fruit/Fruit.java @@ -10,9 +10,8 @@ import com.dtteam.dynamictrees.api.worldgen.LevelContext; import com.dtteam.dynamictrees.block.DynamicBlockProperties; import com.dtteam.dynamictrees.block.Growable; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.DTLootTableBuilder; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.season.SeasonHelper; import com.dtteam.dynamictrees.treepack.Resettable; import com.dtteam.dynamictrees.utility.ResourceLocationUtils; @@ -304,7 +303,7 @@ public LootTable.Builder createBlockDrops(HolderLookup.Provider registries) { @NotNull @Override public Fruit reset() { - canBoneMeal = Services.CONFIG.isServerConfigLoaded() && Services.CONFIG.getBoolConfig(IConfigHelper.CAN_BONE_MEAL_FRUIT); + canBoneMeal = DTConfigs.SERVER_CONFIG.isLoaded() && DTConfigs.SERVER.canBoneMealFruit.get(); requiredProductionFactor = 0.3F; matureAction = Growable.MatureAction.DEFAULT; seasonalFactorGetter = (l,b)-> 1.0f; diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/leaves/DynamicLeavesBlock.java b/common/src/main/java/com/dtteam/dynamictrees/block/leaves/DynamicLeavesBlock.java index 785fe02d4..b2bc880b8 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/leaves/DynamicLeavesBlock.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/leaves/DynamicLeavesBlock.java @@ -12,8 +12,8 @@ import com.dtteam.dynamictrees.data.tags.DTEntityTypeTags; import com.dtteam.dynamictrees.item.Seed; import com.dtteam.dynamictrees.loot.DTLootContextParams; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.GrowSignal; import com.dtteam.dynamictrees.tree.ChunkTreeHelper; import com.dtteam.dynamictrees.tree.TreeHelper; @@ -123,7 +123,7 @@ public int age(LevelAccessor level, BlockPos pos, BlockState state, RandomSource */ @Override public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource rand) { - double growthMultiplier = Services.CONFIG.getDoubleConfig(IConfigHelper.TREE_GROWTH_MULTIPLIER); + double growthMultiplier = DTConfigs.SERVER.treeGrowthMultiplier.get(); if (rand.nextFloat() > growthMultiplier) { return; } @@ -545,11 +545,11 @@ public VoxelShape getBlockSupportShape(BlockState pState, BlockGetter pReader, B } protected boolean isMovementVanilla(){ - return Services.CONFIG.isServerConfigLoaded() && Services.CONFIG.getBoolConfig(IConfigHelper.VANILLA_LEAVES_COLLISION); + return DTConfigs.SERVER_CONFIG.isLoaded() && DTConfigs.SERVER.vanillaLeavesCollision.get(); } protected boolean isLeavesPassable() { - return (Services.CONFIG.isServerConfigLoaded() && Services.CONFIG.getBoolConfig(IConfigHelper.IS_LEAVES_PASSABLE)) + return (DTConfigs.SERVER_CONFIG.isLoaded() && DTConfigs.SERVER.isLeavesPassable.get()) || Services.PLATFORM.isModLoaded(DynamicTrees.PASSABLE_FOLIAGE); } @@ -580,8 +580,7 @@ protected void superFallOn(Level level, BlockState blockState, BlockPos pos, Ent @Override public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { - // We are only interested in Living things crashing through the canopy. - if (!Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_CANOPY_CRASH) || !(entity instanceof LivingEntity)) { + if (!DTConfigs.SERVER.enableCanopyCrash.get() || !(entity instanceof LivingEntity)) { return; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/leaves/LeavesProperties.java b/common/src/main/java/com/dtteam/dynamictrees/block/leaves/LeavesProperties.java index 8252f3f7b..f90dcd6fc 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/leaves/LeavesProperties.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/leaves/LeavesProperties.java @@ -655,15 +655,15 @@ public void setColorString(String colorString) { this.colorString = colorString; } - //@OnlyIn(Dist.CLIENT) + // private BlockColor colorMultiplier; - //@OnlyIn(Dist.CLIENT) + // public int treeFallColorMultiplier(BlockState state, BlockAndTintGetter level, BlockPos pos) { return this.foliageColorMultiplier(state, level, pos); } - //@OnlyIn(Dist.CLIENT) + // public int foliageColorMultiplier(BlockState state, BlockAndTintGetter level, BlockPos pos) { if (colorMultiplier == null) { return 0x00FF00FF; //purple if broken @@ -671,7 +671,7 @@ public int foliageColorMultiplier(BlockState state, BlockAndTintGetter level, Bl return colorMultiplier.getColor(state, level, pos, -1); } -// @OnlyIn(Dist.CLIENT) +// private void processColor() { int color = -1; if (this.colorNumber != null) { @@ -700,7 +700,7 @@ private void processColor() { this.colorMultiplier = (s, w, p, t) -> c == -1 ? Minecraft.getInstance().getBlockColors().getColor(getPrimitiveLeaves(), w, p, 0) : c; } - //@OnlyIn(Dist.CLIENT) + // public static void postInitClient() { REGISTRY.getAll().forEach(LeavesProperties::processColor); } diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/pod/Pod.java b/common/src/main/java/com/dtteam/dynamictrees/block/pod/Pod.java index de818532b..c799938a6 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/pod/Pod.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/pod/Pod.java @@ -9,9 +9,8 @@ import com.dtteam.dynamictrees.api.worldgen.LevelContext; import com.dtteam.dynamictrees.block.DynamicBlockProperties; import com.dtteam.dynamictrees.block.Growable; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.DTLootTableBuilder; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.treepack.Resettable; import com.dtteam.dynamictrees.utility.ResourceLocationUtils; import com.google.common.collect.Maps; @@ -362,7 +361,7 @@ public IntegerProperty getOffsetProperty (){ @NotNull @Override public Pod reset() { - canBoneMeal = Services.CONFIG.isServerConfigLoaded() && Services.CONFIG.getBoolConfig(IConfigHelper.CAN_BONE_MEAL_PODS); + canBoneMeal = DTConfigs.SERVER_CONFIG.isLoaded() && DTConfigs.SERVER.canBoneMealPods.get(); requiredProductionFactor = 0.3F; matureAction = Growable.MatureAction.DEFAULT; seasonalFactorGetter = (l,b)-> 1.0f; diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/sapling/DynamicSaplingBlock.java b/common/src/main/java/com/dtteam/dynamictrees/block/sapling/DynamicSaplingBlock.java index ce28bfdb7..2237a06c9 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/sapling/DynamicSaplingBlock.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/sapling/DynamicSaplingBlock.java @@ -1,7 +1,6 @@ package com.dtteam.dynamictrees.block.sapling; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.tree.TreeHelper; import com.dtteam.dynamictrees.tree.species.Species; import com.dtteam.dynamictrees.utility.CoordUtils; @@ -145,8 +144,7 @@ public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState s @Override public List getDrops(@NotNull BlockState state, @NotNull LootParams.Builder builder) { - // Drop nothing if sapling drops are disabled, nuthin'! - if (!Services.CONFIG.getBoolConfig(IConfigHelper.DYNAMIC_SAPLING_DROPS)) + if (!DTConfigs.SERVER.dynamicSaplingDrops.get()) return Collections.emptyList(); // If a loot table has been added load those drops instead. LootTable loottable = builder.getLevel().getServer().reloadableRegistries().getLootTable(getLootTable()); diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/soil/AerialRootsSoilProperties.java b/common/src/main/java/com/dtteam/dynamictrees/block/soil/AerialRootsSoilProperties.java index c9db12187..081294da3 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/soil/AerialRootsSoilProperties.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/soil/AerialRootsSoilProperties.java @@ -7,11 +7,10 @@ import com.dtteam.dynamictrees.api.treedata.TreePart; import com.dtteam.dynamictrees.block.BlockWithDynamicHardness; import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.tags.DTBlockTags; import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.entity.animation.FalloverAnimationHandler; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.entity.animation.*; import com.dtteam.dynamictrees.systems.nodemapper.NetVolumeNode; import com.dtteam.dynamictrees.systems.nodemapper.RootIntegrityNode; import com.dtteam.dynamictrees.tree.ChunkTreeHelper; @@ -142,7 +141,7 @@ public float getHardness(BlockState state, BlockGetter level, BlockPos pos) { if (up.getBlock() instanceof BlockWithDynamicHardness upBlock){ hardness = upBlock.getHardness(up, level, pos.above()); } - return (float)(hardness * Services.CONFIG.getDoubleConfig(IConfigHelper.ROOTY_BLOCK_HARDNESS_MULTIPLIER)); + return (float)(hardness * DTConfigs.SERVER.rootyBlockHardnessMultiplier.get()); } @Override diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/soil/SoilBlock.java b/common/src/main/java/com/dtteam/dynamictrees/block/soil/SoilBlock.java index c152baf21..7342c40e8 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/soil/SoilBlock.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/soil/SoilBlock.java @@ -10,9 +10,8 @@ import com.dtteam.dynamictrees.block.branch.BasicRootsBlock; import com.dtteam.dynamictrees.block.branch.BranchBlock; import com.dtteam.dynamictrees.block.leaves.LeavesProperties; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.GrowSignal; import com.dtteam.dynamictrees.tree.ChunkTreeHelper; import com.dtteam.dynamictrees.tree.TreeHelper; @@ -167,7 +166,7 @@ public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState s @Override public float getHardness(BlockState state, BlockGetter level, BlockPos pos) { - return (float) (getPrimitiveSoilState(state).getDestroySpeed(level, pos) * Services.CONFIG.getDoubleConfig(IConfigHelper.ROOTY_BLOCK_HARDNESS_MULTIPLIER)); + return (float) (getPrimitiveSoilState(state).getDestroySpeed(level, pos) * DTConfigs.SERVER.rootyBlockHardnessMultiplier.get()); } /////////////////////////////////////////// @@ -207,7 +206,7 @@ public boolean hasTileEntity(BlockState state) { @Override public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - double growthMultiplier = Services.CONFIG.getDoubleConfig(IConfigHelper.TREE_GROWTH_MULTIPLIER); + double growthMultiplier = DTConfigs.SERVER.treeGrowthMultiplier.get(); //Growth multiplier lower than 1 causes only some ticks to grow if (random.nextFloat() > growthMultiplier) return; diff --git a/common/src/main/java/com/dtteam/dynamictrees/block/soil/WaterSoilProperties.java b/common/src/main/java/com/dtteam/dynamictrees/block/soil/WaterSoilProperties.java index b49280c7e..7330153de 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/block/soil/WaterSoilProperties.java +++ b/common/src/main/java/com/dtteam/dynamictrees/block/soil/WaterSoilProperties.java @@ -3,8 +3,7 @@ import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.api.registry.TypedRegistry; import com.dtteam.dynamictrees.block.branch.BranchBlock; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.tree.TreeHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -87,7 +86,7 @@ public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState s @Override public float getHardness(BlockState state, BlockGetter level, BlockPos pos) { - return (float) (0.5 * Services.CONFIG.getDoubleConfig(IConfigHelper.ROOTY_BLOCK_HARDNESS_MULTIPLIER)); + return (float) (0.5 * DTConfigs.SERVER.rootyBlockHardnessMultiplier.get()); } @Override diff --git a/common/src/main/java/com/dtteam/dynamictrees/client/BlockColorMultipliers.java b/common/src/main/java/com/dtteam/dynamictrees/client/BlockColorMultipliers.java index 338ae2051..696381cc7 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/client/BlockColorMultipliers.java +++ b/common/src/main/java/com/dtteam/dynamictrees/client/BlockColorMultipliers.java @@ -9,7 +9,7 @@ import java.util.HashMap; import java.util.Map; -//@OnlyIn(Dist.CLIENT) +// public class BlockColorMultipliers { private static Map colorBase = new HashMap<>(); diff --git a/common/src/main/java/com/dtteam/dynamictrees/client/SoundInstanceHandler.java b/common/src/main/java/com/dtteam/dynamictrees/client/SoundInstanceHandler.java index 5ff0ee963..1c3ec1fdd 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/client/SoundInstanceHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/client/SoundInstanceHandler.java @@ -12,7 +12,7 @@ import java.util.HashMap; import java.util.Map; -//@OnlyIn(Dist.CLIENT) +// public class SoundInstanceHandler { private static final Map instances = new HashMap<>(); diff --git a/common/src/main/java/com/dtteam/dynamictrees/client/TextureHelper.java b/common/src/main/java/com/dtteam/dynamictrees/client/TextureHelper.java index f11b8db2c..8add702d2 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/client/TextureHelper.java +++ b/common/src/main/java/com/dtteam/dynamictrees/client/TextureHelper.java @@ -1,6 +1,6 @@ package com.dtteam.dynamictrees.client; -import com.dtteam.dynamictrees.platform.Services; +import com.dtteam.dynamictrees.platform.ClientServices; import com.mojang.blaze3d.platform.NativeImage; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -37,7 +37,7 @@ public PixelBuffer(TextureAtlasSprite sprite) { pixels = new int[w * h]; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { - pixels[calcPos(x, y)] = Services.MISC.getPixelRGBA(sprite, x, y); + pixels[calcPos(x, y)] = ClientServices.CLIENT.getPixelRGBA(sprite, x, y); } } diff --git a/common/src/main/java/com/dtteam/dynamictrees/client/ThickBranchRingsSprite.java b/common/src/main/java/com/dtteam/dynamictrees/client/ThickBranchRingsSprite.java index 7a141e13f..02c5ae83f 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/client/ThickBranchRingsSprite.java +++ b/common/src/main/java/com/dtteam/dynamictrees/client/ThickBranchRingsSprite.java @@ -5,10 +5,8 @@ import net.minecraft.client.resources.metadata.animation.FrameSize; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; -@OnlyIn(Dist.CLIENT) + public class ThickBranchRingsSprite extends SpriteContents { private static final int RESOLUTION = 16; private static final int LAYERS = 3; @@ -18,7 +16,7 @@ public class ThickBranchRingsSprite extends SpriteContents { }; public ThickBranchRingsSprite(ResourceLocation name, SpriteContents originalSprite){ - super(name, getFrameSize(originalSprite), processImage(originalSprite.originalImage), originalSprite.metadata); + super(name, getFrameSize(originalSprite), processImage(originalSprite.originalImage), originalSprite.metadata()); } private static FrameSize getFrameSize(SpriteContents sprite){ diff --git a/common/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java b/common/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java new file mode 100644 index 000000000..35990e5eb --- /dev/null +++ b/common/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java @@ -0,0 +1,187 @@ +package com.dtteam.dynamictrees.config; + +import com.dtteam.dynamictrees.*; +import com.dtteam.dynamictrees.block.branch.*; +import com.dtteam.dynamictrees.systems.season.*; +import com.dtteam.dynamictrees.tree.species.*; +import net.neoforged.neoforge.common.*; +import org.apache.commons.lang3.tuple.*; + +import java.util.*; + +public class DTConfigs { + + public static final ModConfigSpec SERVER_CONFIG; + public static final DTConfigs SERVER; + public static final ModConfigSpec COMMON_CONFIG; + public static final DTConfigs COMMON; + public static final ModConfigSpec CLIENT_CONFIG; + public static final DTConfigs CLIENT; + + static { + Pair serverPair = new ModConfigSpec.Builder().configure(DTConfigs::buildServerConfig); + SERVER_CONFIG = serverPair.getRight(); + SERVER = serverPair.getLeft(); + + Pair commonPair = new ModConfigSpec.Builder().configure(DTConfigs::buildCommonConfig); + COMMON_CONFIG = commonPair.getRight(); + COMMON = commonPair.getLeft(); + + Pair clientPair = new ModConfigSpec.Builder().configure(DTConfigs::buildClientConfig); + CLIENT_CONFIG = clientPair.getRight(); + CLIENT = clientPair.getLeft(); + } + + public ModConfigSpec.DoubleValue leavesSeedDropRate; + public ModConfigSpec.DoubleValue minSeasonalLeavesSeedDropRate; + public ModConfigSpec.DoubleValue voluntarySeedDropRate; + public ModConfigSpec.DoubleValue minSeasonalVoluntarySeedDropRate; + public ModConfigSpec.DoubleValue seedPlantRate; + public ModConfigSpec.IntValue seedTimeToLive; + public ModConfigSpec.BooleanValue seedOnlyForest; + public ModConfigSpec.DoubleValue seedMinForestness; + public ModConfigSpec.BooleanValue climateAffectsFruitsAndPods; + + public ModConfigSpec.DoubleValue treeGrowthMultiplier; + public ModConfigSpec.DoubleValue treeHarvestMultiplier; + public ModConfigSpec.DoubleValue maxTreeHardness; + public ModConfigSpec.DoubleValue treeHardnessMultiplier; + public ModConfigSpec.BooleanValue dropSticks; + public ModConfigSpec.DoubleValue scaleBiomeGrowthRate; + public ModConfigSpec.DoubleValue diseaseChance; + public ModConfigSpec.IntValue maxBranchRotRadius; + public ModConfigSpec.DoubleValue rootyBlockHardnessMultiplier; + public ModConfigSpec.EnumValue swampOaksInWater; + public ModConfigSpec.IntValue boneMealGrowthPulses; + + public ModConfigSpec.BooleanValue isLeavesPassable; + public ModConfigSpec.BooleanValue vanillaLeavesCollision; + public ModConfigSpec.BooleanValue enableBranchClimbing; + public ModConfigSpec.BooleanValue enableCanopyCrash; + public ModConfigSpec.EnumValue axeDamageMode; + public ModConfigSpec.BooleanValue enableFallingTrees; + public ModConfigSpec.BooleanValue enableFallingTreeDamage; + public ModConfigSpec.DoubleValue fallingTreeDamageMultiplier; + public ModConfigSpec.BooleanValue dirtBucketPlacesDirt; + public ModConfigSpec.BooleanValue sloppyBreakDrops; + public ModConfigSpec.IntValue minRadiusForStrip; + public ModConfigSpec.BooleanValue enableStripRadiusReduction; + public ModConfigSpec.BooleanValue canBoneMealFruit; + public ModConfigSpec.BooleanValue canBoneMealPods; + public ModConfigSpec.BooleanValue dynamicSaplingDrops; + + public ModConfigSpec.BooleanValue replaceVanillaSaplings; + public ModConfigSpec.BooleanValue replaceNyliumFungi; + public ModConfigSpec.BooleanValue cancelVanillaVillageTrees; + public ModConfigSpec.IntValue maxFallingTreeLeavesParticles; + + public ModConfigSpec.BooleanValue generatePodzol; + public ModConfigSpec.BooleanValue worldGen; + public ModConfigSpec.ConfigValue> dimensionBlacklist; + + public ModConfigSpec.BooleanValue generateDirtBucketRecipes; + public ModConfigSpec.BooleanValue generateMegaSeedRecipe; + public ModConfigSpec.ConfigValue biocharBrewingBase; + + public ModConfigSpec.ConfigValue preferredSeasonMod; + public ModConfigSpec.BooleanValue enableSeasonalSeedDrop; + public ModConfigSpec.BooleanValue enableSeasonalGrowth; + public ModConfigSpec.BooleanValue enableSeasonalFruitProduction; + public ModConfigSpec.DoubleValue wetSeasonOffset; + + public ModConfigSpec.BooleanValue debug; + + private DTConfigs() {} + + private static DTConfigs buildServerConfig(ModConfigSpec.Builder builder) { + DTConfigs config = new DTConfigs(); + + builder.push("seeds"); + config.leavesSeedDropRate = builder.defineInRange("leavesSeedDropRate", 1.0, 0.0, 64.0); + config.minSeasonalLeavesSeedDropRate = builder.defineInRange("minSeasonalLeavesSeedDropRate", 0.15, 0.0, 1.0); + config.voluntarySeedDropRate = builder.defineInRange("voluntarySeedDropRate", 0.01, 0.0, 1.0); + config.minSeasonalVoluntarySeedDropRate = builder.defineInRange("minSeasonalVoluntarySeedDropRate", 0.0, 0.0, 1.0); + config.seedPlantRate = builder.defineInRange("seedPlantRate", 1.0 / 6.0, 0.0, 1.0); + config.seedTimeToLive = builder.defineInRange("seedTimeToLive", 1200, 0, 6000); + config.seedOnlyForest = builder.define("seedOnlyForest", true); + config.seedMinForestness = builder.defineInRange("seedMinForestness", 0.0, 0.0, 1.0); + config.climateAffectsFruitsAndPods = builder.define("climateAffectsFruitsAndPods", true); + builder.pop(); + + builder.push("trees"); + config.treeGrowthMultiplier = builder.defineInRange("treeGrowthMultiplier", 0.5, 0, 16.0); + config.treeHarvestMultiplier = builder.defineInRange("treeHarvestMultiplier", 1.0, 0.0, 128.0); + config.maxTreeHardness = builder.defineInRange("maxTreeHardness", 20.0, 1.0, 200.0); + config.treeHardnessMultiplier = builder.defineInRange("treeHardnessMultiplier", 1.0, 1.0/128.0, 32.0); + config.dropSticks = builder.define("dropSticks", true); + config.scaleBiomeGrowthRate = builder.defineInRange("scaleBiomeGrowthRate", 0.5, 0.0, 1.0); + config.diseaseChance = builder.defineInRange("diseaseChance", 0.0, 0.0, 1.0); + config.maxBranchRotRadius = builder.defineInRange("maxBranchRotRadius", 7, 0, ThickBranchBlock.MAX_RADIUS_THICK); + config.rootyBlockHardnessMultiplier = builder.defineInRange("rootyBlockHardnessMultiplier", 40.0, 0.0, 128.0); + config.swampOaksInWater = builder.defineEnum("swampOaksInWater", SwampSpecies.WaterSurfaceGenerationState.ROOTED); + config.boneMealGrowthPulses = builder.defineInRange("boneMealGrowthPulses", 1, 1, 512); + builder.pop(); + + builder.push("interaction"); + config.isLeavesPassable = builder.define("isLeavesPassable", false); + config.vanillaLeavesCollision = builder.define("vanillaLeavesCollision", false); + config.enableBranchClimbing = builder.define("enableBranchClimbing", true); + config.enableCanopyCrash = builder.define("enableCanopyCrash", true); + config.axeDamageMode = builder.defineEnum("axeDamageMode", DynamicTrees.AxeDamage.THICKNESS); + config.enableFallingTrees = builder.define("enableFallingTrees", true); + config.enableFallingTreeDamage = builder.define("enableFallingTreeDamage", true); + config.fallingTreeDamageMultiplier = builder.defineInRange("fallingTreeDamageMultiplier", 1.0, 0.0, 100.0); + config.dirtBucketPlacesDirt = builder.define("dirtBucketPlacesDirt", true); + config.sloppyBreakDrops = builder.define("sloppyBreakDrops", false); + config.minRadiusForStrip = builder.defineInRange("minRadiusForStrip", 6, 0, 24); + config.enableStripRadiusReduction = builder.define("enableStripRadiusReduction", true); + config.canBoneMealFruit = builder.define("canBoneMealFruit", false); + config.canBoneMealPods = builder.define("canBoneMealPods", true); + config.dynamicSaplingDrops = builder.define("dynamicSaplingDrops", true); + builder.pop(); + + builder.push("world"); + config.generatePodzol = builder.define("generatePodzol", true); + config.worldGen = builder.define("worldGen", true); + config.dimensionBlacklist = builder.define("dimensionsBlacklist", new ArrayList<>()); + builder.pop(); + + builder.push("debug"); + config.debug = builder.define("debug", false); + builder.pop(); + + return config; + } + + private static DTConfigs buildCommonConfig(ModConfigSpec.Builder builder) { + DTConfigs config = new DTConfigs(); + + builder.push("vanilla"); + config.replaceVanillaSaplings = builder.define("replaceVanillaSaplings", false); + config.replaceNyliumFungi = builder.define("replaceNyliumFungi", true); + config.cancelVanillaVillageTrees = builder.define("cancelVanillaVillageTrees", true); + config.maxFallingTreeLeavesParticles = builder.defineInRange("maxFallingTreeLeavesParticles", 400, 0, 4096); + builder.pop(); + + builder.push("misc"); + config.generateDirtBucketRecipes = builder.define("generateDirtBucketRecipes", true); + config.generateMegaSeedRecipe = builder.define("generateMegaSeedRecipe", false); + config.biocharBrewingBase = builder.define("biocharBrewingBase", "minecraft:thick"); + builder.pop(); + + builder.push("integration"); + config.preferredSeasonMod = builder.define("preferredSeasonMod", SeasonCompatibilityHandler.ANY); + config.enableSeasonalSeedDrop = builder.define("enableSeasonalSeedDropFactor", true); + config.enableSeasonalGrowth = builder.define("enableSeasonalGrowthFactor", true); + config.enableSeasonalFruitProduction = builder.define("enableSeasonalFruitProductionFactor", true); + config.wetSeasonOffset = builder.defineInRange("wetSeasonOffset", 2.5, 0.0, 4.0); + builder.pop(); + + return config; + } + + private static DTConfigs buildClientConfig(ModConfigSpec.Builder builder) { + return new DTConfigs(); + } + +} diff --git a/common/src/main/java/com/dtteam/dynamictrees/data/DirtBucketRecipeHandler.java b/common/src/main/java/com/dtteam/dynamictrees/data/DirtBucketRecipeHandler.java index 322325bb4..b2ca19956 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/data/DirtBucketRecipeHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/data/DirtBucketRecipeHandler.java @@ -1,8 +1,7 @@ package com.dtteam.dynamictrees.data; import com.dtteam.dynamictrees.DynamicTrees; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.registry.DTRegistries; import com.dtteam.dynamictrees.tree.species.Species; import net.minecraft.core.NonNullList; @@ -36,11 +35,11 @@ public static void registerDirtBucketRecipes(final Collection> c final ResourceLocation registryName = species.getRegistryName(); - if (Services.CONFIG.getBoolConfig(IConfigHelper.GENERATE_DIRT_BUCKET_RECIPES)){ + if (DTConfigs.COMMON.generateDirtBucketRecipes.get()){ generateSaplingRecipes(craftingRecipes, species, registryName); } - if (Services.CONFIG.getBoolConfig(IConfigHelper.GENERATE_MEGA_SEED_RECIPE)){ + if (DTConfigs.COMMON.generateMegaSeedRecipe.get()){ generateMegaSeedRecipes(craftingRecipes, species, registryName); } } diff --git a/common/src/main/java/com/dtteam/dynamictrees/entity/FallingTreeEntity.java b/common/src/main/java/com/dtteam/dynamictrees/entity/FallingTreeEntity.java index 0ce7fd2f4..2821aab69 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/entity/FallingTreeEntity.java +++ b/common/src/main/java/com/dtteam/dynamictrees/entity/FallingTreeEntity.java @@ -8,10 +8,10 @@ import com.dtteam.dynamictrees.entity.animation.AnimationHandler; import com.dtteam.dynamictrees.entity.animation.AnimationHandlers; import com.dtteam.dynamictrees.entity.animation.DataAnimationHandler; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.model.FallingTreeEntityModelTrackerCache; import com.dtteam.dynamictrees.model.ModelTracker; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.platform.*; import com.dtteam.dynamictrees.registry.DTRegistries; import com.dtteam.dynamictrees.tree.TreeHelper; import com.dtteam.dynamictrees.tree.species.Species; @@ -335,7 +335,7 @@ protected void updateNeighbors() { } protected AnimationHandler selectAnimationHandler() { - return Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_FALLING_TREES) ? destroyData.species.selectAnimationHandler(this) : AnimationHandlers.voidAnimationHandler; + return DTConfigs.SERVER.enableFallingTrees.get() ? destroyData.species.selectAnimationHandler(this) : AnimationHandlers.voidAnimationHandler; } public AnimationHandler defaultAnimationHandler() { diff --git a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/AnimationHandler.java b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/AnimationHandler.java index fe97af290..25dfbebd2 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/AnimationHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/AnimationHandler.java @@ -14,10 +14,10 @@ public interface AnimationHandler { boolean shouldDie(FallingTreeEntity entity); -// @OnlyIn(Dist.CLIENT) +// void renderTransform(FallingTreeEntity entity, float entityYaw, float partialTick, PoseStack poseStack); -// @OnlyIn(Dist.CLIENT) +// boolean shouldRender(FallingTreeEntity entity, double x, double y, double z); } \ No newline at end of file diff --git a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/FalloverAnimationHandler.java b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/FalloverAnimationHandler.java index 8d24abd8a..20181541c 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/FalloverAnimationHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/FalloverAnimationHandler.java @@ -3,10 +3,9 @@ import com.dtteam.dynamictrees.api.network.BranchDestructionData; import com.dtteam.dynamictrees.block.branch.BranchBlock; import com.dtteam.dynamictrees.client.SoundInstanceHandler; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.tags.DTEntityTypeTags; import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.tree.TreeHelper; import com.dtteam.dynamictrees.tree.species.Species; import com.dtteam.dynamictrees.utility.MathUtils; @@ -107,7 +106,7 @@ private Vec3 rotateAroundAxis(Vec3 in, Vec3 axis, double theta){ protected void flingLeavesParticles(FallingTreeEntity entity, float fallSpeed){ int bounces = getData(entity).bounces; if (bounces > 1) return; - int maxParticleBlocks = Services.CONFIG.getIntConfig(IConfigHelper.MAX_FALLING_TREE_LEAVES_PARTICLES); + int maxParticleBlocks = DTConfigs.COMMON.maxFallingTreeLeavesParticles.get(); if (maxParticleBlocks == 0) return; BranchDestructionData data = entity.getDestroyData(); @@ -224,21 +223,19 @@ public void handleMotion(FallingTreeEntity entity) { //Crush living things with clumsy dead trees Level level = entity.level(); - if (Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_FALLING_TREE_DAMAGE) && !level.isClientSide) { + if (DTConfigs.SERVER.enableFallingTreeDamage.get() && !level.isClientSide) { List elist = testEntityCollision(entity); for (LivingEntity living : elist) { if (!getData(entity).entitiesHit.contains(living) && !living.getType().is(DTEntityTypeTags.FALLING_TREE_DAMAGE_IMMUNE)) { getData(entity).entitiesHit.add(living); float damage = entity.getDestroyData().woodVolume.getVolume() * Math.abs(fallSpeed) * 3f; if (getData(entity).bounces == 0 && damage > 2) { - //System.out.println("damage: " + damage); living.setDeltaMovement( living.getDeltaMovement().x + (level.random.nextFloat() * entity.getDestroyData().toolDir.getOpposite().getStepX() * damage * 0.2f), living.getDeltaMovement().y + (level.random.nextFloat() * fallSpeed * 0.25f), living.getDeltaMovement().z + (level.random.nextFloat() * entity.getDestroyData().toolDir.getOpposite().getStepZ() * damage * 0.2f)); living.setDeltaMovement(living.getDeltaMovement().x + (level.random.nextFloat() - 0.5), living.getDeltaMovement().y, living.getDeltaMovement().z + (level.random.nextFloat() - 0.5)); - damage *= Services.CONFIG.getDoubleConfig(IConfigHelper.FALLING_TREE_DAMAGE_MULTIPLIER); - //System.out.println("Tree Falling Damage: " + damage + "/" + living.getHealth()); + damage *= DTConfigs.SERVER.fallingTreeDamageMultiplier.get(); living.hurt(AnimationConstants.treeDamage(level.registryAccess()), damage); } } @@ -384,7 +381,7 @@ public boolean shouldDie(FallingTreeEntity entity) { } @Override -// @OnlyIn(Dist.CLIENT) +// public void renderTransform(FallingTreeEntity entity, float entityYaw, float partialTick, PoseStack poseStack) { float yaw = Mth.wrapDegrees(MathUtils.angleDegreesInterpolate(entity.yRotO, entity.getYRot(), partialTick)); @@ -407,7 +404,7 @@ public void renderTransform(FallingTreeEntity entity, float entityYaw, float par } @Override -// @OnlyIn(Dist.CLIENT) +// public boolean shouldRender(FallingTreeEntity entity, double x, double y, double z) { return true; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/PhysicsAnimationHandler.java b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/PhysicsAnimationHandler.java index 678681ec3..3781f6b54 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/PhysicsAnimationHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/PhysicsAnimationHandler.java @@ -161,7 +161,7 @@ public boolean shouldDie(FallingTreeEntity entity) { } @Override -// @OnlyIn(Dist.CLIENT) +// public void renderTransform(FallingTreeEntity entity, float entityYaw, float partialTick, PoseStack poseStack) { final float yaw = Mth.wrapDegrees(MathUtils.angleDegreesInterpolate(entity.yRotO, entity.getYRot(), partialTick)); final float pit = Mth.wrapDegrees(MathUtils.angleDegreesInterpolate(entity.xRotO, entity.getXRot(), partialTick)); @@ -174,7 +174,7 @@ public void renderTransform(FallingTreeEntity entity, float entityYaw, float par } @Override -// @OnlyIn(Dist.CLIENT) +// public boolean shouldRender(FallingTreeEntity entity, double x, double y, double z) { return true; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/VoidAnimationHandler.java b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/VoidAnimationHandler.java index d2a9551be..4d4389731 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/entity/animation/VoidAnimationHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/entity/animation/VoidAnimationHandler.java @@ -32,7 +32,7 @@ public void handleMotion(FallingTreeEntity entity) {} public void dropPayload(FallingTreeEntity entity) {} @Override -// @OnlyIn(Dist.CLIENT) +// public boolean shouldRender(FallingTreeEntity entity, double x, double y, double z) { return false; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/item/DirtBucket.java b/common/src/main/java/com/dtteam/dynamictrees/item/DirtBucket.java index 2d5ee0b0b..605094c47 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/item/DirtBucket.java +++ b/common/src/main/java/com/dtteam/dynamictrees/item/DirtBucket.java @@ -1,7 +1,6 @@ package com.dtteam.dynamictrees.item; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.registry.DTRegistries; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -43,7 +42,7 @@ public InteractionResultHolder use(Level world, Player player, Intera } } - if (Services.CONFIG.getBoolConfig(IConfigHelper.DIRT_BUCKET_PLACES_DIRT)) { + if (DTConfigs.SERVER.dirtBucketPlacesDirt.get()) { if (blockRayTraceResult.getType() != HitResult.Type.BLOCK) { return new InteractionResultHolder<>(InteractionResult.PASS, itemStack); } else { diff --git a/common/src/main/java/com/dtteam/dynamictrees/item/Seed.java b/common/src/main/java/com/dtteam/dynamictrees/item/Seed.java index 2b260ae08..b6bab4adb 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/item/Seed.java +++ b/common/src/main/java/com/dtteam/dynamictrees/item/Seed.java @@ -3,8 +3,8 @@ import com.dtteam.dynamictrees.api.lazyvalue.LazyValue; import com.dtteam.dynamictrees.api.worldgen.LevelContext; import com.dtteam.dynamictrees.block.sapling.PottedSaplingBlock; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; +import com.dtteam.dynamictrees.platform.*; import com.dtteam.dynamictrees.registry.DTRegistries; import com.dtteam.dynamictrees.tree.species.Species; import com.dtteam.dynamictrees.worldgen.DynamicTreeGenerationContext; @@ -122,9 +122,9 @@ public boolean shouldPlant(Level level, BlockPos pos, ItemStack seedStack) { return false; } - float plantChance = (float) (getSpecies().biomeSuitability(level, pos) * Services.CONFIG.getDoubleConfig(IConfigHelper.SEED_PLANT_RATE)); + float plantChance = (float) (getSpecies().biomeSuitability(level, pos) * DTConfigs.SERVER.seedPlantRate.get()); - if (Services.CONFIG.getBoolConfig(IConfigHelper.SEED_ONLY_FOREST)) { + if (DTConfigs.SERVER.seedOnlyForest.get()) { // plantChance *= BiomeDatabases.getDimensionalOrDefault(level.dimension().location()) // .getForestness(level.getBiome(pos)); } @@ -150,7 +150,7 @@ public boolean hasForcePlant(ItemStack seedStack) { } public int getTimeToLive(ItemStack seedStack) { - int lifespan = Services.CONFIG.getIntConfig(IConfigHelper.SEED_TIME_TO_LIVE);//1 minute by default(helps with lag) + int lifespan = DTConfigs.SERVER.seedTimeToLive.get(); // if (seedStack.hasTag()) { // CompoundTag nbtData = seedStack.getTag(); // assert nbtData != null; diff --git a/common/src/main/java/com/dtteam/dynamictrees/loot/condition/SeasonalSeedDropChance.java b/common/src/main/java/com/dtteam/dynamictrees/loot/condition/SeasonalSeedDropChance.java index 6096a218e..44527b540 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/loot/condition/SeasonalSeedDropChance.java +++ b/common/src/main/java/com/dtteam/dynamictrees/loot/condition/SeasonalSeedDropChance.java @@ -1,8 +1,7 @@ package com.dtteam.dynamictrees.loot.condition; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.loot.DTLootContextParams; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.registry.DTRegistries; import com.mojang.datafixers.util.Unit; import com.mojang.serialization.Codec; @@ -34,10 +33,9 @@ public LootItemConditionType getType() { public boolean test(LootContext context) { Float seasonalSeedDropFactor = context.getParamOrNull(DTLootContextParams.SEASONAL_SEED_DROP_FACTOR); assert seasonalSeedDropFactor != null; - // Adjusted to a minimum of 0.15 to ensure there are at least some seed drops all year round. - double minimumDropRate = Services.CONFIG.getDoubleConfig(IConfigHelper.MIN_SEASONAL_LEAVES_SEED_DROP_RATE); + double minimumDropRate = DTConfigs.SERVER.minSeasonalLeavesSeedDropRate.get(); double adjustedSeasonalSeedDropFactor = Math.min(seasonalSeedDropFactor + minimumDropRate, 1.0F); - return Services.CONFIG.getDoubleConfig(IConfigHelper.LEAVES_SEED_DROP_RATE) * adjustedSeasonalSeedDropFactor > context.getRandom().nextFloat(); + return DTConfigs.SERVER.leavesSeedDropRate.get() * adjustedSeasonalSeedDropFactor > context.getRandom().nextFloat(); } public static LootItemCondition.Builder seasonalSeedDropChance() { diff --git a/common/src/main/java/com/dtteam/dynamictrees/loot/condition/VoluntarySeedDropChance.java b/common/src/main/java/com/dtteam/dynamictrees/loot/condition/VoluntarySeedDropChance.java index ce0a1470d..77c517b45 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/loot/condition/VoluntarySeedDropChance.java +++ b/common/src/main/java/com/dtteam/dynamictrees/loot/condition/VoluntarySeedDropChance.java @@ -1,8 +1,7 @@ package com.dtteam.dynamictrees.loot.condition; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.loot.DTLootContextParams; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.registry.DTRegistries; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; @@ -36,9 +35,9 @@ public LootItemConditionType getType() { public boolean test(LootContext context) { final Float seasonalSeedDropFactor = context.getParamOrNull(DTLootContextParams.SEASONAL_SEED_DROP_FACTOR); assert seasonalSeedDropFactor != null; - double minimumDropRate = Services.CONFIG.getDoubleConfig(IConfigHelper.MIN_SEASONAL_VOLUNTARY_SEED_DROP_RATE); + double minimumDropRate = DTConfigs.SERVER.minSeasonalVoluntarySeedDropRate.get(); double adjustedSeasonalSeedDropFactor = Math.min(seasonalSeedDropFactor + minimumDropRate, 1.0F); - return rarity * Services.CONFIG.getDoubleConfig(IConfigHelper.VOLUNTARY_SEED_DROP_RATE) * adjustedSeasonalSeedDropFactor > context.getRandom().nextFloat(); + return rarity * DTConfigs.SERVER.voluntarySeedDropRate.get() * adjustedSeasonalSeedDropFactor > context.getRandom().nextFloat(); } public static LootItemCondition.Builder voluntarySeedDropChance() { diff --git a/common/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelTrackerCache.java b/common/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelTrackerCache.java index f382750e6..475b9e95c 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelTrackerCache.java +++ b/common/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelTrackerCache.java @@ -1,7 +1,7 @@ package com.dtteam.dynamictrees.model; import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.platform.Services; +import com.dtteam.dynamictrees.platform.ClientServices; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; @@ -17,7 +17,7 @@ public class FallingTreeEntityModelTrackerCache { @Nullable public static FallingTreeEntityModel getOrCreateModel(FallingTreeEntity entity) { if (entity.level().isClientSide()) - return models.computeIfAbsent(entity.getId(), i -> Services.MISC.newFallingTreeEntityModel(entity)); + return models.computeIfAbsent(entity.getId(), i -> ClientServices.CLIENT.newFallingTreeEntityModel(entity)); return null; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/platform/ClientServices.java b/common/src/main/java/com/dtteam/dynamictrees/platform/ClientServices.java new file mode 100644 index 000000000..2dacb9f3c --- /dev/null +++ b/common/src/main/java/com/dtteam/dynamictrees/platform/ClientServices.java @@ -0,0 +1,20 @@ +package com.dtteam.dynamictrees.platform; + +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.platform.services.IClientHelper; + +import java.util.ServiceLoader; + + +public class ClientServices { + + public static final IClientHelper CLIENT = load(IClientHelper.class); + + public static T load(Class clazz) { + final T loadedService = ServiceLoader.load(clazz) + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + DynamicTrees.LOG.debug("Loaded {} for service {}", loadedService, clazz); + return loadedService; + } +} diff --git a/common/src/main/java/com/dtteam/dynamictrees/platform/services/IClientHelper.java b/common/src/main/java/com/dtteam/dynamictrees/platform/services/IClientHelper.java new file mode 100644 index 000000000..fd6b025dc --- /dev/null +++ b/common/src/main/java/com/dtteam/dynamictrees/platform/services/IClientHelper.java @@ -0,0 +1,15 @@ +package com.dtteam.dynamictrees.platform.services; + +import com.dtteam.dynamictrees.entity.FallingTreeEntity; +import com.dtteam.dynamictrees.model.FallingTreeEntityModel; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + + +public interface IClientHelper { + + int getPixelRGBA(TextureAtlasSprite sprite, int x, int y); + + + FallingTreeEntityModel newFallingTreeEntityModel(FallingTreeEntity entity); + +} diff --git a/common/src/main/java/com/dtteam/dynamictrees/platform/services/IMiscHelper.java b/common/src/main/java/com/dtteam/dynamictrees/platform/services/IMiscHelper.java index b0bd7ad5c..d00377915 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/platform/services/IMiscHelper.java +++ b/common/src/main/java/com/dtteam/dynamictrees/platform/services/IMiscHelper.java @@ -1,19 +1,12 @@ package com.dtteam.dynamictrees.platform.services; -import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.model.FallingTreeEntityModel; import com.dtteam.dynamictrees.worldgen.IDTBiomeHolderSet; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; public interface IMiscHelper { - int getPixelRGBA (TextureAtlasSprite sprite, int x, int y); - - FallingTreeEntityModel newFallingTreeEntityModel (FallingTreeEntity entity); - - boolean isLevelRestoringBlockSnapshots (Level level); + boolean isLevelRestoringBlockSnapshots(Level level); MinecraftServer getCurrentServer(); diff --git a/common/src/main/java/com/dtteam/dynamictrees/systems/genfeature/PodzolGenFeature.java b/common/src/main/java/com/dtteam/dynamictrees/systems/genfeature/PodzolGenFeature.java index fa90ce173..d2bce9b8b 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/systems/genfeature/PodzolGenFeature.java +++ b/common/src/main/java/com/dtteam/dynamictrees/systems/genfeature/PodzolGenFeature.java @@ -6,9 +6,8 @@ import com.dtteam.dynamictrees.block.branch.TrunkShellBlock; import com.dtteam.dynamictrees.block.soil.SoilBlock; import com.dtteam.dynamictrees.block.soil.SoilHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.tags.DTBlockTags; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.genfeature.context.PostGrowContext; import com.dtteam.dynamictrees.systems.nodemapper.FindEndsNode; import com.dtteam.dynamictrees.tree.TreeHelper; @@ -54,7 +53,7 @@ protected GenFeatureConfiguration createDefaultConfiguration() { @Override protected boolean postGrow(GenFeatureConfiguration configuration, PostGrowContext context) { - if (!Services.CONFIG.getBoolConfig(IConfigHelper.GENERATE_PODZOL)) return false; + if (!DTConfigs.SERVER.generatePodzol.get()) return false; final LevelAccessor level = context.level(); final FindEndsNode endFinder = new FindEndsNode(); diff --git a/common/src/main/java/com/dtteam/dynamictrees/systems/season/ActiveSeasonGrowthCalculator.java b/common/src/main/java/com/dtteam/dynamictrees/systems/season/ActiveSeasonGrowthCalculator.java index de7060b09..e983cbb1f 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/systems/season/ActiveSeasonGrowthCalculator.java +++ b/common/src/main/java/com/dtteam/dynamictrees/systems/season/ActiveSeasonGrowthCalculator.java @@ -3,8 +3,7 @@ import com.dtteam.dynamictrees.api.season.ClimateZoneType; import com.dtteam.dynamictrees.api.season.SeasonGrowthCalculator; import com.dtteam.dynamictrees.api.season.SeasonType; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import net.minecraft.util.Mth; public class ActiveSeasonGrowthCalculator implements SeasonGrowthCalculator { @@ -15,7 +14,7 @@ protected float clippedSineWave(float seasonValue, float qPhase, float amplitude private float peakClimateOffset(SeasonType type){ float summerOffset = -0.5f; - float wetSeasonOffset = (float)(summerOffset + Services.CONFIG.getDoubleConfig(IConfigHelper.WET_SEASON_OFFSET)); + float wetSeasonOffset = (float)(summerOffset + DTConfigs.COMMON.wetSeasonOffset.get()); if (type == SeasonType.DRY_WET){ return wetSeasonOffset; } else return summerOffset; diff --git a/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonCompatibilityHandler.java b/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonCompatibilityHandler.java index a24472f36..fb723f8ae 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonCompatibilityHandler.java +++ b/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonCompatibilityHandler.java @@ -2,8 +2,8 @@ import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.api.season.SeasonManager; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.google.common.collect.Maps; import org.apache.logging.log4j.LogManager; @@ -60,7 +60,7 @@ public static void registerBuiltInSeasonManagers() { public static final String ANY = "*"; public static void reloadSeasonManager() { - final String modId = Services.CONFIG.getStringConfig(IConfigHelper.PREFERRED_SEASON_MOD); + final String modId = DTConfigs.COMMON.preferredSeasonMod.get(); // If disabled, use null manager. if (Objects.equals(modId, DISABLED)) { diff --git a/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonHelper.java b/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonHelper.java index fb2a3192a..cb338b717 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonHelper.java +++ b/common/src/main/java/com/dtteam/dynamictrees/systems/season/SeasonHelper.java @@ -3,8 +3,7 @@ import com.dtteam.dynamictrees.api.season.ClimateZoneType; import com.dtteam.dynamictrees.api.season.SeasonManager; import com.dtteam.dynamictrees.api.worldgen.LevelContext; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; @@ -29,22 +28,22 @@ static public void updateTick(Level level, long dayTime) { } static public float globalSeasonalGrowthFactor(LevelContext levelContext, BlockPos rootPos, float offset) { - return Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_SEASONAL_GROWTH) + return DTConfigs.COMMON.enableSeasonalGrowth.get() ? SeasonCompatibilityHandler.getSeasonManager().getGrowthFactor(levelContext.level(), rootPos, offset) : 1.0F; } static public float globalSeasonalSeedDropFactor(LevelContext levelContext, BlockPos pos, float offset) { - return Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_SEASONAL_SEED_DROP) + return DTConfigs.COMMON.enableSeasonalSeedDrop.get() ? SeasonCompatibilityHandler.getSeasonManager().getSeedDropFactor(levelContext.level(), pos, offset) : 1.0F; } static public float globalSeasonalFruitProductionFactor(LevelContext levelContext, BlockPos pos, float offset) { - return Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_SEASONAL_SEED_FRUIT_PRODUCTION) + return DTConfigs.COMMON.enableSeasonalFruitProduction.get() ? SeasonCompatibilityHandler.getSeasonManager().getFruitProductionFactor(levelContext.level(), pos, offset) : 1.0F; } static public Float getPeakFruitProductionSeason(LevelContext levelContext, BlockPos pos, float offset) { - return Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_SEASONAL_SEED_FRUIT_PRODUCTION) + return DTConfigs.COMMON.enableSeasonalFruitProduction.get() ? SeasonCompatibilityHandler.getSeasonManager().getPeakFruitProductionSeasonValue(levelContext.level(), pos, offset) : null; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/tree/family/Family.java b/common/src/main/java/com/dtteam/dynamictrees/tree/family/Family.java index 251a8cd54..4cd017b06 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/tree/family/Family.java +++ b/common/src/main/java/com/dtteam/dynamictrees/tree/family/Family.java @@ -19,8 +19,8 @@ import com.dtteam.dynamictrees.data.tags.DTItemTags; import com.dtteam.dynamictrees.entity.FallingTreeEntity; import com.dtteam.dynamictrees.entity.animation.AnimationHandler; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.cell.MetadataCell; import com.dtteam.dynamictrees.tree.TreeHelper; import com.dtteam.dynamictrees.tree.species.Species; @@ -178,9 +178,9 @@ public Species getSpeciesForLocation(LevelAccessor level, BlockPos trunkPos) { protected float lootVolumeMultiplier = 1.0f; -// @OnlyIn(Dist.CLIENT) +// public int woodRingColor; // For rooty blocks -// @OnlyIn(Dist.CLIENT) +// public int woodBarkColor; // For rooty water /** @@ -432,7 +432,7 @@ public void setMaxBranchRadius(int maxBranchRadius) { this.maxBranchRadius = maxBranchRadius; } -// @OnlyIn(Dist.CLIENT) +// public int getRootColor(BlockState state, boolean getBark) { return getBark ? woodBarkColor : woodRingColor; } @@ -630,7 +630,7 @@ public void setHasStrippedBranch(boolean hasStrippedBranch) { } public int getMinRadiusForStripping() { - if (minRadiusForStripping == null) return Services.CONFIG.getIntConfig(IConfigHelper.MIN_RADIUS_FOR_STRIP); + if (minRadiusForStripping == null) return DTConfigs.SERVER.minRadiusForStrip.get(); return minRadiusForStripping; } @@ -639,7 +639,7 @@ public void setMinRadiusForStripping(int radius) { } public boolean reduceRadiusWhenStripping() { - if (Services.CONFIG.getBoolConfig(IConfigHelper.ENABLE_STRIP_RADIUS_REDUCTION)) + if (DTConfigs.SERVER.enableStripRadiusReduction.get()) return reduceRadiusWhenStripping; return false; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/tree/species/Species.java b/common/src/main/java/com/dtteam/dynamictrees/tree/species/Species.java index 489c6c806..0d324ae0c 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/tree/species/Species.java +++ b/common/src/main/java/com/dtteam/dynamictrees/tree/species/Species.java @@ -41,8 +41,8 @@ import com.dtteam.dynamictrees.loot.DTLootParameterSets; import com.dtteam.dynamictrees.loot.entry.SeedItemLootPoolEntry; import com.dtteam.dynamictrees.model.FallingTreeEntityModel; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.registry.DTRegistries; import com.dtteam.dynamictrees.systems.GrowSignal; import com.dtteam.dynamictrees.systems.SeedSaplingRecipe; @@ -647,8 +647,8 @@ public List getBranchesDrops(Level level, NetVolumeNode.Volume volume } public void processVolume(NetVolumeNode.Volume volume) { - volume.multiplyVolume(Services.CONFIG.getDoubleConfig(IConfigHelper.TREE_HARVEST_MULTIPLIER)); // For cheaters. you know who you are. - volume.multiplyVolume(getFamily().getLootVolumeMultiplier()); //the family can have a multiplier too + volume.multiplyVolume(DTConfigs.SERVER.treeHarvestMultiplier.get()); + volume.multiplyVolume(getFamily().getLootVolumeMultiplier()); } private List getDropsForBranchType(Level level, ItemStack tool, @Nullable Float explosionRadius, @@ -694,7 +694,7 @@ public static class LogsAndSticks { public LogsAndSticks(List logs, int sticks) { this.logs = logs; - this.sticks = Services.CONFIG.getBoolConfig(IConfigHelper.DROP_STICKS) ? sticks : 0; + this.sticks = DTConfigs.SERVER.dropSticks.get() ? sticks : 0; } } @@ -1477,7 +1477,7 @@ public boolean rot(LevelAccessor level, BlockPos pos, int neighborCount, int rad } } - int maxBranchRotRadius = Services.CONFIG.getIntConfig(IConfigHelper.MAX_BRANCH_ROT_RADIUS); + int maxBranchRotRadius = DTConfigs.SERVER.maxBranchRotRadius.get(); if (rapid || (maxBranchRotRadius != 0 && radius <= maxBranchRotRadius)) { BranchBlock branch = TreeHelper.getBranch(level.getBlockState(pos)); if (branch != null) { @@ -1527,7 +1527,7 @@ public float rotChance(LevelAccessor level, BlockPos pos, RandomSource rand, int */ public boolean grow(Level level, SoilBlock rootyDirt, BlockPos rootPos, int fertility, TreePart treeBase, BlockPos treePos, RandomSource random, boolean natural) { - float growthRate = (float) (getGrowthRate(level, rootPos) * Services.CONFIG.getDoubleConfig(IConfigHelper.TREE_GROWTH_MULTIPLIER)); + float growthRate = (float) (getGrowthRate(level, rootPos) * DTConfigs.SERVER.treeGrowthMultiplier.get()); do { if (fertility > 0) { if (growthRate > random.nextFloat()) { @@ -1615,7 +1615,7 @@ public boolean postGrow(Level level, BlockPos rootPos, BlockPos treePos, int fer * @return true if the tree became diseased */ public boolean handleDisease(Level level, TreePart baseTreePart, BlockPos treePos, RandomSource random, int fertility) { - if (fertility == 0 && Services.CONFIG.getDoubleConfig(IConfigHelper.DISEASE_CHANCE) > random.nextFloat()) { + if (fertility == 0 && DTConfigs.SERVER.diseaseChance.get() > random.nextFloat()) { baseTreePart.analyse(level.getBlockState(treePos), level, treePos, Direction.DOWN, new MapSignal(new DiseaseNode(this))); return true; } @@ -1665,7 +1665,7 @@ public float biomeSuitability(Level level, BlockPos pos) { return result.suitability(); } - double ugs = Services.CONFIG.getDoubleConfig(IConfigHelper.SCALE_BIOME_GROWTH_RATE); // Universal growth scalar. + double ugs = DTConfigs.SERVER.scaleBiomeGrowthRate.get(); if (ugs == 1.0 || preferredClimate == ClimateZoneType.NONE) { return 1.0f; @@ -1816,7 +1816,7 @@ public void inheritSeasonalFruitingParametersToFruits(){ this.fruits.forEach((fruit)->{ fruit.setSeasonalFactorGetter((l, p)->{ ClimateZoneType climate = ClimateHelper.getClimate(l.level(), p); - double multiplier = Services.CONFIG.getBoolConfig(IConfigHelper.CLIMATE_AFFECTS_FRUITS_AND_PODS) + double multiplier = DTConfigs.SERVER.climateAffectsFruitsAndPods.get() ? ClimateHelper.climateMultiplier(this, climate, climateTolerance) : 1.0; return (float)(this.seasonalFruitProductionFactor(l,p) * multiplier); }); @@ -1828,7 +1828,7 @@ public void inheritSeasonalFruitingParametersToPods(){ this.pods.forEach((fruit)->{ fruit.setSeasonalFactorGetter((l, p)->{ ClimateZoneType climate = ClimateHelper.getClimate(l.level(), p); - double multiplier = Services.CONFIG.getBoolConfig(IConfigHelper.CLIMATE_AFFECTS_FRUITS_AND_PODS) + double multiplier = DTConfigs.SERVER.climateAffectsFruitsAndPods.get() ? ClimateHelper.climateMultiplier(this, climate, climateTolerance) : 1.0; return (float)(this.seasonalFruitProductionFactor(l,p) * multiplier); }); @@ -1843,7 +1843,7 @@ public int getSeasonalTooltipFlags(LevelContext levelContext, Player player) { if (showSeasonalTooltip()) { BlockPos playerPos = BlockPos.containing(player.position()); ClimateZoneType climate = ClimateHelper.getClimate(player.level(), playerPos); - float suitability = (float) (Services.CONFIG.getBoolConfig(IConfigHelper.CLIMATE_AFFECTS_FRUITS_AND_PODS) + float suitability = (float) (DTConfigs.SERVER.climateAffectsFruitsAndPods.get() ? ClimateHelper.climateMultiplier(this, climate, climateTolerance) : 1.0); if (suitability < 0.3) return 0; //No seasons, still display @@ -1896,7 +1896,7 @@ public SubstanceEffect getSubstanceEffect(ItemStack itemStack) { // Bonemeal fertilizes the soil and causes a single growth pulse. if (canBoneMealTree() && itemStack.is(DTItemTags.FERTILIZER)) { - return new FertilizeSubstance().setAmount(2).setGrow(true).setPulses(Services.CONFIG.getIntConfig(IConfigHelper.BONE_MEAL_GROWTH_PULSES)); + return new FertilizeSubstance().setAmount(2).setGrow(true).setPulses(DTConfigs.SERVER.boneMealGrowthPulses.get()); } // Use substance provider interface if it's available. diff --git a/common/src/main/java/com/dtteam/dynamictrees/tree/species/SwampSpecies.java b/common/src/main/java/com/dtteam/dynamictrees/tree/species/SwampSpecies.java index 366877f5c..3125941c6 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/tree/species/SwampSpecies.java +++ b/common/src/main/java/com/dtteam/dynamictrees/tree/species/SwampSpecies.java @@ -2,8 +2,7 @@ import com.dtteam.dynamictrees.api.registry.TypedRegistry; import com.dtteam.dynamictrees.block.leaves.LeavesProperties; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.tree.family.Family; import com.dtteam.dynamictrees.worldgen.DynamicTreeGenerationContext; import net.minecraft.core.Direction; @@ -28,7 +27,7 @@ public SwampSpecies(ResourceLocation name, Family family, LeavesProperties leave @Override public boolean generate(DynamicTreeGenerationContext context) { if (isWater(context.level().getBlockState(context.rootPos()))) { - switch (Services.CONFIG.getEnumConfig(IConfigHelper.SWAMP_OAKS_IN_WATER, WaterSurfaceGenerationState.class)) { + switch (DTConfigs.SERVER.swampOaksInWater.get()) { case WaterSurfaceGenerationState.SUNK: //generate 1 block down if (context.radius() >= minRadiusForSunkGeneration) { context.rootPos().move(Direction.DOWN, countWaterBlocksBelow(context.level(), context.rootPos(), getAllowedWaterHeightForWorldgen())); diff --git a/common/src/main/java/com/dtteam/dynamictrees/treepack/Resources.java b/common/src/main/java/com/dtteam/dynamictrees/treepack/Resources.java index a796d3d18..65ef38e61 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/treepack/Resources.java +++ b/common/src/main/java/com/dtteam/dynamictrees/treepack/Resources.java @@ -3,9 +3,9 @@ import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.api.configuration.ConfigurationTemplateResourceLoader; import com.dtteam.dynamictrees.api.resource.TreeResourceManager; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.DirtBucketRecipeHandler; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.genfeature.GenFeature; import com.dtteam.dynamictrees.systems.genfeature.GenFeatureConfiguration; import com.dtteam.dynamictrees.systems.growthlogic.GrowthLogicKit; @@ -165,8 +165,8 @@ public CompletableFuture reload(PreparationBarrier stage, ResourceManager } private void registerDirtBucketRecipes() { - if (!Services.CONFIG.getBoolConfig(IConfigHelper.GENERATE_DIRT_BUCKET_RECIPES) - && !Services.CONFIG.getBoolConfig(IConfigHelper.GENERATE_MEGA_SEED_RECIPE)) { + if (!DTConfigs.COMMON.generateDirtBucketRecipes.get() + && !DTConfigs.COMMON.generateMegaSeedRecipe.get()) { return; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/utility/ItemUtils.java b/common/src/main/java/com/dtteam/dynamictrees/utility/ItemUtils.java index a7b876572..e4975784b 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/utility/ItemUtils.java +++ b/common/src/main/java/com/dtteam/dynamictrees/utility/ItemUtils.java @@ -1,8 +1,8 @@ package com.dtteam.dynamictrees.utility; import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.nodemapper.NetVolumeNode; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; @@ -72,7 +72,7 @@ public static void damageAxe(final LivingEntity entity, @Nullable final ItemStac return; } - int damage = switch (Services.CONFIG.getEnumConfig(IConfigHelper.AXE_DAMAGE_MODE, DynamicTrees.AxeDamage.class)) { + int damage = switch (DTConfigs.SERVER.axeDamageMode.get()) { case VANILLA -> 1; case THICKNESS -> Math.max(1, radius) / 2; case VOLUME -> (int) woodVolume.getVolume(); diff --git a/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabase.java b/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabase.java index 8be1e6567..52d7db9c6 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabase.java +++ b/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabase.java @@ -2,9 +2,8 @@ import com.dtteam.dynamictrees.api.worldgen.BiomePropertySelectors; import com.dtteam.dynamictrees.api.worldgen.BiomePropertySelectors.*; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.deserialization.JsonDeserializers; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.google.common.collect.Maps; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -570,7 +569,7 @@ public Function getMultipass(Holder biome) { } public BiomeDatabase setForestness(Holder biome, float forestness) { - getEntry(biome).setForestness((float) Math.max(forestness, Services.CONFIG.getDoubleConfig(IConfigHelper.SEED_MIN_FORESTNESS))); + getEntry(biome).setForestness((float) Math.max(forestness, DTConfigs.SERVER.seedMinForestness.get())); return this; } diff --git a/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabases.java b/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabases.java index 2193671cc..9438e5626 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabases.java +++ b/common/src/main/java/com/dtteam/dynamictrees/worldgen/BiomeDatabases.java @@ -1,7 +1,6 @@ package com.dtteam.dynamictrees.worldgen; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import net.minecraft.ResourceLocationException; @@ -45,8 +44,8 @@ public static boolean isBlacklisted(ResourceLocation dimensionLocation) { } public static void populateBlacklistFromConfig() { - if (Services.CONFIG.isServerConfigLoaded()){ - Services.CONFIG.getStringListConfig(IConfigHelper.DIMENSION_BLACK_LIST).forEach(BiomeDatabases::tryBlacklist); + if (DTConfigs.SERVER_CONFIG.isLoaded()){ + DTConfigs.SERVER.dimensionBlacklist.get().forEach(BiomeDatabases::tryBlacklist); } else { LogManager.getLogger().error("Dimension Blacklist tried to load from config before config was loaded! this should not happen."); } diff --git a/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DTReplaceNyliumFungiBlockStateProvider.java b/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DTReplaceNyliumFungiBlockStateProvider.java index e304577b6..1f93cdda9 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DTReplaceNyliumFungiBlockStateProvider.java +++ b/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DTReplaceNyliumFungiBlockStateProvider.java @@ -1,7 +1,6 @@ package com.dtteam.dynamictrees.worldgen.feature; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.registry.DTRegistries; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; @@ -31,7 +30,7 @@ protected BlockStateProviderType type() { @Override public BlockState getState(RandomSource random, BlockPos state) { - return Services.CONFIG.getBoolConfig(IConfigHelper.REPLACE_NYLIUM_FUNGI) + return DTConfigs.COMMON.replaceNyliumFungi.get() ? this.enabled.getState(random, state) : this.disabled.getState(random, state); } diff --git a/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DynamicTreeFeature.java b/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DynamicTreeFeature.java index 347101e7a..d2e5c019f 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DynamicTreeFeature.java +++ b/common/src/main/java/com/dtteam/dynamictrees/worldgen/feature/DynamicTreeFeature.java @@ -5,9 +5,8 @@ import com.dtteam.dynamictrees.api.worldgen.LevelContext; import com.dtteam.dynamictrees.api.worldgen.RandomXOR; import com.dtteam.dynamictrees.block.soil.SoilBlock; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.data.tags.DTBlockTags; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.systems.poissondisc.PoissonDisc; import com.dtteam.dynamictrees.systems.poissondisc.UniversalPoissonDiscProvider; import com.dtteam.dynamictrees.tree.species.Species; @@ -138,7 +137,7 @@ protected GeneratorResult generateTree(LevelContext levelContext, BiomeDatabase. } // Display concrete circles for testing the circle growing algorithm. - if (Services.CONFIG.getBoolConfig(IConfigHelper.DEBUG)) { + if (DTConfigs.SERVER.debug.get()) { this.generateConcreteCircle(levelContext.accessor(), circle, groundPos.getY(), result); } diff --git a/common/src/main/java/com/dtteam/dynamictrees/worldgen/structure/DTCancelVanillaTreePoolElement.java b/common/src/main/java/com/dtteam/dynamictrees/worldgen/structure/DTCancelVanillaTreePoolElement.java index ac26a1490..ca1cf42ab 100644 --- a/common/src/main/java/com/dtteam/dynamictrees/worldgen/structure/DTCancelVanillaTreePoolElement.java +++ b/common/src/main/java/com/dtteam/dynamictrees/worldgen/structure/DTCancelVanillaTreePoolElement.java @@ -1,7 +1,6 @@ package com.dtteam.dynamictrees.worldgen.structure; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.registry.DTRegistries; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; @@ -44,7 +43,7 @@ public static Function { + VanillaSaplingEventHandler.updateEnabled(); + FabricMiscHelper.debugSpeciesRegistry(); + }); + + ServerLifecycleEvents.SERVER_STOPPING.register(server -> { + FabricMiscHelper.currentServer = null; + }); + + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + ServerLifecycleEvents.SERVER_STARTED.register(server -> { + LeavesProperties.postInitClient(); + BlockColorMultipliers.cleanUp(); + DynamicTreesFabricClient.registerBlockColors(); + DynamicTreesFabricClient.discoverWoodColors(); + }); + } } } diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/DynamicTreesFabricClient.java b/fabric/src/main/java/com/dtteam/dynamictrees/DynamicTreesFabricClient.java new file mode 100644 index 000000000..c91e393d5 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/DynamicTreesFabricClient.java @@ -0,0 +1,198 @@ +package com.dtteam.dynamictrees; + +import com.dtteam.dynamictrees.api.season.*; +import com.dtteam.dynamictrees.api.worldgen.*; +import com.dtteam.dynamictrees.block.branch.*; +import com.dtteam.dynamictrees.block.leaves.*; +import com.dtteam.dynamictrees.block.sapling.*; +import com.dtteam.dynamictrees.block.soil.*; +import com.dtteam.dynamictrees.client.*; +import com.dtteam.dynamictrees.config.*; +import com.dtteam.dynamictrees.entity.render.*; +import com.dtteam.dynamictrees.item.*; +import com.dtteam.dynamictrees.model.*; +import com.dtteam.dynamictrees.registry.*; +import com.dtteam.dynamictrees.systems.season.*; +import com.dtteam.dynamictrees.tree.*; +import com.dtteam.dynamictrees.tree.family.*; +import com.dtteam.dynamictrees.tree.species.*; +import fuzs.forgeconfigapiport.fabric.api.neoforge.v4.*; +import net.fabricmc.api.*; +import net.fabricmc.fabric.api.blockrenderlayer.v1.*; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.*; +import net.fabricmc.fabric.api.client.item.v1.*; +import net.fabricmc.fabric.api.client.model.loading.v1.*; +import net.fabricmc.fabric.api.client.rendering.v1.*; +import net.fabricmc.fabric.impl.client.rendering.*; +import net.minecraft.client.*; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.block.model.*; +import net.minecraft.client.renderer.texture.*; +import net.minecraft.client.resources.model.*; +import net.minecraft.core.*; +import net.minecraft.resources.*; +import net.minecraft.util.*; +import net.minecraft.world.entity.player.*; +import net.minecraft.world.inventory.*; +import net.minecraft.world.item.*; +import net.minecraft.world.level.*; +import net.minecraft.world.level.block.state.*; +import net.neoforged.fml.config.*; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +public class DynamicTreesFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + NeoForgeConfigRegistry.INSTANCE.register(DynamicTrees.MOD_ID, ModConfig.Type.CLIENT, DTConfigs.CLIENT_CONFIG); + AtlasSourceTypeRegistryImpl.register(ThickBranchRingsSource.ID, ThickBranchRingsSource.setType(ThickBranchRingsSource.CODEC)); + registerModelLoaders(); + registerEntityRenderers(); + registerColorHandlers(); + registerTooltipCallback(); + registerClientTick(); + } + + private void registerModelLoaders() { + ModelLoadingPlugin.register(new DTModelLoadingPlugin()); + } + + private void registerEntityRenderers() { + EntityRendererRegistry.register(DTRegistries.FALLING_TREE.get(), FallingTreeRenderer::new); + EntityRendererRegistry.register(DTRegistries.LINGERING_EFFECTOR.get(), LingeringEffectorRenderer::new); + } + + private void registerColorHandlers() { + BlockColorMultipliers.register("birch", (state, level, pos, tintIndex) -> FoliageColor.getBirchColor()); + BlockColorMultipliers.register("spruce", (state, level, pos, tintIndex) -> FoliageColor.getEvergreenColor()); + + ColorProviderRegistry.ITEM.register(DTRegistries.DENDRO_POTION.get()::getColor, DTRegistries.DENDRO_POTION.get()); + ColorProviderRegistry.ITEM.register(DTRegistries.STAFF.get()::getColor, DTRegistries.STAFF.get()); + } + + public static void registerBlockColors() { + final int white = 0xFFFFFFFF; + final int magenta = 0x00FF00FF; + final var blockColors = Minecraft.getInstance().getBlockColors(); + + for (SoilProperties soil : SoilProperties.REGISTRY) { + if (soil.getBlock().isEmpty()) continue; + SoilBlock roots = soil.getBlock().get(); + ColorProviderRegistry.BLOCK.register( + (state, level, pos, tintIndex) -> roots.colorMultiplier(blockColors, state, level, pos, tintIndex), + roots + ); + BlockRenderLayerMap.INSTANCE.putBlock(roots, RenderType.cutoutMipped()); + } + + for (Family family : Family.REGISTRY.getAll()) { + if (family instanceof UndergroundRootsFamily rootsFamily) { + rootsFamily.getRoots().ifPresent(roots -> + BlockRenderLayerMap.INSTANCE.putBlock(roots, RenderType.cutoutMipped()) + ); + } + } + + ColorProviderRegistry.BLOCK.register( + (state, level, pos, tintIndex) -> isValidPos(level, pos) && (state.getBlock() instanceof PottedSaplingBlock) + ? DTRegistries.POTTED_SAPLING.get().getSpecies(level, pos).saplingColorMultiplier(state, level, pos, tintIndex) : white, + DTRegistries.POTTED_SAPLING.get() + ); + + for (Species species : Species.REGISTRY) { + if (species.getSapling().isPresent()) { + ColorProviderRegistry.BLOCK.register( + (state, level, pos, tintIndex) -> isValidPos(level, pos) + ? species.saplingColorMultiplier(state, level, pos, tintIndex) : white, + species.getSapling().get() + ); + } + } + + for (DynamicLeavesBlock leaves : LeavesProperties.REGISTRY.getAll().stream() + .filter(lp -> lp.getDynamicLeavesBlock().isPresent()) + .map(lp -> lp.getDynamicLeavesBlock().get()) + .collect(Collectors.toSet())) { + ColorProviderRegistry.BLOCK.register( + (state, level, pos, tintIndex) -> isValidPos(level, pos) && TreeHelper.isLeaves(state.getBlock()) + ? ((DynamicLeavesBlock) state.getBlock()).getLeavesProperties().foliageColorMultiplier(state, level, pos) : magenta, + leaves + ); + } + } + + private static boolean isValidPos(BlockGetter level, BlockPos pos) { + return level != null && pos != null; + } + + private void registerTooltipCallback() { + ItemTooltipCallback.EVENT.register((stack, context, type, lines) -> { + Item item = stack.getItem(); + if (!(item instanceof Seed seed)) { + return; + } + + Player player = Minecraft.getInstance().player; + if (player == null) { + return; + } + + LevelContext levelContext = LevelContext.create(player.level()); + Species species = seed.getSpecies(); + + if (SeasonHelper.getSeasonValue(levelContext, BlockPos.ZERO) == null || !species.isValid()) { + return; + } + + BlockPos playerPos = BlockPos.containing(player.position()); + ClimateZoneType climate = ClimateHelper.getClimate(player.level(), playerPos); + int flags = seed.getSpecies().getSeasonalTooltipFlags(levelContext, player); + Tooltips.applySeasonalTooltips(lines, flags, climate); + }); + } + + private void registerClientTick() { + ClientTickEvents.START_WORLD_TICK.register(level -> { + SeasonHelper.updateTick(level, level.getDayTime()); + }); + } + + public static void discoverWoodColors() { + final Function bakedTextureGetter = Minecraft.getInstance() + .getTextureAtlas(InventoryMenu.BLOCK_ATLAS); + + for (Family family : Family.REGISTRY.getAll()) { + family.woodRingColor = 0xFFF1AE; + family.woodBarkColor = 0xB3A979; + if (family != Family.NULL_FAMILY) { + family.getPrimitiveLog().ifPresent(branch -> { + BlockState state = branch.defaultBlockState(); + family.woodRingColor = getFaceColor(state, Direction.DOWN, bakedTextureGetter); + family.woodBarkColor = getFaceColor(state, Direction.NORTH, bakedTextureGetter); + }); + } + } + } + + private static int getFaceColor(BlockState state, Direction face, Function textureGetter) { + final BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + List quads = model.getQuads(state, face, RandomSource.create()); + if (quads.isEmpty()) { + quads = model.getQuads(state, null, RandomSource.create()); + } + if (quads.isEmpty()) { + DynamicTrees.LOG.warn("Could not get color of {} side for {}! Branch needs to be handled manually!", face, state.getBlock()); + return 0; + } + TextureAtlasSprite sprite = quads.getFirst().getSprite(); + final TextureHelper.PixelBuffer pixelBuffer = new TextureHelper.PixelBuffer(sprite); + final int u = pixelBuffer.w / 16; + final TextureHelper.PixelBuffer center = new TextureHelper.PixelBuffer(u * 8, u * 8); + pixelBuffer.blit(center, u * -8, u * -8); + + return center.averageColor(); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigProvider.java b/fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigProvider.java deleted file mode 100644 index a809b73ce..000000000 --- a/fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigProvider.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.dtteam.dynamictrees.config; - -import com.mojang.datafixers.util.Pair; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; - -public class DTConfigProvider implements SimpleConfig.DefaultConfig { - - private String configContents = ""; - - //id -> (default, cached) - public HashMap, ?>> getDefaultValues() { - return defaultValues; - } - - private final HashMap, ?>> defaultValues = new HashMap<>(); - - public void addKeyValuePair(Pair keyValuePair, String comment, @Nullable Pair range) { - defaultValues.put(keyValuePair.getFirst(), new Pair<>(keyValuePair.getSecond().getClass(), keyValuePair.getSecond())); - configContents += - " # " + comment + "\n" + - " # Default: " + keyValuePair.getSecond() + "\n" + - (range == null ? "" : " # Range: " + range.getFirst() + " ~ " + range.getSecond() + "\n") + - " " + keyValuePair.getFirst() + "=" + keyValuePair.getSecond() + "\n"; - } - - public void addSection(String name){ - configContents += "\n[" + name + "]\n"; - } - - @Override - public String get(String namespace) { - return configContents; - } -} \ No newline at end of file diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java b/fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java deleted file mode 100644 index 10412baa8..000000000 --- a/fabric/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.dtteam.dynamictrees.config; - -import com.dtteam.dynamictrees.DynamicTrees; -import com.dtteam.dynamictrees.block.branch.ThickBranchBlock; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; -import com.dtteam.dynamictrees.systems.season.SeasonCompatibilityHandler; -import com.dtteam.dynamictrees.tree.species.SwampSpecies; -import com.mojang.datafixers.util.Pair; - -public class DTConfigs { - public static SimpleConfig CONFIG; - private static DTConfigProvider configs; - public static boolean isLoaded = false; - - public static void registerConfigs() { - configs = new DTConfigProvider(); - createConfigs(); - - CONFIG = SimpleConfig.of(DynamicTrees.MOD_ID).provider(configs).request(); - isLoaded = true; - } - - private static void createConfigs() { - configs.addSection("seeds"); - createConfig("The rate at which seeds drop from leaves.", - IConfigHelper.LEAVES_SEED_DROP_RATE, 1D, 0D, 64D); - createConfig("The rate at which seeds voluntarily drop from branches", - IConfigHelper.VOLUNTARY_SEED_DROP_RATE, 0.01, 0.0, 1.0); - createConfig("The rate at which seeds voluntarily plant themselves in their ideal biomes", - IConfigHelper.SEED_PLANT_RATE, 1f / 6f, 0.0, 1.0); - createConfig("Ticks before a seed in the world attempts to plant itself or despawn. 1200 = 1 minute", - IConfigHelper.SEED_TIME_TO_LIVE, 1200, 0, 6000); - createConfig("If enabled then seeds will only voluntarily plant themselves in forest-like biomes.", - IConfigHelper.SEED_ONLY_FOREST, true); - createConfig("The minimum forestness that non-forest-like biomes can have. 0 = is not at all a forest, 1 = may as well be a forest. Can be fractional.", - IConfigHelper.SEED_MIN_FORESTNESS, 0.0, 0.0, 1.0); - - configs.addSection("trees"); - createConfig("Factor that multiplies the rate at which trees grow. Use at own risk", - IConfigHelper.TREE_GROWTH_MULTIPLIER, 0.5f, 0, 16f); - createConfig("Factor that multiplies the wood returned from harvesting a tree. You cheat.", - IConfigHelper.TREE_HARVEST_MULTIPLIER, 1f, 0f, 128f); - createConfig("Maximum harvesting hardness that can be calculated. Regardless of tree thickness.", - IConfigHelper.MAX_TREE_HARDNESS, 20f, 1f, 200f); - createConfig("A multiplier of tree hardness. Higher values make trees slower to chop, lower values makes them faster to chop.", - IConfigHelper.TREE_HARDNESS_MULTIPLIER, 1, (1/128f), 32f); - createConfig("If enabled then sticks will be dropped for partial logs", - IConfigHelper.DROP_STICKS, true); - createConfig("Scales the growth for the environment. 0.5f is nominal. 0.0 trees only grow in their native biome. 1.0 trees grow anywhere like they are in their native biome", - IConfigHelper.SCALE_BIOME_GROWTH_RATE, 0.5f, 0.0f, 1.0f); - createConfig("The chance of a tree on depleted soil to die. 1/256(~0.004) averages to about 1 death every 16 minecraft days", - IConfigHelper.DISEASE_CHANCE, 0.0f, 0.0f, 1.0f); - createConfig("The maximum radius of a branch that is allowed to postRot away. 8 = Full block size. 24 = Full 3x3 thick size. Set to 0 to prevent rotting", - IConfigHelper.MAX_BRANCH_ROT_RADIUS, 5, 0, ThickBranchBlock.MAX_RADIUS_THICK); - createConfig("How much harder it is to destroy a rooty block compared to its non-rooty state", - IConfigHelper.ROOTY_BLOCK_HARDNESS_MULTIPLIER, 40f, 0f, 128f); - createConfig("Options for how oak trees generate in swamps. ROOTED: Swamp oak trees will generate on shallow water with mangrove-like roots. SUNK: Swamp oak trees will generate on shallow water one block under the surface. DISABLED: Swamp oaks will not generate on water.", - IConfigHelper.SWAMP_OAKS_IN_WATER, SwampSpecies.WaterSurfaceGenerationState.ROOTED.toString()); - createConfig("The amount of growth pulses to send when bone meal is applied to a tree. Warning: setting values higher than 64 is not recommended other than for testing purposes. ", - IConfigHelper.BONE_MEAL_GROWTH_PULSES, 1, 1, 512); - - configs.addSection("interaction"); - createConfig("If enabled all leaves will be passable. If the Passable Foliage mod is installed this config is overridden as true.", - IConfigHelper.IS_LEAVES_PASSABLE, false); - createConfig("If enabled player movement on leaves will not be enhanced.", - IConfigHelper.VANILLA_LEAVES_COLLISION, false); - createConfig("If enabled then thinner branches can be climbed", - IConfigHelper.ENABLE_BRANCH_CLIMBING, true); - createConfig("If enabled players receive reduced fall damage on leaves at the expense of the block(s) destruction", - IConfigHelper.ENABLE_CANOPY_CRASH, true); - createConfig("Damage dealt to the axe item when cutting a tree down. VANILLA: Standard 1 Damage. THICKNESS: By Branch/Trunk Thickness. VOLUME: By Tree Volume.", - IConfigHelper.AXE_DAMAGE_MODE, DynamicTrees.AxeDamage.THICKNESS.toString()); - createConfig("If enabled then trees will fall over when harvested", - IConfigHelper.ENABLE_FALLING_TREES, true); - createConfig("If enabled then trees will harm living entities when falling", - IConfigHelper.ENABLE_FALLING_TREE_DAMAGE, true); - createConfig("Multiplier for damage incurred by a falling tree", - IConfigHelper.FALLING_TREE_DAMAGE_MULTIPLIER, 1.0, 0.0, 100.0); - createConfig("If enabled the Dirt Bucket will place a dirt block on right-click", - IConfigHelper.DIRT_BUCKET_PLACES_DIRT, true); - createConfig("If enabled then improperly broken trees(not by an entity) will still drop wood.", - IConfigHelper.SLOPPY_BREAK_DROPS, false); - createConfig("The minimum radius a branch must have before its able to be stripped. 8 = Full block size. Set to 0 to disable stripping trees", - IConfigHelper.MIN_RADIUS_FOR_STRIP, 6, 0, 24); - createConfig("If enabled, stripping a branch will decrease its radius by one", - IConfigHelper.ENABLE_STRIP_RADIUS_REDUCTION, true); - createConfig("Sets the default for whether or not fruit growing from dynamic trees can be bone-mealed. Note that this is a default; it can be overridden by the individual fruit.", - IConfigHelper.CAN_BONE_MEAL_FRUIT, false); - createConfig("Sets the default for whether or not pods growing from dynamic trees can be bone-mealed. Note that this is a default; it can be overridden by the individual pod.", - IConfigHelper.CAN_BONE_MEAL_PODS, true); - createConfig("If enabled, dynamic sapling blocks will drop their seed when broken.", - IConfigHelper.DYNAMIC_SAPLING_DROPS, true); - - configs.addSection("vanilla"); - createConfig("Right clicking with a vanilla sapling places a dynamic sapling instead.", - IConfigHelper.REPLACE_VANILLA_SAPLINGS, false); - createConfig("Crimson Fungus and Warped Fungus that sprout from nylium will be dynamic instead.", - IConfigHelper.REPLACE_NYLIUM_FUNGI, true); - createConfig("If enabled, cancels the non-dynamic trees that spawn with vanilla villages.", - IConfigHelper.CANCEL_VANILLA_VILLAGE_TREES, true); - createConfig("The maximum number of leaves blocks that will fling particles when a falling tree crashes into the ground. Higher values might have a performance impact.", - IConfigHelper.MAX_FALLING_TREE_LEAVES_PARTICLES, 400, 0, 4096); - - configs.addSection("world"); - createConfig("Randomly generate podzol under select trees like spruce.", - IConfigHelper.GENERATE_PODZOL, true); - createConfig("World Generation produces Dynamic Trees instead of Vanilla trees.", - IConfigHelper.WORLD_GEN, true); - createConfig("Blacklist of dimension registry names for disabling Dynamic Tree worldgen.", - IConfigHelper.DIMENSION_BLACK_LIST, "[]"); - - configs.addSection("misc"); - createConfig("If enabled, dirt bucket recipes will be automatically generated.", - IConfigHelper.GENERATE_DIRT_BUCKET_RECIPES, true); - createConfig("The base potion the Biochar Base is brewed from. Minecraft potions use 'awkward'. If you change this, don't forget to update the patchouli manual page too.", - IConfigHelper.BIOCHAR_BREWING_BASE, "minecraft:thick"); - - configs.addSection("integration"); - createConfig("The mod ID of preferred season mod. If a season provider for this mod ID is present, it will be used for integration with seasons. Set this to \"!\" to disable integration or \"*\" to accept the any integration (the first available).", - IConfigHelper.PREFERRED_SEASON_MOD, SeasonCompatibilityHandler.ANY); - createConfig("If enabled, seed drop rates will be multiplied based on the current season (requires serene seasons).", - IConfigHelper.ENABLE_SEASONAL_SEED_DROP, true); - createConfig("If enabled, growth rates will be multiplied based on the current season (requires serene seasons).", - IConfigHelper.ENABLE_SEASONAL_GROWTH, true); - createConfig("If enabled, fruit production rates will be multiplied based on the current season (requires serene seasons).", - IConfigHelper.ENABLE_SEASONAL_SEED_FRUIT_PRODUCTION, true); - createConfig("The seasonal offset of the wet season relative to summer. Tropical and arid climates use wet/dry seasons instead of regular summer/fall/winter/spring seasons. Tree growth and fruit production usually peak during the wet season. If set to 0.0 the wet season happens at the same time as summer. The default of 1.5 means it happens between fall and winter.", - IConfigHelper.WET_SEASON_OFFSET, 1.5, 0.0, 4.0); - -// configs.addSection("visuals"); -// fancyThickRings = createConfig("Rings of thick trees are rendered using a texture created with an expanded tangram construction technique. Otherwise the ring texture is simply stretched", -// "fancyThickRings", true); -// CLIENT_BUILDER.pop(); - - configs.addSection("debug"); - createConfig("Enable to mark tree spawn locations with concrete circles.", - IConfigHelper.DEBUG, false); - } - - private static void createConfig(String comment, String id, T def){ - configs.addKeyValuePair(new Pair<>(id, def), comment, null); - } - private static void createConfig(String comment, String id, T def, T rangeMin, T rangeMax){ - configs.addKeyValuePair(new Pair<>(id, def), comment, new Pair<>(rangeMin, rangeMax)); - } - - public static Pair, ?> getDefaultValue (String id){ - return configs.getDefaultValues().get(id); - } - -} \ No newline at end of file diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/config/SimpleConfig.java b/fabric/src/main/java/com/dtteam/dynamictrees/config/SimpleConfig.java deleted file mode 100644 index 58c815023..000000000 --- a/fabric/src/main/java/com/dtteam/dynamictrees/config/SimpleConfig.java +++ /dev/null @@ -1,260 +0,0 @@ -package com.dtteam.dynamictrees.config; - -/* - * Copyright (c) 2021 magistermaks - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -import net.fabricmc.loader.api.FabricLoader; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Objects; -import java.util.Scanner; - -public class SimpleConfig { - - private static final Logger LOGGER = LogManager.getLogger("SimpleConfig"); - private final HashMap config = new HashMap<>(); - private final ConfigRequest request; - private boolean broken = false; - - public interface DefaultConfig { - String get( String namespace ); - - static String empty( String namespace ) { - return ""; - } - } - - public static class ConfigRequest { - - private final File file; - private final String filename; - private DefaultConfig provider; - - private ConfigRequest(File file, String filename ) { - this.file = file; - this.filename = filename; - this.provider = DefaultConfig::empty; - } - - /** - * Sets the default config provider, used to generate the - * config if it's missing. - * - * @param provider default config provider - * @return current config request object - * @see DefaultConfig - */ - public ConfigRequest provider( DefaultConfig provider ) { - this.provider = provider; - return this; - } - - /** - * Loads the config from the filesystem. - * - * @return config object - * @see SimpleConfig - */ - public SimpleConfig request() { - return new SimpleConfig( this ); - } - - private String getConfig() { - return provider.get( filename ) + "\n"; - } - - } - - /** - * Creates new config request object, ideally `namespace` - * should be the name of the mod id of the requesting mod - * - * @param filename - name of the config file - * @return new config request object - */ - public static ConfigRequest of( String filename ) { - Path path = FabricLoader.getInstance().getConfigDir(); - return new ConfigRequest( path.resolve( filename + ".properties" ).toFile(), filename ); - } - - private void createConfig() throws IOException { - - // try creating missing files - request.file.getParentFile().mkdirs(); - Files.createFile( request.file.toPath() ); - - // write default config data - PrintWriter writer = new PrintWriter(request.file, StandardCharsets.UTF_8); - writer.write( request.getConfig() ); - writer.close(); - - } - - private void loadConfig() throws IOException { - Scanner reader = new Scanner( request.file ); - for( int line = 1; reader.hasNextLine(); line ++ ) { - parseConfigEntry( reader.nextLine(), line ); - } - } - - private void parseConfigEntry( String entry, int line ) { - if( !entry.isEmpty() && !(entry.trim().startsWith( "#" ) || (entry.trim().startsWith("[") && entry.trim().endsWith("]"))) ) { - String[] parts = entry.split("=", 2); - if( parts.length == 2 ) { - config.put( parts[0].trim(), parts[1].trim() ); - }else{ - throw new RuntimeException("Syntax error in config file on line " + line + "!"); - } - } - } - - private SimpleConfig( ConfigRequest request ) { - this.request = request; - String identifier = "Config '" + request.filename + "'"; - - if( !request.file.exists() ) { - LOGGER.info("{} is missing, generating default one...", identifier); - - try { - createConfig(); - } catch (IOException e) { - LOGGER.error("{} failed to generate!", identifier); - LOGGER.trace( e ); - broken = true; - } - } - - if( !broken ) { - try { - loadConfig(); - } catch (Exception e) { - LOGGER.error("{} failed to load!", identifier); - LOGGER.trace( e ); - broken = true; - } - } - - } - - /** - * Queries a value from config, returns `null` if the - * key does not exist. - * - * @return value corresponding to the given key - * @see SimpleConfig#getOrDefault - */ - @Deprecated - public String get( String key ) { - return config.get( key ); - } - - public boolean containsConfig (String key){ - return get(key) != null; - } - - /** - * Returns string value from config corresponding to the given - * key, or the default string if the key is missing. - * - * @return value corresponding to the given key, or the default value - */ - public String getOrDefault( String key, String def ) { - String val = get(key); - return val == null ? def : val; - } - - /** - * Returns integer value from config corresponding to the given - * key, or the default integer if the key is missing or invalid. - * - * @return value corresponding to the given key, or the default value - */ - public Integer getOrDefault( String key, Integer def ) { - try { - if (Objects.equals(get(key), "null")) return null; - return Integer.parseInt( get(key) ); - } catch (Exception e) { - return def; - } - } - - /** - * Returns boolean value from config corresponding to the given - * key, or the default boolean if the key is missing. - * - * @return value corresponding to the given key, or the default value - */ - public Boolean getOrDefault( String key, Boolean def ) { - if (Objects.equals(get(key), "null")) return null; - String val = get(key); - if( val != null ) { - return val.equalsIgnoreCase("true"); - } - - return def; - } - - /** - * Returns double value from config corresponding to the given - * key, or the default string if the key is missing or invalid. - * - * @return value corresponding to the given key, or the default value - */ - public Double getOrDefault( String key, Double def ) { - try { - if (Objects.equals(get(key), "null")) return null; - return Double.parseDouble( get(key) ); - } catch (Exception e) { - return def; - } - } - - /** - * If any error occurred during loading or reading from the config - * a 'broken' flag is set, indicating that the config's state - * is undefined and should be discarded using `delete()` - * - * @return the 'broken' flag of the configuration - */ - public boolean isBroken() { - return broken; - } - - /** - * deletes the config file from the filesystem - * - * @return true if the operation was successful - */ - public boolean delete() { - LOGGER.warn( "Config '" + request.filename + "' was removed from existence! Restart the game to regenerate it." ); - return request.file.delete(); - } - -} \ No newline at end of file diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/CommonEventHandler.java b/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/CommonEventHandler.java index 061a77a0e..f23816fe2 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/CommonEventHandler.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/CommonEventHandler.java @@ -1,9 +1,13 @@ package com.dtteam.dynamictrees.event.handler; import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.dtteam.dynamictrees.block.branch.TrunkShellBlock; +import com.dtteam.dynamictrees.block.sapling.PottedSaplingBlock; +import com.dtteam.dynamictrees.block.soil.SoilBlock; import com.dtteam.dynamictrees.command.DTCommand; -import com.dtteam.dynamictrees.platform.FabricMiscHelper; import com.dtteam.dynamictrees.systems.FutureBreak; +import com.dtteam.dynamictrees.systems.season.SeasonCompatibilityHandler; import com.dtteam.dynamictrees.systems.season.SeasonHelper; import com.dtteam.dynamictrees.treepack.Resources; import com.dtteam.dynamictrees.worldgen.BiomeDatabases; @@ -13,10 +17,17 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; +import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.block.Block; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; public class CommonEventHandler { @@ -28,16 +39,11 @@ public static void RegisterEvents(){ }); ServerWorldEvents.LOAD.register(((minecraftServer, serverLevel) -> { - FabricMiscHelper.currentServer = minecraftServer; BiomeDatabases.populateBlacklistFromConfig(); })); -// if (event.getLevel().isClientSide()) { -// ClientModEventHandler.discoverWoodColors(); -// } ServerWorldEvents.UNLOAD.register(((minecraftServer, serverLevel) -> { - FabricMiscHelper.currentServer = null; - DynamicTreeFeature.DISC_PROVIDER.unloadWorld(serverLevel);//clears the circles + DynamicTreeFeature.DISC_PROVIDER.unloadWorld(serverLevel); })); ClientTickEvents.START_WORLD_TICK.register((level)->{ @@ -45,13 +51,27 @@ public static void RegisterEvents(){ }); ServerLifecycleEvents.SERVER_STARTED.register((minecraftServer -> { - SeasonHelper.getSeasonManager().flushMappings(); + SeasonCompatibilityHandler.getSeasonManager().flushMappings(); })); CommandRegistrationCallback.EVENT.register(((commandDispatcher, commandBuildContext, commandSelection) -> { new DTCommand().registerDTCommand(commandDispatcher); })); + PlayerBlockBreakEvents.BEFORE.register((level, player, pos, state, blockEntity) -> { + Block block = state.getBlock(); + if (block instanceof BranchBlock branchBlock) { + return branchBlock.onDestroyedByPlayer(state, level, pos, player, true, level.getFluidState(pos)); + } else if (block instanceof TrunkShellBlock trunkShellBlock) { + return trunkShellBlock.onDestroyedByPlayer(state, level, pos, player, true, level.getFluidState(pos)); + } else if (block instanceof SoilBlock soilBlock) { + return soilBlock.onDestroyedByPlayer(state, level, pos, player, true, level.getFluidState(pos)); + } else if (block instanceof PottedSaplingBlock pottedSaplingBlock) { + return pottedSaplingBlock.onDestroyedByPlayer(state, level, pos, player, true, level.getFluidState(pos)); + } + return true; + }); + ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new FabricReloadListener()); } @@ -62,6 +82,13 @@ public FabricReloadListener() { super(null); } + @Override + public CompletableFuture reload(PreparationBarrier stage, ResourceManager resourceManager, + ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, + Executor backgroundExecutor, Executor gameExecutor) { + return super.reload(stage, resourceManager, preparationsProfiler, reloadProfiler, backgroundExecutor, gameExecutor); + } + @Override public ResourceLocation getFabricId() { return DynamicTrees.location(DynamicTrees.MOD_ID); diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/ModEventHandler.java b/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/ModEventHandler.java index e16a8a7e9..33d7f6141 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/ModEventHandler.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/ModEventHandler.java @@ -1,12 +1,37 @@ package com.dtteam.dynamictrees.event.handler; +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.api.cell.CellKit; import com.dtteam.dynamictrees.api.registry.Registries; import com.dtteam.dynamictrees.api.registry.Registry; import com.dtteam.dynamictrees.api.registry.SimpleRegistry; import com.dtteam.dynamictrees.api.worldgen.FeatureCanceller; +import com.dtteam.dynamictrees.block.leaves.LeavesProperties; +import com.dtteam.dynamictrees.block.leaves.PalmLeavesProperties; +import com.dtteam.dynamictrees.block.leaves.ScruffyLeavesProperties; +import com.dtteam.dynamictrees.block.leaves.SolidLeavesProperties; +import com.dtteam.dynamictrees.block.leaves.WartProperties; +import com.dtteam.dynamictrees.block.soil.AerialRootsSoilProperties; +import com.dtteam.dynamictrees.block.soil.SoilProperties; +import com.dtteam.dynamictrees.block.soil.SpreadableSoilProperties; +import com.dtteam.dynamictrees.block.soil.WaterSoilProperties; import com.dtteam.dynamictrees.deserialization.JsonDeserializers; +import com.dtteam.dynamictrees.systems.cell.CellKits; +import com.dtteam.dynamictrees.systems.genfeature.GenFeature; +import com.dtteam.dynamictrees.systems.genfeature.GenFeatures; +import com.dtteam.dynamictrees.systems.growthlogic.GrowthLogicKit; +import com.dtteam.dynamictrees.systems.growthlogic.GrowthLogicKits; +import com.dtteam.dynamictrees.tree.family.Family; +import com.dtteam.dynamictrees.tree.family.NetherFungusFamily; +import com.dtteam.dynamictrees.tree.family.PalmFamily; +import com.dtteam.dynamictrees.tree.family.UndergroundRootsFamily; +import com.dtteam.dynamictrees.tree.species.NetherFungusSpecies; +import com.dtteam.dynamictrees.tree.species.PalmSpecies; +import com.dtteam.dynamictrees.tree.species.Species; +import com.dtteam.dynamictrees.tree.species.SwampSpecies; +import com.dtteam.dynamictrees.tree.species.UndergroundRootsSpecies; import com.dtteam.dynamictrees.treepack.Resources; -import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback; +import com.dtteam.dynamictrees.worldgen.featurecancellation.FeatureCancellers; import java.util.List; import java.util.stream.Collectors; @@ -14,96 +39,76 @@ public class ModEventHandler { public static void RegisterEvents(){ + registerLeavesPropertiesTypes(); + registerFamilyTypes(); + registerSpeciesTypes(); + registerSoilPropertiesTypes(); + registerCellKits(); + registerGrowthLogicKits(); + registerGenFeatures(); + registerFeatureCancellers(); + + final List> registries = Registries.REGISTRIES.stream() + .filter(registry -> registry instanceof SimpleRegistry) + .map(registry -> (SimpleRegistry) registry) + .collect(Collectors.toList()); + + registries.forEach(SimpleRegistry::postRegistryEvent); + + Resources.setupTreesResourceManager(); + + JsonDeserializers.registerRegistryEntryGetters(); + JsonDeserializers.postRegistryEvent(); + + FeatureCanceller.REGISTRY.postRegistryEvent(); + FeatureCanceller.REGISTRY.lock(); -// @SubscribeEvent -// public static void registerLeavesPropertiesTypes(final TypeRegistryEvent event) { -// if (!event.isEntryOfType(LeavesProperties.class)) return; -// event.registerType(DynamicTrees.location("solid"), SolidLeavesProperties.TYPE); -// event.registerType(DynamicTrees.location("wart"), WartProperties.TYPE); -// event.registerType(DynamicTrees.location("palm"), PalmLeavesProperties.TYPE); -// event.registerType(DynamicTrees.location("scruffy"), ScruffyLeavesProperties.TYPE); -// } -// -// @SubscribeEvent -// public static void registerFamilyTypes(final TypeRegistryEvent event) { -// if (!event.isEntryOfType(Family.class)) return; -// event.registerType(DynamicTrees.location("nether_fungus"), NetherFungusFamily.TYPE); -// event.registerType(DynamicTrees.location("underground_roots"), UndergroundRootsFamily.TYPE); -// event.registerType(DynamicTrees.location("palm"), PalmFamily.TYPE); -// } -// -// @SubscribeEvent -// public static void registerSpeciesTypes(final TypeRegistryEvent event) { -// if (!event.isEntryOfType(Species.class)) return; -// event.registerType(DynamicTrees.location("nether_fungus"), NetherFungusSpecies.TYPE); -// event.registerType(DynamicTrees.location("swamp"), SwampSpecies.TYPE); -// event.registerType(DynamicTrees.location("palm"), PalmSpecies.TYPE); -// event.registerType(DynamicTrees.location("underground_roots"), UndergroundRootsSpecies.TYPE); -// } -// -// @SubscribeEvent -// public static void registerSoilPropertiesTypes(final TypeRegistryEvent event) { -// if (!event.isEntryOfType(SoilProperties.class)) return; -// event.registerType(DynamicTrees.location("water"), WaterSoilProperties.TYPE); -// event.registerType(DynamicTrees.location("spreadable"), SpreadableSoilProperties.TYPE); -// event.registerType(DynamicTrees.location("aerial_roots"), AerialRootsSoilProperties.TYPE); -// } -// -// /////////////////////////////////////////// -// // CUSTOM TREE LOGIC -// /////////////////////////////////////////// -// -// @SubscribeEvent -// public static void onCellKitRegistry(final RegistryEvent event) { -// if (!event.isEntryOfType(CellKit.class)) return; -// CellKits.register(event.getRegistry()); -// } -// -// @SubscribeEvent -// public static void onGrowthLogicKitRegistry(final RegistryEvent event) { -// if (!event.isEntryOfType(GrowthLogicKit.class)) return; -// GrowthLogicKits.register(event.getRegistry()); -// } -// -// @SubscribeEvent -// public static void onGenFeatureRegistry(final RegistryEvent event) { -// if (!event.isEntryOfType(GenFeature.class)) return; -// GenFeatures.register(event.getRegistry()); -// } -// -// @SubscribeEvent -// public static void onFeatureCancellerRegistry(final RegistryEvent event) { -// if (!event.isEntryOfType(FeatureCanceller.class)) return; -// FeatureCancellers.register(event.getRegistry()); -// } - - DynamicRegistrySetupCallback.EVENT.register((dynamicRegistryView -> { - final List> registries = Registries.REGISTRIES.stream() - .filter(registry -> registry instanceof SimpleRegistry) - .map(registry -> (SimpleRegistry) registry) - .collect(Collectors.toList()); - - // Post registry events. - registries.forEach(SimpleRegistry::postRegistryEvent); - - Resources.setupTreesResourceManager(); - - // Register Forge registry entry getters and add-on Json object getters. - JsonDeserializers.registerRegistryEntryGetters(); - JsonDeserializers.postRegistryEvent(); - - // Register feature cancellers. - FeatureCanceller.REGISTRY.postRegistryEvent(); - FeatureCanceller.REGISTRY.lock(); - })); - - //Register any registry entries from Json files. Resources.MANAGER.load(); - // Lock all the registries. Registries.REGISTRIES.stream() .filter(registry -> registry instanceof SimpleRegistry) .forEach(Registry::lock); + } + + private static void registerLeavesPropertiesTypes() { + LeavesProperties.REGISTRY.registerType(DynamicTrees.location("solid"), SolidLeavesProperties.TYPE); + LeavesProperties.REGISTRY.registerType(DynamicTrees.location("wart"), WartProperties.TYPE); + LeavesProperties.REGISTRY.registerType(DynamicTrees.location("palm"), PalmLeavesProperties.TYPE); + LeavesProperties.REGISTRY.registerType(DynamicTrees.location("scruffy"), ScruffyLeavesProperties.TYPE); + } + + private static void registerFamilyTypes() { + Family.REGISTRY.registerType(DynamicTrees.location("nether_fungus"), NetherFungusFamily.TYPE); + Family.REGISTRY.registerType(DynamicTrees.location("underground_roots"), UndergroundRootsFamily.TYPE); + Family.REGISTRY.registerType(DynamicTrees.location("palm"), PalmFamily.TYPE); + } + + private static void registerSpeciesTypes() { + Species.REGISTRY.registerType(DynamicTrees.location("nether_fungus"), NetherFungusSpecies.TYPE); + Species.REGISTRY.registerType(DynamicTrees.location("swamp"), SwampSpecies.TYPE); + Species.REGISTRY.registerType(DynamicTrees.location("palm"), PalmSpecies.TYPE); + Species.REGISTRY.registerType(DynamicTrees.location("underground_roots"), UndergroundRootsSpecies.TYPE); + } + + private static void registerSoilPropertiesTypes() { + SoilProperties.REGISTRY.registerType(DynamicTrees.location("water"), WaterSoilProperties.TYPE); + SoilProperties.REGISTRY.registerType(DynamicTrees.location("spreadable"), SpreadableSoilProperties.TYPE); + SoilProperties.REGISTRY.registerType(DynamicTrees.location("aerial_roots"), AerialRootsSoilProperties.TYPE); + } + + private static void registerCellKits() { + CellKits.register(CellKit.REGISTRY); + } + + private static void registerGrowthLogicKits() { + GrowthLogicKits.register(GrowthLogicKit.REGISTRY); + } + + private static void registerGenFeatures() { + GenFeatures.register(GenFeature.REGISTRY); + } + private static void registerFeatureCancellers() { + FeatureCancellers.register(FeatureCanceller.REGISTRY); } } diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/VanillaSaplingEventHandler.java b/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/VanillaSaplingEventHandler.java new file mode 100644 index 000000000..cd2404009 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/event/handler/VanillaSaplingEventHandler.java @@ -0,0 +1,62 @@ +package com.dtteam.dynamictrees.event.handler; + +import com.dtteam.dynamictrees.block.sapling.DynamicSaplingBlock; +import com.dtteam.dynamictrees.config.DTConfigs; +import com.dtteam.dynamictrees.tree.species.Species; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.BlockHitResult; + +public class VanillaSaplingEventHandler { + + private static boolean isEnabled = false; + + public static void register() { + UseBlockCallback.EVENT.register(VanillaSaplingEventHandler::onUseBlock); + } + + public static void updateEnabled() { + isEnabled = DTConfigs.COMMON.replaceVanillaSaplings.get(); + } + + private static InteractionResult onUseBlock(Player player, Level level, InteractionHand hand, BlockHitResult hitResult) { + if (!isEnabled || level.isClientSide()) { + return InteractionResult.PASS; + } + + ItemStack stack = player.getItemInHand(hand); + if (stack.isEmpty() || !(stack.getItem() instanceof BlockItem blockItem)) { + return InteractionResult.PASS; + } + + Block block = blockItem.getBlock(); + if (!DynamicSaplingBlock.SAPLING_REPLACERS.containsKey(block)) { + return InteractionResult.PASS; + } + + BlockPos placePos = hitResult.getBlockPos().relative(hitResult.getDirection()); + + if (!level.getBlockState(placePos).canBeReplaced()) { + return InteractionResult.PASS; + } + + Species targetSpecies = DynamicSaplingBlock.SAPLING_REPLACERS.get(block); + Species species = targetSpecies.selfOrLocationOverride(level, placePos); + + if (species.plantSapling(level, placePos, targetSpecies != species)) { + if (!player.isCreative()) { + stack.shrink(1); + } + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinBushBlock.java b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinBushBlock.java new file mode 100644 index 000000000..7447e03d0 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinBushBlock.java @@ -0,0 +1,34 @@ +package com.dtteam.dynamictrees.mixin; + +import com.dtteam.dynamictrees.block.branch.BasicRootsBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BushBlock; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BushBlock.class) +public class MixinBushBlock { + + @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") + private void canSurvive(BlockState state, LevelReader level, BlockPos pos, CallbackInfoReturnable cir) { + BlockPos blockpos = pos.below(); + BlockState belowBlockState = level.getBlockState(blockpos); + if (belowBlockState.getBlock() instanceof BasicRootsBlock roots){ + if (belowBlockState.getValue(BasicRootsBlock.LAYER) == BasicRootsBlock.Layer.COVERED){ + Block block = BasicRootsBlock.Layer.COVERED.getPrimitive(roots.getFamily()).orElse(null); + if (block == null) return; + cir.setReturnValue(mayPlaceOn(block.defaultBlockState(), level, blockpos)); + } + } + } + +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinChunkSerializer.java b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinChunkSerializer.java index 29cad3061..1edb5147f 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinChunkSerializer.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinChunkSerializer.java @@ -1,8 +1,7 @@ package com.dtteam.dynamictrees.mixin; import com.dtteam.dynamictrees.api.worldgen.LevelContext; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.systems.poissondisc.UniversalPoissonDiscProvider; import com.dtteam.dynamictrees.worldgen.feature.DynamicTreeFeature; import net.minecraft.nbt.CompoundTag; @@ -24,7 +23,7 @@ public class MixinChunkSerializer { @Inject(at = @At("HEAD"), method = "read (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/ai/village/poi/PoiManager;Lnet/minecraft/world/level/chunk/storage/RegionStorageInfo;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/level/chunk/ProtoChunk;") private static void read(ServerLevel level, PoiManager poiManager, RegionStorageInfo regionStorageInfo, ChunkPos pos, CompoundTag tag, CallbackInfoReturnable cir) { - if (!Services.CONFIG.getBoolConfig(IConfigHelper.WORLD_GEN)) return; + if (!DTConfigs.SERVER.worldGen.get()) return; final byte[] circleData = tag.getByteArray(UniversalPoissonDiscProvider.CIRCLE_DATA_ID); final UniversalPoissonDiscProvider discProvider = DynamicTreeFeature.DISC_PROVIDER; @@ -34,7 +33,7 @@ private static void read(ServerLevel level, PoiManager poiManager, RegionStorage @Inject(at = @At("RETURN"), method = "write (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;)Lnet/minecraft/nbt/CompoundTag;") private static void write(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable cir) { - if (!Services.CONFIG.getBoolConfig(IConfigHelper.WORLD_GEN)) return; + if (!DTConfigs.SERVER.worldGen.get()) return; final LevelContext levelContext = LevelContext.create(level); final UniversalPoissonDiscProvider discProvider = DynamicTreeFeature.DISC_PROVIDER; diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinMinecraftServer.java b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinMinecraftServer.java new file mode 100644 index 000000000..44f4bcc99 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinMinecraftServer.java @@ -0,0 +1,16 @@ +package com.dtteam.dynamictrees.mixin; + +import com.dtteam.dynamictrees.platform.FabricMiscHelper; +import net.minecraft.server.MinecraftServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = MinecraftServer.class, priority = 500) +public abstract class MixinMinecraftServer { + @Inject(method = "", at = @At(value = "RETURN")) + private void onServerConstruction(CallbackInfo ci) { + FabricMiscHelper.currentServer = (MinecraftServer) (Object) this; + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinSaplingBlock.java b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinSaplingBlock.java new file mode 100644 index 000000000..6224068c0 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/mixin/MixinSaplingBlock.java @@ -0,0 +1,43 @@ +package com.dtteam.dynamictrees.mixin; + +import com.dtteam.dynamictrees.block.sapling.DynamicSaplingBlock; +import com.dtteam.dynamictrees.config.DTConfigs; +import com.dtteam.dynamictrees.tree.species.Species; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SaplingBlock; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(SaplingBlock.class) +public class MixinSaplingBlock { + + @Inject(method = "advanceTree", at = @At("HEAD"), cancellable = true) + private void onAdvanceTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, CallbackInfo ci) { + if (!DTConfigs.COMMON.replaceVanillaSaplings.get()) { + return; + } + + Block block = state.getBlock(); + if (!DynamicSaplingBlock.SAPLING_REPLACERS.containsKey(block)) { + return; + } + + Species species = DynamicSaplingBlock.SAPLING_REPLACERS.get(block) + .selfOrLocationOverride(level, pos); + + level.removeBlock(pos, false); + ci.cancel(); + + if (species.isValid()) { + if (DynamicSaplingBlock.canSaplingStay(level, species, pos)) { + species.transitionToTree(level, pos); + } + } + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/BakedModelBlockPottedSapling.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/BakedModelBlockPottedSapling.java new file mode 100644 index 000000000..38e47de31 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/BakedModelBlockPottedSapling.java @@ -0,0 +1,30 @@ +package com.dtteam.dynamictrees.model; + +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class BakedModelBlockPottedSapling extends ForwardingBakedModel { + + public BakedModelBlockPottedSapling(BakedModel basePotModel) { + this.wrapped = basePotModel; + } + + @Override + public boolean isVanillaAdapter() { + return true; + } + + @Override + @NotNull + public List getQuads(BlockState state, Direction face, RandomSource random) { + return new ArrayList<>(wrapped.getQuads(state, face, random)); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/BranchBlockUnbakedModel.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/BranchBlockUnbakedModel.java new file mode 100644 index 000000000..bd5c0c98c --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/BranchBlockUnbakedModel.java @@ -0,0 +1,59 @@ +package com.dtteam.dynamictrees.model; + +import com.dtteam.dynamictrees.model.baked.BasicBranchBlockBakedModel; +import com.dtteam.dynamictrees.model.baked.ThickBranchBlockBakedModel; +import com.dtteam.dynamictrees.tree.family.Family; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.InventoryMenu; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.function.Function; + +public class BranchBlockUnbakedModel implements UnbakedModel { + + protected final ResourceLocation barkTextureLocation; + protected final ResourceLocation ringsTextureLocation; + protected final ResourceLocation familyName; + protected final boolean forceThickness; + + public BranchBlockUnbakedModel(ResourceLocation barkTextureLocation, ResourceLocation ringsTextureLocation, @Nullable ResourceLocation familyName, boolean forceThickness) { + this.barkTextureLocation = barkTextureLocation; + this.ringsTextureLocation = ringsTextureLocation; + this.familyName = familyName; + this.forceThickness = forceThickness; + } + + @Override + public Collection getDependencies() { + return Collections.emptyList(); + } + + @Override + public void resolveParents(Function resolver) { + } + + @Override + public BakedModel bake(ModelBaker baker, Function spriteGetter, ModelState state) { + TextureAtlasSprite barkSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, barkTextureLocation)); + TextureAtlasSprite ringsSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, ringsTextureLocation)); + + Family family = familyName != null ? Family.REGISTRY.get(familyName) : null; + boolean useThickModel = forceThickness || (family != null && family.isThick()); + + if (useThickModel) { + ResourceLocation thickRingsLocation = ringsTextureLocation.withSuffix("_thick"); + TextureAtlasSprite thickRingsSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, thickRingsLocation)); + return new ThickBranchBlockBakedModel(barkSprite, ringsSprite, thickRingsSprite); + } + + return new BasicBranchBlockBakedModel(barkSprite, ringsSprite); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/DTModelLoadingPlugin.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/DTModelLoadingPlugin.java new file mode 100644 index 000000000..752b58e5e --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/DTModelLoadingPlugin.java @@ -0,0 +1,246 @@ +package com.dtteam.dynamictrees.model; + +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.block.branch.BasicRootsBlock; +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.dtteam.dynamictrees.block.branch.SurfaceRootBlock; +import com.dtteam.dynamictrees.model.baked.BasicBranchBlockBakedModel; +import com.dtteam.dynamictrees.model.baked.BasicRootsBlockBakedModel; +import com.dtteam.dynamictrees.model.baked.SurfaceRootBlockBakedModel; +import com.dtteam.dynamictrees.model.baked.ThickBranchBlockBakedModel; +import com.dtteam.dynamictrees.tree.family.Family; +import com.dtteam.dynamictrees.tree.family.UndergroundRootsFamily; +import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; +import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.level.block.Block; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +public class DTModelLoadingPlugin implements ModelLoadingPlugin { + + public static final ResourceLocation POTTED_SAPLING_MODEL = DynamicTrees.location("potted_sapling"); + private static final Map BRANCH_MODEL_CACHE = new HashMap<>(); + private static final Map ROOT_MODEL_CACHE = new HashMap<>(); + private static final Map UNDERGROUND_ROOTS_MODEL_CACHE = new HashMap<>(); + private static boolean modelsInitialized = false; + + @Override + public void onInitializeModelLoader(Context pluginContext) { + modelsInitialized = false; + BRANCH_MODEL_CACHE.clear(); + ROOT_MODEL_CACHE.clear(); + UNDERGROUND_ROOTS_MODEL_CACHE.clear(); + pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, this::modifyModelAfterBake); + } + + private void initBranchModels(Function spriteGetter) { + if (modelsInitialized) return; + modelsInitialized = true; + + for (Family family : Family.REGISTRY.getAll()) { + if (!family.isValid()) continue; + + family.getPrimitiveLog().ifPresent(primitiveLog -> { + ResourceLocation primitiveLogId = BuiltInRegistries.BLOCK.getKey(primitiveLog); + ResourceLocation barkTexture = ResourceLocation.fromNamespaceAndPath(primitiveLogId.getNamespace(), "block/" + primitiveLogId.getPath()); + ResourceLocation ringsTexture = barkTexture.withSuffix("_top"); + + AtomicReference barkRef = new AtomicReference<>(barkTexture); + AtomicReference ringsRef = new AtomicReference<>(ringsTexture); + + family.getTexturePath(Family.BRANCH).ifPresent(barkRef::set); + family.getTexturePath(Family.BRANCH_TOP).ifPresent(ringsRef::set); + + boolean isThick = family.isThick(); + + family.getBranch().ifPresent(branch -> { + ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(branch); + BakedModel model = createBranchModel(barkRef.get(), ringsRef.get(), isThick, spriteGetter); + BRANCH_MODEL_CACHE.put(blockId, model); + }); + }); + + family.getPrimitiveStrippedLog().ifPresent(strippedLog -> { + ResourceLocation strippedLogId = BuiltInRegistries.BLOCK.getKey(strippedLog); + ResourceLocation strippedBarkTexture = ResourceLocation.fromNamespaceAndPath(strippedLogId.getNamespace(), "block/" + strippedLogId.getPath()); + ResourceLocation strippedRingsTexture = strippedBarkTexture.withSuffix("_top"); + + AtomicReference barkRef = new AtomicReference<>(strippedBarkTexture); + AtomicReference ringsRef = new AtomicReference<>(strippedRingsTexture); + + family.getTexturePath(Family.STRIPPED_BRANCH).ifPresent(barkRef::set); + family.getTexturePath(Family.STRIPPED_BRANCH_TOP).ifPresent(ringsRef::set); + + boolean isThick = family.isThick(); + + family.getStrippedBranch().ifPresent(strippedBranch -> { + ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(strippedBranch); + BakedModel model = createBranchModel(barkRef.get(), ringsRef.get(), isThick, spriteGetter); + BRANCH_MODEL_CACHE.put(blockId, model); + }); + }); + + family.getSurfaceRoot().ifPresent(surfaceRoot -> { + family.getPrimitiveLog().ifPresent(primitiveLog -> { + ResourceLocation primitiveLogId = BuiltInRegistries.BLOCK.getKey(primitiveLog); + ResourceLocation barkTexture = ResourceLocation.fromNamespaceAndPath(primitiveLogId.getNamespace(), "block/" + primitiveLogId.getPath()); + AtomicReference barkRef = new AtomicReference<>(barkTexture); + family.getTexturePath(Family.BRANCH).ifPresent(barkRef::set); + + ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(surfaceRoot); + BakedModel model = createRootModel(barkRef.get(), spriteGetter); + ROOT_MODEL_CACHE.put(blockId, model); + }); + }); + + if (family instanceof UndergroundRootsFamily undergroundFamily) { + undergroundFamily.getRoots().ifPresent(roots -> { + ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(roots); + + undergroundFamily.getPrimitiveRoots().ifPresent(primitiveRoots -> { + ResourceLocation primitiveRootsId = BuiltInRegistries.BLOCK.getKey(primitiveRoots); + ResourceLocation barkTexture = ResourceLocation.fromNamespaceAndPath(primitiveRootsId.getNamespace(), "block/" + primitiveRootsId.getPath() + "_side"); + ResourceLocation ringsTexture = ResourceLocation.fromNamespaceAndPath(primitiveRootsId.getNamespace(), "block/" + primitiveRootsId.getPath() + "_top"); + + AtomicReference barkRef = new AtomicReference<>(barkTexture); + AtomicReference ringsRef = new AtomicReference<>(ringsTexture); + + family.getTexturePath(Family.ROOTS_SIDE).ifPresent(barkRef::set); + family.getTexturePath(Family.ROOTS_TOP).ifPresent(ringsRef::set); + + BakedModel model = createRootsBlockModel(barkRef.get(), ringsRef.get(), spriteGetter); + UNDERGROUND_ROOTS_MODEL_CACHE.put(blockId.withSuffix("_exposed"), model); + }); + + undergroundFamily.getPrimitiveFilledRoots().ifPresent(primitiveFilledRoots -> { + ResourceLocation primitiveFilledRootsId = BuiltInRegistries.BLOCK.getKey(primitiveFilledRoots); + ResourceLocation barkTexture = ResourceLocation.fromNamespaceAndPath(primitiveFilledRootsId.getNamespace(), "block/" + primitiveFilledRootsId.getPath() + "_side"); + ResourceLocation ringsTexture = ResourceLocation.fromNamespaceAndPath(primitiveFilledRootsId.getNamespace(), "block/" + primitiveFilledRootsId.getPath() + "_top"); + + BakedModel model = createRootsBlockModel(barkTexture, ringsTexture, spriteGetter); + UNDERGROUND_ROOTS_MODEL_CACHE.put(blockId.withSuffix("_filled"), model); + }); + + + }); + } + } + } + + private BakedModel createBranchModel(ResourceLocation barkTexture, ResourceLocation ringsTexture, boolean isThick, Function spriteGetter) { + TextureAtlasSprite barkSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, barkTexture)); + TextureAtlasSprite ringsSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, ringsTexture)); + + if (isThick) { + ResourceLocation thickRingsTexture = ringsTexture.withSuffix("_thick"); + TextureAtlasSprite thickRingsSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, thickRingsTexture)); + return new ThickBranchBlockBakedModel(barkSprite, ringsSprite, thickRingsSprite); + } + + return new BasicBranchBlockBakedModel(barkSprite, ringsSprite); + } + + private BakedModel createRootModel(ResourceLocation barkTexture, Function spriteGetter) { + TextureAtlasSprite barkSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, barkTexture)); + return new SurfaceRootBlockBakedModel(barkSprite); + } + + private BakedModel createRootsBlockModel(ResourceLocation barkTexture, ResourceLocation ringsTexture, Function spriteGetter) { + TextureAtlasSprite barkSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, barkTexture)); + TextureAtlasSprite ringsSprite = spriteGetter.apply(new Material(InventoryMenu.BLOCK_ATLAS, ringsTexture)); + return new BasicRootsBlockBakedModel(barkSprite, ringsSprite); + } + + private BakedModel createFallbackRootsModel(UndergroundRootsFamily family, String variant, Function spriteGetter) { + if (variant.contains("layer=exposed")) { + return family.getPrimitiveRoots().map(primitiveRoots -> { + ResourceLocation primitiveRootsId = BuiltInRegistries.BLOCK.getKey(primitiveRoots); + ResourceLocation barkTexture = ResourceLocation.fromNamespaceAndPath(primitiveRootsId.getNamespace(), "block/" + primitiveRootsId.getPath() + "_side"); + ResourceLocation ringsTexture = ResourceLocation.fromNamespaceAndPath(primitiveRootsId.getNamespace(), "block/" + primitiveRootsId.getPath() + "_top"); + return createRootsBlockModel(barkTexture, ringsTexture, spriteGetter); + }).orElse(null); + } else if (variant.contains("layer=filled")) { + return family.getPrimitiveFilledRoots().map(primitiveFilledRoots -> { + ResourceLocation primitiveFilledRootsId = BuiltInRegistries.BLOCK.getKey(primitiveFilledRoots); + ResourceLocation barkTexture = ResourceLocation.fromNamespaceAndPath(primitiveFilledRootsId.getNamespace(), "block/" + primitiveFilledRootsId.getPath() + "_side"); + ResourceLocation ringsTexture = ResourceLocation.fromNamespaceAndPath(primitiveFilledRootsId.getNamespace(), "block/" + primitiveFilledRootsId.getPath() + "_top"); + return createRootsBlockModel(barkTexture, ringsTexture, spriteGetter); + }).orElse(null); + } + return null; + } + + private BakedModel modifyModelAfterBake(BakedModel model, ModelModifier.AfterBake.Context context) { + ModelResourceLocation modelId = context.topLevelId(); + if (modelId == null) return model; + + if (modelId.id().equals(POTTED_SAPLING_MODEL)) { + return new BakedModelBlockPottedSapling(model); + } + + ResourceLocation blockId = modelId.id(); + Block block = BuiltInRegistries.BLOCK.get(blockId); + + if (block instanceof BasicRootsBlock rootsBlock) { + initBranchModels(context.textureGetter()); + + String variant = modelId.variant(); + ResourceLocation cacheKey; + if (variant.contains("layer=filled")) { + cacheKey = blockId.withSuffix("_filled"); + } else if (variant.contains("layer=exposed")) { + cacheKey = blockId.withSuffix("_exposed"); + } else if (variant.contains("layer=covered")) { + return model; + } else { + return model; + } + + BakedModel rootsModel = UNDERGROUND_ROOTS_MODEL_CACHE.get(cacheKey); + if (rootsModel != null) { + return rootsModel; + } + + if (rootsBlock.getFamily() instanceof UndergroundRootsFamily undergroundFamily) { + BakedModel fallbackModel = createFallbackRootsModel(undergroundFamily, variant, context.textureGetter()); + if (fallbackModel != null) { + UNDERGROUND_ROOTS_MODEL_CACHE.put(cacheKey, fallbackModel); + return fallbackModel; + } + } + return model; + } + + if (block instanceof SurfaceRootBlock) { + initBranchModels(context.textureGetter()); + + BakedModel rootModel = ROOT_MODEL_CACHE.get(blockId); + if (rootModel != null) { + return rootModel; + } + return model; + } + + if (block instanceof BranchBlock) { + initBranchModels(context.textureGetter()); + + BakedModel branchModel = BRANCH_MODEL_CACHE.get(blockId); + if (branchModel != null) { + return branchModel; + } + } + + + return model; + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelFabric.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelFabric.java new file mode 100644 index 000000000..17204afd7 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/FallingTreeEntityModelFabric.java @@ -0,0 +1,257 @@ +package com.dtteam.dynamictrees.model; + +import com.dtteam.dynamictrees.api.network.BranchDestructionData; +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.dtteam.dynamictrees.block.soil.SoilBlock; +import com.dtteam.dynamictrees.entity.FallingTreeEntity; +import com.dtteam.dynamictrees.model.baked.BasicBranchBlockBakedModel; +import com.dtteam.dynamictrees.tree.TreeHelper; +import com.dtteam.dynamictrees.tree.species.Species; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +public class FallingTreeEntityModelFabric extends FallingTreeEntityModel { + + public FallingTreeEntityModelFabric(FallingTreeEntity entity) { + super(entity); + } + + @Override + public List generateTreeQuads(FallingTreeEntity entity) { + BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer(); + BranchDestructionData destructionData = entity.getDestroyData(); + Direction cutDir = destructionData.cutDir; + + ArrayList treeQuads = new ArrayList<>(); + + int[] connectionArray = new int[6]; + + if (destructionData.getNumBranches() > 0) { + BlockState exState = destructionData.getBranchBlockState(0); + BlockPos cutPos = destructionData.cutPos; + if (exState != null) { + Species species = destructionData.species; + RandomSource random = entity.getRandom(); + + boolean rootyBlockAdded = false; + if (destructionData.soilState != null) { + SoilBlock soilBlock = TreeHelper.getRooty(BuiltInRegistries.BLOCK.get(destructionData.soilState.getLeft())); + if (soilBlock != null) { + BlockState soilState = soilBlock.GetStateFromIndex(destructionData.soilState.getRight()); + BakedModel rootyModel = dispatcher.getBlockModel(soilState); + BlockPos cutOffset = destructionData.getRelativeCutPos(); + treeQuads.addAll(toTreeQuadData( + getQuadsWithOffset(rootyModel, soilState, new Vec3(cutOffset.getX(), cutOffset.getY() - 1, cutOffset.getZ()), random), + destructionData.species.getFamily().getRootColor(soilState, soilBlock.getColorFromBark()), + soilState)); + rootyBlockAdded = true; + } + } + + BakedModel branchModel = dispatcher.getBlockModel(exState); + destructionData.getConnections(0, connectionArray); + boolean bottomRingsAdded = false; + if (!rootyBlockAdded && connectionArray[cutDir.get3DDataValue()] > 0) { + BlockPos offsetPos = destructionData.getRelativeCutPos().relative(cutDir); + float offset = (8 - Math.min(((BranchBlock) exState.getBlock()).getRadius(exState), BranchBlock.MAX_RADIUS)) / 16f; + int coreRadius = ((BranchBlock) exState.getBlock()).getRadius(exState); + treeQuads.addAll(toTreeQuadData( + getBottomRingQuads(branchModel, new Vec3(offsetPos.getX(), offsetPos.getY(), offsetPos.getZ()).scale(offset), coreRadius, cutDir), + exState)); + bottomRingsAdded = true; + } + + for (int index = 0; index < destructionData.getNumBranches(); index++) { + Block previousBranch = exState.getBlock(); + exState = destructionData.getBranchBlockState(index); + if (!previousBranch.equals(exState.getBlock())) { + branchModel = dispatcher.getBlockModel(exState); + } + BlockPos relPos = destructionData.getBranchRelPos(index); + destructionData.getConnections(index, connectionArray); + int coreRadius = ((BranchBlock) exState.getBlock()).getRadius(exState); + Direction forceRingDir = (index == 0 && bottomRingsAdded) ? cutDir : null; + treeQuads.addAll(toTreeQuadData( + getBranchQuadsWithConnections(branchModel, exState, new Vec3(relPos.getX(), relPos.getY(), relPos.getZ()), random, connectionArray, coreRadius, forceRingDir), + exState)); + } + + for (Pair leafLoc : destructionData.getAllLeavesWithPos()) { + BlockState leafState = leafLoc.getValue(); + List bakedQuads = getQuadsWithOffset(dispatcher.getBlockModel(leafState), leafState, + new Vec3(leafLoc.getKey().getX(), leafLoc.getKey().getY(), leafLoc.getKey().getZ()), random); + + treeQuads.addAll(toTreeQuadData(bakedQuads, species.leafColorMultiplier(entity.level(), + cutPos.offset(leafLoc.getKey())), leafState)); + } + } + } + + return treeQuads; + } + + private List getBottomRingQuads(BakedModel model, Vec3 offset, int coreRadius, Direction cutDir) { + List allQuads = new ArrayList<>(); + + if (model instanceof BasicBranchBlockBakedModel branchModel) { + List ringQuads = branchModel.ringsQuads[coreRadius - 1]; + for (BakedQuad quad : ringQuads) { + if (quad.getDirection() == cutDir) { + allQuads.add(quad); + } + } + } + + if (offset.x() != 0 || offset.y() != 0 || offset.z() != 0) { + List offsetQuads = new ArrayList<>(); + for (BakedQuad quad : allQuads) { + offsetQuads.add(offsetQuad(quad, offset)); + } + return offsetQuads; + } + + return allQuads; + } + + private List getBranchQuadsWithConnections(BakedModel model, BlockState state, Vec3 offset, RandomSource random, int[] connections, int coreRadius, Direction forceRingDir) { + List allQuads = new ArrayList<>(); + + if (model instanceof BasicBranchBlockBakedModel branchModel) { + int twigRadius = 1; + if (state.getBlock() instanceof BranchBlock branchBlock) { + twigRadius = branchBlock.getFamily().getPrimaryThickness(); + } + + int numConnections = 0; + for (int i : connections) { + numConnections += (i != 0) ? 1 : 0; + } + + Direction sourceDir = getSourceDir(coreRadius, connections); + int coreDir = resolveCoreDir(sourceDir); + Direction coreRingDir = forceRingDir != null ? forceRingDir : + ((numConnections == 1 && sourceDir != null) ? sourceDir.getOpposite() : null); + + for (Direction face : Direction.values()) { + if (coreRadius != connections[face.get3DDataValue()]) { + List quads; + if (coreRingDir == null || coreRingDir != face) { + quads = branchModel.coresQuads[coreDir][coreRadius - 1]; + } else { + quads = branchModel.ringsQuads[coreRadius - 1]; + } + for (BakedQuad quad : quads) { + if (quad.getDirection() == face) { + allQuads.add(quad); + } + } + } + + if (coreRadius != 8) { + for (Direction connDir : Direction.values()) { + int idx = connDir.get3DDataValue(); + int connRadius = connections[idx]; + if (connRadius > 0 && (connRadius <= twigRadius || face != connDir)) { + List sleeveQuads = branchModel.sleevesQuads[idx][connRadius - 1]; + if (sleeveQuads != null) { + for (BakedQuad quad : sleeveQuads) { + if (quad.getDirection() == face) { + allQuads.add(quad); + } + } + } + } + } + } + } + } else { + for (Direction direction : Direction.values()) { + allQuads.addAll(model.getQuads(state, direction, random)); + } + allQuads.addAll(model.getQuads(state, null, random)); + } + + if (offset.x() != 0 || offset.y() != 0 || offset.z() != 0) { + List offsetQuads = new ArrayList<>(); + for (BakedQuad quad : allQuads) { + offsetQuads.add(offsetQuad(quad, offset)); + } + return offsetQuads; + } + + return allQuads; + } + + private Direction getSourceDir(int coreRadius, int[] connections) { + int largestConnection = 0; + Direction sourceDir = null; + + for (Direction dir : Direction.values()) { + int connRadius = connections[dir.get3DDataValue()]; + if (connRadius > largestConnection) { + largestConnection = connRadius; + sourceDir = dir; + } + } + + if (largestConnection < coreRadius) { + sourceDir = null; + } + return sourceDir; + } + + private int resolveCoreDir(Direction dir) { + if (dir == null) { + return 0; + } + return dir.get3DDataValue() >> 1; + } + + private List getQuadsWithOffset(BakedModel model, BlockState state, Vec3 offset, RandomSource random) { + List allQuads = new ArrayList<>(); + + for (Direction direction : Direction.values()) { + allQuads.addAll(model.getQuads(state, direction, random)); + } + allQuads.addAll(model.getQuads(state, null, random)); + + if (offset.x() != 0 || offset.y() != 0 || offset.z() != 0) { + List offsetQuads = new ArrayList<>(); + for (BakedQuad quad : allQuads) { + offsetQuads.add(offsetQuad(quad, offset)); + } + return offsetQuads; + } + + return allQuads; + } + + private BakedQuad offsetQuad(BakedQuad quad, Vec3 offset) { + int[] vertexData = quad.getVertices().clone(); + + for (int i = 0; i < 4; i++) { + int baseIndex = i * 8; + float x = Float.intBitsToFloat(vertexData[baseIndex]) + (float) offset.x(); + float y = Float.intBitsToFloat(vertexData[baseIndex + 1]) + (float) offset.y(); + float z = Float.intBitsToFloat(vertexData[baseIndex + 2]) + (float) offset.z(); + vertexData[baseIndex] = Float.floatToRawIntBits(x); + vertexData[baseIndex + 1] = Float.floatToRawIntBits(y); + vertexData[baseIndex + 2] = Float.floatToRawIntBits(z); + } + + return new BakedQuad(vertexData, quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade()); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java new file mode 100644 index 000000000..80b4d2e1f --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java @@ -0,0 +1,305 @@ +package com.dtteam.dynamictrees.model.baked; + +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.google.common.collect.Maps; +import net.fabricmc.fabric.api.renderer.v1.mesh.*; +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockFaceUV; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +@SuppressWarnings("unchecked") +public class BasicBranchBlockBakedModel implements BakedModel, FabricBakedModel { + + protected final TextureAtlasSprite barkTexture; + protected final TextureAtlasSprite ringsTexture; + + public final List[][] sleevesQuads = new List[6][8]; + public final List[][] coresQuads = new List[3][8]; + public final List[] ringsQuads = new List[8]; + + public BasicBranchBlockBakedModel(TextureAtlasSprite barkTexture, TextureAtlasSprite ringsTexture) { + this.barkTexture = barkTexture; + this.ringsTexture = ringsTexture; + initModels(); + } + + private void initModels() { + for (int i = 0; i < 8; i++) { + int radius = i + 1; + if (radius < 8) { + for (Direction dir : Direction.values()) { + sleevesQuads[dir.get3DDataValue()][i] = bakeSleeve(radius, dir, barkTexture); + } + } + coresQuads[0][i] = bakeCore(radius, Axis.Y, barkTexture); + coresQuads[1][i] = bakeCore(radius, Axis.Z, barkTexture); + coresQuads[2][i] = bakeCore(radius, Axis.X, barkTexture); + + ringsQuads[i] = bakeCore(radius, Axis.Y, ringsTexture); + } + } + + public BlockElement generateSleevePart(int radius, Direction dir) { + int dradius = radius * 2; + int halfSize = (16 - dradius) / 2; + int halfSizeX = dir.getStepX() != 0 ? halfSize : dradius; + int halfSizeY = dir.getStepY() != 0 ? halfSize : dradius; + int halfSizeZ = dir.getStepZ() != 0 ? halfSize : dradius; + int move = 16 - halfSize; + int centerX = 16 + (dir.getStepX() * move); + int centerY = 16 + (dir.getStepY() * move); + int centerZ = 16 + (dir.getStepZ() * move); + + Vector3f posFrom = new Vector3f((centerX - halfSizeX) / 2f, (centerY - halfSizeY) / 2f, (centerZ - halfSizeZ) / 2f); + Vector3f posTo = new Vector3f((centerX + halfSizeX) / 2f, (centerY + halfSizeY) / 2f, (centerZ + halfSizeZ) / 2f); + + boolean negative = dir.getAxisDirection() == AxisDirection.NEGATIVE; + if (dir.getAxis() == Axis.Z) { + negative = !negative; + } + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + + for (Direction face : Direction.values()) { + if (dir.getOpposite() != face) { + BlockFaceUV uvface = null; + if (dir == face) { + if (radius == 1) { + uvface = new BlockFaceUV(new float[]{8 - radius, 8 - radius, 8 + radius, 8 + radius}, 0); + } + } else { + uvface = new BlockFaceUV(new float[]{8 - radius, negative ? 16 - halfSize : 0, 8 + radius, negative ? 16 : halfSize}, getFaceAngle(dir.getAxis(), face)); + } + if (uvface != null) { + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvface)); + } + } + } + + return new BlockElement(posFrom, posTo, mapFacesIn, null, true); + } + + public List bakeSleeve(int radius, Direction dir, TextureAtlasSprite bark) { + BlockElement part = generateSleevePart(radius, dir); + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + + for (Map.Entry e : part.faces.entrySet()) { + Direction face = e.getKey(); + quads.add(faceBakery.bakeQuad(part.from, part.to, e.getValue(), bark, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + + return quads; + } + + protected BlockElement generateCorePart(int radius, Axis axis) { + Vector3f posFrom = new Vector3f(8 - radius, 8 - radius, 8 - radius); + Vector3f posTo = new Vector3f(8 + radius, 8 + radius, 8 + radius); + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + + for (Direction face : Direction.values()) { + BlockFaceUV uvface = new BlockFaceUV(new float[]{8 - radius, 8 - radius, 8 + radius, 8 + radius}, getFaceAngle(axis, face)); + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvface)); + } + + return new BlockElement(posFrom, posTo, mapFacesIn, null, true); + } + + public List bakeCore(int radius, Axis axis, TextureAtlasSprite icon) { + BlockElement part = generateCorePart(radius, axis); + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + + for (Map.Entry e : part.faces.entrySet()) { + Direction face = e.getKey(); + quads.add(faceBakery.bakeQuad(part.from, part.to, e.getValue(), icon, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + + return quads; + } + + public int getFaceAngle(Axis axis, Direction face) { + if (axis == Axis.Y) { + return 0; + } else if (axis == Axis.Z) { + return switch (face) { + case UP -> 0; + case WEST -> 270; + case DOWN -> 180; + default -> 90; + }; + } else { + return (face == Direction.NORTH) ? 270 : 90; + } + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + if (state == null) return; + + final int coreRadius = getRadius(state); + if (coreRadius <= 0 || coreRadius > 8) return; + + int[] connections = new int[]{0, 0, 0, 0, 0, 0}; + int twigRadius = 1; + + if (state.getBlock() instanceof BranchBlock branchBlock) { + connections = branchBlock.getConnectionData(blockView, pos, state).getAllRadii(); + twigRadius = branchBlock.getFamily().getPrimaryThickness(); + } + + int numConnections = 0; + for (int i : connections) { + numConnections += (i != 0) ? 1 : 0; + } + + QuadEmitter emitter = context.getEmitter(); + + Direction sourceDir = getSourceDir(coreRadius, connections); + int coreDir = resolveCoreDir(sourceDir); + Direction coreRingDir = (numConnections == 1 && sourceDir != null) ? sourceDir.getOpposite() : null; + + for (Direction face : Direction.values()) { + if (coreRadius != connections[face.get3DDataValue()]) { + List quads; + if (coreRingDir == null || coreRingDir != face) { + quads = coresQuads[coreDir][coreRadius - 1]; + } else { + quads = ringsQuads[coreRadius - 1]; + } + for (BakedQuad quad : quads) { + if (quad.getDirection() == face) { + emitQuad(emitter, quad, face); + } + } + } + + if (coreRadius != 8) { + for (Direction connDir : Direction.values()) { + int idx = connDir.get3DDataValue(); + int connRadius = connections[idx]; + if (connRadius > 0 && connRadius < 8 && (connRadius <= twigRadius || face != connDir)) { + List sleeveQuads = sleevesQuads[idx][connRadius - 1]; + if (sleeveQuads != null) { + for (BakedQuad quad : sleeveQuads) { + if (quad.getDirection() == face) { + emitQuad(emitter, quad, face); + } + } + } + } + } + } + } + } + + protected void emitQuad(QuadEmitter emitter, BakedQuad quad, Direction cullFace) { + emitter.fromVanilla(quad, null, cullFace); + emitter.emit(); + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + } + + @Nullable + protected Direction getSourceDir(int coreRadius, int[] connections) { + int largestConnection = 0; + Direction sourceDir = null; + + for (Direction dir : Direction.values()) { + int connRadius = connections[dir.get3DDataValue()]; + if (connRadius > largestConnection) { + largestConnection = connRadius; + sourceDir = dir; + } + } + + if (largestConnection < coreRadius) { + sourceDir = null; + } + return sourceDir; + } + + protected int resolveCoreDir(@Nullable Direction dir) { + if (dir == null) { + return 0; + } + return dir.get3DDataValue() >> 1; + } + + protected int getRadius(BlockState blockState) { + return ((BranchBlock) blockState.getBlock()).getRadius(blockState); + } + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction direction, RandomSource random) { + return Collections.emptyList(); + } + + @Override + public boolean useAmbientOcclusion() { + return true; + } + + @Override + public boolean isGui3d() { + return false; + } + + @Override + public boolean usesBlockLight() { + return false; + } + + @Override + public boolean isCustomRenderer() { + return false; + } + + @Override + public TextureAtlasSprite getParticleIcon() { + return barkTexture; + } + + @Override + public ItemTransforms getTransforms() { + return ItemTransforms.NO_TRANSFORMS; + } + + @Override + public ItemOverrides getOverrides() { + return ItemOverrides.EMPTY; + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java new file mode 100644 index 000000000..e900afa56 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java @@ -0,0 +1,166 @@ +package com.dtteam.dynamictrees.model.baked; + +import com.dtteam.dynamictrees.block.branch.BasicRootsBlock; +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.google.common.collect.Maps; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockFaceUV; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +@SuppressWarnings("unchecked") +public class BasicRootsBlockBakedModel extends BasicBranchBlockBakedModel { + + final static float Z_FIGHTING_OFFSET = 0.001f; + + private final List[][] sleeveEndFaces = new List[6][8]; + + public BasicRootsBlockBakedModel(TextureAtlasSprite barkTexture, TextureAtlasSprite ringsTexture) { + super(barkTexture, ringsTexture); + initRootsModels(); + } + + private void initRootsModels() { + for (int i = 0; i < 8; i++) { + int radius = i + 1; + for (Direction dir : Direction.values()) { + sleeveEndFaces[dir.get3DDataValue()][i] = bakeSleeveFace(radius, dir, ringsTexture); + } + } + } + + public List bakeSleeveFace(int radius, Direction dir, TextureAtlasSprite rings) { + int dradius = radius * 2; + int halfSize = (16 - dradius) / 2; + float halfSizeX = dir.getStepX() != 0 ? halfSize + Z_FIGHTING_OFFSET : dradius; + float halfSizeY = dir.getStepY() != 0 ? halfSize + Z_FIGHTING_OFFSET : dradius; + float halfSizeZ = dir.getStepZ() != 0 ? halfSize + Z_FIGHTING_OFFSET : dradius; + int move = 16 - halfSize; + int centerX = 16 + (dir.getStepX() * move); + int centerY = 16 + (dir.getStepY() * move); + int centerZ = 16 + (dir.getStepZ() * move); + + Vector3f posFrom = new Vector3f((centerX - halfSizeX) / 2f, (centerY - halfSizeY) / 2f, (centerZ - halfSizeZ) / 2f); + Vector3f posTo = new Vector3f((centerX + halfSizeX) / 2f, (centerY + halfSizeY) / 2f, (centerZ + halfSizeZ) / 2f); + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + BlockFaceUV uvface = new BlockFaceUV(new float[]{8 - radius, 8 - radius, 8 + radius, 8 + radius}, 0); + mapFacesIn.put(dir, new BlockElementFace(dir, -1, "", uvface)); + + BlockElement part = new BlockElement(posFrom, posTo, mapFacesIn, null, true); + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + + for (Map.Entry e : part.faces.entrySet()) { + Direction face = e.getKey(); + quads.add(faceBakery.bakeQuad(part.from, part.to, e.getValue(), rings, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + + return quads; + } + + @Override + protected int getRadius(BlockState blockState) { + if (blockState.getBlock() instanceof BasicRootsBlock) { + if (blockState.hasProperty(BasicRootsBlock.RADIUS)) { + return blockState.getValue(BasicRootsBlock.RADIUS); + } + } + return super.getRadius(blockState); + } + + @Override + protected void emitQuad(QuadEmitter emitter, BakedQuad quad, Direction cullFace) { + emitter.fromVanilla(quad, null, null); + emitter.emit(); + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + if (state == null) return; + + final int coreRadius = getRadius(state); + if (coreRadius <= 0 || coreRadius > 8) return; + + int[] connections = new int[]{0, 0, 0, 0, 0, 0}; + int twigRadius = 1; + + if (state.getBlock() instanceof BranchBlock branchBlock) { + connections = branchBlock.getConnectionData(blockView, pos, state).getAllRadii(); + twigRadius = branchBlock.getFamily().getPrimaryThickness(); + } + + int numConnections = 0; + for (int i : connections) { + numConnections += (i != 0) ? 1 : 0; + } + + var emitter = context.getEmitter(); + + Direction sourceDir = getSourceDir(coreRadius, connections); + int coreDir = resolveCoreDir(sourceDir); + Direction coreRingDir = (numConnections == 1 && sourceDir != null) ? sourceDir.getOpposite() : null; + + for (Direction face : Direction.values()) { + int connectionOnFace = connections[face.get3DDataValue()]; + + if (coreRadius != connectionOnFace) { + List quads; + if (coreRingDir == null || coreRingDir != face) { + quads = coresQuads[coreDir][coreRadius - 1]; + } else { + quads = ringsQuads[coreRadius - 1]; + } + for (BakedQuad quad : quads) { + if (quad.getDirection() == face) { + emitQuad(emitter, quad, face); + } + } + } + + if (coreRadius != 8) { + for (Direction connDir : Direction.values()) { + int idx = connDir.get3DDataValue(); + int connRadius = connections[idx]; + if (connRadius > 0 && connRadius < 8 && (connRadius <= twigRadius || face != connDir)) { + List sleeveQuads = sleevesQuads[idx][connRadius - 1]; + if (sleeveQuads != null) { + for (BakedQuad quad : sleeveQuads) { + if (quad.getDirection() == face) { + emitQuad(emitter, quad, face); + } + } + } + } + } + } + + if (connectionOnFace > 0 && connectionOnFace <= coreRadius) { + List endFaceQuads = sleeveEndFaces[face.get3DDataValue()][connectionOnFace - 1]; + if (endFaceQuads != null) { + for (BakedQuad quad : endFaceQuads) { + if (quad.getDirection() == face) { + emitQuad(emitter, quad, face); + } + } + } + } + } + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java new file mode 100644 index 000000000..b56fe423c --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java @@ -0,0 +1,361 @@ +package com.dtteam.dynamictrees.model.baked; + +import com.dtteam.dynamictrees.api.network.RootConnections; +import com.dtteam.dynamictrees.block.branch.SurfaceRootBlock; +import com.dtteam.dynamictrees.utility.CoordUtils; +import com.google.common.collect.Maps; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockFaceUV; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +@SuppressWarnings("unchecked") +public class SurfaceRootBlockBakedModel implements BakedModel, FabricBakedModel { + + protected final TextureAtlasSprite barkTexture; + + public final List[][] sleevesQuads = new List[4][7]; + public final List[][] coresQuads = new List[2][8]; + public final List[][] vertsQuads = new List[4][8]; + + public SurfaceRootBlockBakedModel(TextureAtlasSprite barkTexture) { + this.barkTexture = barkTexture; + initModels(); + } + + private void initModels() { + for (int r = 0; r < 8; r++) { + int radius = r + 1; + if (radius < 8) { + for (Direction dir : CoordUtils.HORIZONTALS) { + int horIndex = dir.get2DDataValue(); + sleevesQuads[horIndex][r] = bakeSleeve(radius, dir); + vertsQuads[horIndex][r] = bakeVert(radius, dir); + } + } + coresQuads[0][r] = bakeCore(radius, Direction.Axis.Z); + coresQuads[1][r] = bakeCore(radius, Direction.Axis.X); + } + } + + public int getRadialHeight(int radius) { + return radius * 2; + } + + public List bakeSleeve(int radius, Direction dir) { + int radialHeight = getRadialHeight(radius); + + int dradius = radius * 2; + int halfSize = (16 - dradius) / 2; + int halfSizeX = dir.getStepX() != 0 ? halfSize : dradius; + int halfSizeZ = dir.getStepZ() != 0 ? halfSize : dradius; + int move = 16 - halfSize; + int centerX = 16 + (dir.getStepX() * move); + int centerZ = 16 + (dir.getStepZ() * move); + + Vector3f posFrom = new Vector3f((centerX - halfSizeX) / 2f, 0, (centerZ - halfSizeZ) / 2f); + Vector3f posTo = new Vector3f((centerX + halfSizeX) / 2f, radialHeight, (centerZ + halfSizeZ) / 2f); + + boolean sleeveNegative = dir.getAxisDirection() == Direction.AxisDirection.NEGATIVE; + if (dir.getAxis() == Direction.Axis.Z) { + sleeveNegative = !sleeveNegative; + } + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + + for (Direction face : Direction.values()) { + if (dir.getOpposite() != face) { + BlockFaceUV uvface; + if (face.getAxis().isHorizontal()) { + boolean facePositive = face.getAxisDirection() == Direction.AxisDirection.POSITIVE; + uvface = new BlockFaceUV(new float[]{facePositive ? 16 - radialHeight : 0, (sleeveNegative ? 16 - halfSize : 0), facePositive ? 16 : radialHeight, (sleeveNegative ? 16 : halfSize)}, getFaceAngle(dir.getAxis(), face)); + } else { + uvface = new BlockFaceUV(new float[]{8 - radius, sleeveNegative ? 16 - halfSize : 0, 8 + radius, sleeveNegative ? 16 : halfSize}, getFaceAngle(dir.getAxis(), face)); + } + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvface)); + } + } + + BlockElement part = new BlockElement(posFrom, posTo, mapFacesIn, null, true); + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + + for (Map.Entry e : part.faces.entrySet()) { + Direction face = e.getKey(); + quads.add(faceBakery.bakeQuad(part.from, part.to, e.getValue(), barkTexture, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + + return quads; + } + + private List bakeVert(int radius, Direction dir) { + int radialHeight = getRadialHeight(radius); + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + + AABB partBoundary = new AABB(8 - radius, radialHeight, 8 - radius, 8 + radius, 16 + radialHeight, 8 + radius) + .move(dir.getStepX() * 7, 0, dir.getStepZ() * 7); + + for (int i = 0; i < 2; i++) { + AABB pieceBoundary = partBoundary.intersect(new AABB(0, 0, 0, 16, 16, 16).move(0, 16 * i, 0)); + + for (Direction face : Direction.values()) { + Map mapFacesIn = Maps.newEnumMap(Direction.class); + + BlockFaceUV uvface = new BlockFaceUV(modUV(getUVs(pieceBoundary, face)), getFaceAngle(Direction.Axis.Y, face)); + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvface)); + + Vector3f[] limits = AABBLimits(pieceBoundary); + + BlockElement part = new BlockElement(limits[0], limits[1], mapFacesIn, null, true); + quads.add(faceBakery.bakeQuad(part.from, part.to, part.faces.get(face), barkTexture, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + } + + return quads; + } + + public List bakeCore(int radius, Direction.Axis axis) { + int radialHeight = getRadialHeight(radius); + + Vector3f posFrom = new Vector3f(8 - radius, 0, 8 - radius); + Vector3f posTo = new Vector3f(8 + radius, radialHeight, 8 + radius); + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + + for (Direction face : Direction.values()) { + BlockFaceUV uvface; + if (face.getAxis().isHorizontal()) { + boolean positive = face.getAxisDirection() == Direction.AxisDirection.POSITIVE; + uvface = new BlockFaceUV(new float[]{positive ? 16 - radialHeight : 0, 8 - radius, positive ? 16 : radialHeight, 8 + radius}, getFaceAngle(axis, face)); + } else { + uvface = new BlockFaceUV(new float[]{8 - radius, 8 - radius, 8 + radius, 8 + radius}, getFaceAngle(axis, face)); + } + + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvface)); + } + + BlockElement part = new BlockElement(posFrom, posTo, mapFacesIn, null, true); + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + + for (Map.Entry e : part.faces.entrySet()) { + Direction face = e.getKey(); + quads.add(faceBakery.bakeQuad(part.from, part.to, e.getValue(), barkTexture, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + + return quads; + } + + public int getFaceAngle(Direction.Axis axis, Direction face) { + if (axis == Direction.Axis.Y) { + return 0; + } else if (axis == Direction.Axis.Z) { + return switch (face) { + case UP -> 0; + case WEST, NORTH -> 270; + case DOWN -> 180; + default -> 90; + }; + } else { + return (face == Direction.NORTH) ? 270 : 90; + } + } + + public float[] getUVs(AABB box, Direction face) { + return switch (face) { + case UP -> new float[]{(float) box.minX, (float) box.minZ, (float) box.maxX, (float) box.maxZ}; + case NORTH -> new float[]{16f - (float) box.maxX, (float) box.minY, 16f - (float) box.minX, (float) box.maxY}; + case SOUTH -> new float[]{(float) box.minX, (float) box.minY, (float) box.maxX, (float) box.maxY}; + case WEST -> new float[]{(float) box.minZ, (float) box.minY, (float) box.maxZ, (float) box.maxY}; + case EAST -> new float[]{16f - (float) box.maxZ, (float) box.minY, 16f - (float) box.minZ, (float) box.maxY}; + default -> new float[]{(float) box.minX, 16f - (float) box.minZ, (float) box.maxX, 16f - (float) box.maxZ}; + }; + } + + public float[] modUV(float[] uvs) { + uvs[0] = (int) uvs[0] & 0xf; + uvs[1] = (int) uvs[1] & 0xf; + uvs[2] = (((int) uvs[2] - 1) & 0xf) + 1; + uvs[3] = (((int) uvs[3] - 1) & 0xf) + 1; + return uvs; + } + + public Vector3f[] AABBLimits(AABB aabb) { + return new Vector3f[]{ + new Vector3f((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ), + new Vector3f((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ), + }; + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + if (state == null) return; + + int coreRadius = getRadius(state); + if (coreRadius <= 0 || coreRadius > 8) return; + + int[] connections = new int[]{0, 0, 0, 0}; + RootConnections.ConnectionLevel[] connectionLevels = RootConnections.PLACEHOLDER_CONNECTION_LEVELS.clone(); + + if (state.getBlock() instanceof SurfaceRootBlock surfaceRootBlock) { + RootConnections connectionData = surfaceRootBlock.getConnectionData(blockView, pos); + connections = connectionData.getAllRadii(); + connectionLevels = connectionData.getConnectionLevels(); + } + + for (int i = 0; i < connections.length; i++) { + connections[i] = Mth.clamp(connections[i], 0, coreRadius); + } + + Direction sourceDir = getSourceDir(coreRadius, connections); + if (sourceDir == null) { + sourceDir = Direction.DOWN; + } + int coreDir = resolveCoreDir(sourceDir); + + boolean isGrounded = state.getValue(SurfaceRootBlock.GROUNDED); + + QuadEmitter emitter = context.getEmitter(); + + for (Direction face : Direction.values()) { + if (isGrounded) { + List coreQuads = coresQuads[coreDir][coreRadius - 1]; + if (coreQuads != null) { + for (BakedQuad quad : coreQuads) { + if (quad.getDirection() == face) { + emitter.fromVanilla(quad, null, null); + emitter.emit(); + } + } + } + } + + if (coreRadius != 8) { + for (Direction connDir : CoordUtils.HORIZONTALS) { + int idx = connDir.get2DDataValue(); + int connRadius = connections[idx]; + if (connRadius > 0) { + if (isGrounded && sleevesQuads[idx][connRadius - 1] != null) { + for (BakedQuad quad : sleevesQuads[idx][connRadius - 1]) { + if (quad.getDirection() == face) { + emitter.fromVanilla(quad, null, null); + emitter.emit(); + } + } + } + if (connectionLevels[idx] == RootConnections.ConnectionLevel.HIGH && vertsQuads[idx][connRadius - 1] != null) { + for (BakedQuad quad : vertsQuads[idx][connRadius - 1]) { + if (quad.getDirection() == face) { + emitter.fromVanilla(quad, null, null); + emitter.emit(); + } + } + } + } + } + } + } + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + } + + protected Direction getSourceDir(int coreRadius, int[] connections) { + int largestConnection = 0; + Direction sourceDir = null; + + for (Direction dir : CoordUtils.HORIZONTALS) { + int horIndex = dir.get2DDataValue(); + int connRadius = connections[horIndex]; + if (connRadius > largestConnection) { + largestConnection = connRadius; + sourceDir = dir; + } + } + + if (largestConnection < coreRadius) { + sourceDir = null; + } + return sourceDir; + } + + protected int resolveCoreDir(Direction dir) { + return dir.getAxis() == Direction.Axis.X ? 1 : 0; + } + + protected int getRadius(BlockState blockState) { + return ((SurfaceRootBlock) blockState.getBlock()).getRadius(blockState); + } + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction direction, RandomSource random) { + return Collections.emptyList(); + } + + @Override + public boolean useAmbientOcclusion() { + return true; + } + + @Override + public boolean isGui3d() { + return false; + } + + @Override + public boolean usesBlockLight() { + return false; + } + + @Override + public boolean isCustomRenderer() { + return true; + } + + @Override + public TextureAtlasSprite getParticleIcon() { + return barkTexture; + } + + @Override + public ItemTransforms getTransforms() { + return ItemTransforms.NO_TRANSFORMS; + } + + @Override + public ItemOverrides getOverrides() { + return ItemOverrides.EMPTY; + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java new file mode 100644 index 000000000..d7e10ccc2 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java @@ -0,0 +1,235 @@ +package com.dtteam.dynamictrees.model.baked; + +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.dtteam.dynamictrees.block.branch.ThickBranchBlock; +import com.dtteam.dynamictrees.utility.CoordUtils; +import com.dtteam.dynamictrees.utility.CoordUtils.Surround; +import com.google.common.collect.Maps; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockFaceUV; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +@SuppressWarnings("unchecked") +public class ThickBranchBlockBakedModel extends BasicBranchBlockBakedModel { + + private final TextureAtlasSprite thickRingsTexture; + private final List[] trunksBarkQuads = new List[16]; + private final List[] trunksTopBarkQuads = new List[16]; + private final List[] trunksTopRingsQuads = new List[16]; + private final List[] trunksBotRingsQuads = new List[16]; + + public ThickBranchBlockBakedModel(TextureAtlasSprite barkTexture, TextureAtlasSprite ringsTexture, TextureAtlasSprite thickRingsTexture) { + super(barkTexture, ringsTexture); + this.thickRingsTexture = thickRingsTexture; + initThickModels(); + } + + private void initThickModels() { + for (int i = 0; i < ThickBranchBlock.MAX_RADIUS_THICK - ThickBranchBlock.MAX_RADIUS; i++) { + int radius = i + ThickBranchBlock.MAX_RADIUS + 1; + trunksBarkQuads[i] = bakeTrunkBark(radius, this.barkTexture, true); + trunksTopBarkQuads[i] = bakeTrunkBark(radius, this.barkTexture, false); + trunksTopRingsQuads[i] = bakeTrunkRings(radius, thickRingsTexture, Direction.UP); + trunksBotRingsQuads[i] = bakeTrunkRings(radius, thickRingsTexture, Direction.DOWN); + } + } + + public List bakeTrunkBark(int radius, TextureAtlasSprite bark, boolean side) { + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + AABB wholeVolume = new AABB(8 - radius, 0, 8 - radius, 8 + radius, 16, 8 + radius); + + final Direction[] run = side ? CoordUtils.HORIZONTALS : new Direction[]{Direction.UP, Direction.DOWN}; + ArrayList offsets = new ArrayList<>(); + + for (Surround dir : Surround.values()) { + offsets.add(dir.getOffset()); + } + offsets.add(new Vec3i(0, 0, 0)); + + for (Direction face : run) { + final Vec3i dirVector = face.getNormal(); + + for (Vec3i offset : offsets) { + if (face.getAxis() == Axis.Y || new Vec3(dirVector.getX(), dirVector.getY(), dirVector.getZ()).add(new Vec3(offset.getX(), offset.getY(), offset.getZ())).lengthSqr() > 2.25) { + Vec3 scaledOffset = new Vec3(offset.getX() * 16, offset.getY() * 16, offset.getZ() * 16); + AABB partBoundary = new AABB(0, 0, 0, 16, 16, 16).move(scaledOffset).intersect(wholeVolume); + + Vector3f[] limits = aabbLimits(partBoundary); + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + + BlockFaceUV uvface = new BlockFaceUV(modUV(getUVs(partBoundary, face)), getFaceAngle(Axis.Y, face)); + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvface)); + + BlockElement part = new BlockElement(limits[0], limits[1], mapFacesIn, null, true); + quads.add(faceBakery.bakeQuad(part.from, part.to, part.faces.get(face), bark, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + } + } + + return quads; + } + + public List bakeTrunkRings(int radius, TextureAtlasSprite ring, Direction face) { + List quads = new ArrayList<>(); + FaceBakery faceBakery = new FaceBakery(); + AABB wholeVolume = new AABB(8 - radius, 0, 8 - radius, 8 + radius, 16, 8 + radius); + int wholeVolumeWidth = 48; + + ArrayList offsets = new ArrayList<>(); + + for (Surround dir : Surround.values()) { + offsets.add(dir.getOffset()); + } + offsets.add(new Vec3i(0, 0, 0)); + + for (Vec3i offset : offsets) { + Vec3 scaledOffset = new Vec3(offset.getX() * 16, offset.getY() * 16, offset.getZ() * 16); + AABB partBoundary = new AABB(0, 0, 0, 16, 16, 16).move(scaledOffset).intersect(wholeVolume); + + Vector3f posFrom = new Vector3f((float) partBoundary.minX, (float) partBoundary.minY, (float) partBoundary.minZ); + Vector3f posTo = new Vector3f((float) partBoundary.maxX, (float) partBoundary.maxY, (float) partBoundary.maxZ); + + Map mapFacesIn = Maps.newEnumMap(Direction.class); + float[] uvs = getRingsUvs(face, partBoundary, wholeVolumeWidth); + + BlockFaceUV uvFace = new BlockFaceUV(uvs, getFaceAngle(Axis.Y, face)); + mapFacesIn.put(face, new BlockElementFace(null, -1, null, uvFace)); + + BlockElement part = new BlockElement(posFrom, posTo, mapFacesIn, null, true); + quads.add(faceBakery.bakeQuad(part.from, part.to, part.faces.get(face), ring, face, BlockModelRotation.X0_Y0, part.rotation, true)); + } + + return quads; + } + + private static float[] getRingsUvs(Direction face, AABB partBoundary, int wholeVolumeWidth) { + float textureOffsetX = -16f; + float textureOffsetZ = -16f; + + float minX = ((float) ((partBoundary.minX - textureOffsetX) / wholeVolumeWidth)) * 16f; + float maxX = ((float) ((partBoundary.maxX - textureOffsetX) / wholeVolumeWidth)) * 16f; + float minZ = ((float) ((partBoundary.minZ - textureOffsetZ) / wholeVolumeWidth)) * 16f; + float maxZ = ((float) ((partBoundary.maxZ - textureOffsetZ) / wholeVolumeWidth)) * 16f; + + if (face == Direction.DOWN) { + minZ = ((float) ((partBoundary.maxZ - textureOffsetZ) / wholeVolumeWidth)) * 16f; + maxZ = ((float) ((partBoundary.minZ - textureOffsetZ) / wholeVolumeWidth)) * 16f; + } + + return new float[]{minX, minZ, maxX, maxZ}; + } + + public static float[] getUVs(AABB box, Direction face) { + return switch (face) { + case UP -> new float[]{(float) box.minX, (float) box.minZ, (float) box.maxX, (float) box.maxZ}; + case NORTH -> new float[]{16f - (float) box.maxX, (float) box.minY, 16f - (float) box.minX, (float) box.maxY}; + case SOUTH -> new float[]{(float) box.minX, (float) box.minY, (float) box.maxX, (float) box.maxY}; + case WEST -> new float[]{(float) box.minZ, (float) box.minY, (float) box.maxZ, (float) box.maxY}; + case EAST -> new float[]{16f - (float) box.maxZ, (float) box.minY, 16f - (float) box.minZ, (float) box.maxY}; + default -> new float[]{(float) box.minX, 16f - (float) box.minZ, (float) box.maxX, 16f - (float) box.maxZ}; + }; + } + + public static float[] modUV(float[] uvs) { + uvs[0] = (int) uvs[0] & 0xf; + uvs[1] = (int) uvs[1] & 0xf; + uvs[2] = (((int) uvs[2] - 1) & 0xf) + 1; + uvs[3] = (((int) uvs[3] - 1) & 0xf) + 1; + return uvs; + } + + public static Vector3f[] aabbLimits(AABB aabb) { + return new Vector3f[]{ + new Vector3f((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ), + new Vector3f((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ), + }; + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + if (state == null) return; + + int coreRadius = getRadius(state); + + if (coreRadius <= BranchBlock.MAX_RADIUS) { + super.emitBlockQuads(blockView, state, pos, randomSupplier, context); + return; + } + + coreRadius = Mth.clamp(coreRadius, 9, 24); + + int[] connections = new int[]{0, 0, 0, 0, 0, 0}; + int twigRadius = 1; + + if (state.getBlock() instanceof BranchBlock branchBlock) { + connections = branchBlock.getConnectionData(blockView, pos, state).getAllRadii(); + twigRadius = branchBlock.getFamily().getPrimaryThickness(); + } + + var emitter = context.getEmitter(); + + boolean branchesAround = connections[2] + connections[3] + connections[4] + connections[5] != 0; + + int radiusIndex = coreRadius - 9; + if (radiusIndex < 0 || radiusIndex >= trunksBarkQuads.length) return; + + for (Direction face : Direction.values()) { + List barkQuads = trunksBarkQuads[radiusIndex]; + if (barkQuads != null) { + for (BakedQuad quad : barkQuads) { + if (quad.getDirection() == face) { + emitter.fromVanilla(quad, null, face); + emitter.emit(); + } + } + } + + if (face == Direction.UP || face == Direction.DOWN) { + if (connections[face.get3DDataValue()] < twigRadius && !branchesAround) { + List ringQuads = trunksTopRingsQuads[radiusIndex]; + if (ringQuads != null) { + for (BakedQuad quad : ringQuads) { + if (quad.getDirection() == face) { + emitter.fromVanilla(quad, null, face); + emitter.emit(); + } + } + } + } else if (connections[face.get3DDataValue()] < coreRadius) { + List topBarkQuads = trunksTopBarkQuads[radiusIndex]; + if (topBarkQuads != null) { + for (BakedQuad quad : topBarkQuads) { + if (quad.getDirection() == face) { + emitter.fromVanilla(quad, null, face); + emitter.emit(); + } + } + } + } + } + } + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricClientHelper.java b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricClientHelper.java new file mode 100644 index 000000000..eb6690304 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricClientHelper.java @@ -0,0 +1,34 @@ +package com.dtteam.dynamictrees.platform; + +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.entity.FallingTreeEntity; +import com.dtteam.dynamictrees.model.FallingTreeEntityModel; +import com.dtteam.dynamictrees.model.FallingTreeEntityModelFabric; +import com.dtteam.dynamictrees.platform.services.IClientHelper; +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.renderer.texture.SpriteContents; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +public class FabricClientHelper implements IClientHelper { + + @Override + public int getPixelRGBA(TextureAtlasSprite sprite, int x, int y) { + try { + SpriteContents contents = sprite.contents(); + NativeImage image = contents.originalImage; + if (image != null) { + return image.getPixelRGBA(x, y); + } + return 0; + } catch (Exception e) { + DynamicTrees.LOG.warn("Failed to get pixel from sprite: {}", e.getMessage()); + return 0; + } + } + + @Override + public FallingTreeEntityModel newFallingTreeEntityModel(FallingTreeEntity entity) { + return new FallingTreeEntityModelFabric(entity); + } + +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricConfigHelper.java b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricConfigHelper.java index 5b3523467..3fba475d4 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricConfigHelper.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricConfigHelper.java @@ -11,69 +11,48 @@ public class FabricConfigHelper implements IConfigHelper { - private T getConfig(String config, Class tClass){ - if (!DTConfigs.CONFIG.containsConfig(config)){ - DynamicTrees.LOG.error("Failed to get configuration \"{}\" of {} as it does not exist.", config, tClass); - } - Pair, ?> def = DTConfigs.getDefaultValue(config); - if (!tClass.equals(def.getFirst())) { - DynamicTrees.LOG.error("Failed to get configuration \"{}\" of {} as it is of {} instead.", config, tClass, def.getFirst()); - return null; - } - return tClass.cast(def.getSecond()); + private T getConfig(String config, Class tClass) { + return null; } @Override public Boolean getBoolConfig(String config){ - return DTConfigs.CONFIG.getOrDefault(config, getConfig(config, Boolean.class)); + return getConfig(config, Boolean.class); } @Override public Integer getIntConfig(String config){ - return DTConfigs.CONFIG.getOrDefault(config, getConfig(config, Integer.class)); + return getConfig(config, Integer.class); } @Override public Double getDoubleConfig(String config){ - return DTConfigs.CONFIG.getOrDefault(config, getConfig(config, Double.class)); + return getConfig(config, Double.class); } @Override public String getStringConfig(String config){ - return DTConfigs.CONFIG.getOrDefault(config, getConfig(config, String.class)); + return getConfig(config, String.class); } - @Override public > T getEnumConfig(String config, Class tClass) { - String value = getStringConfig(config); - return Enum.valueOf(tClass, value.toUpperCase(Locale.ENGLISH)); + return getConfig(config, tClass); } - + @SuppressWarnings("unchecked") @Override public List getStringListConfig(String config){ - String array = getStringConfig(config); - if (array == null) return new ArrayList<>(); - array = array.trim().substring(1, array.length()-1); //remove [ and ] - String[] values = array.split(","); - List stringList = new ArrayList<>(); - for (String val : values) { //remove " and " - if (val.isEmpty()) continue; - val = val.trim(); - if (val.charAt(0) == '\"') val = val.substring(1, val.length()-1).trim(); - stringList.add(val); - } - return stringList; + return getConfig(config, List.class); } @Override public boolean isServerConfigLoaded() { - return DTConfigs.isLoaded; + return DTConfigs.SERVER_CONFIG.isLoaded(); } @Override public boolean isCommonConfigLoaded() { - return DTConfigs.isLoaded; + return DTConfigs.COMMON_CONFIG.isLoaded(); } @Override public boolean isClientConfigLoaded() { - return DTConfigs.isLoaded; + return DTConfigs.CLIENT_CONFIG.isLoaded(); } } \ No newline at end of file diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricEventHelper.java b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricEventHelper.java index 172b231b7..762e9fde7 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricEventHelper.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricEventHelper.java @@ -23,42 +23,38 @@ public class FabricEventHelper implements IEventHelper { @Override public > void postRegistryEvent(AbstractRegistry registry) { - //RegistryEvent.EVENT.invoker(). } @Override public > void postTypedRegistryEvent(TypedRegistry registry) { - } @Override - public void postAddResourceLoadersEvent(TreeResourceManager resourceManager) { + public void postAddResourceLoadersEventPre(TreeResourceManager resourceManager) { + } + @Override + public void postAddResourceLoadersEventPost(TreeResourceManager resourceManager) { } @Override public void postJsonDeserializerRegistryEvent() { - } @Override public void postApplierEvent(StagedApplierResourceLoader.ApplierStage stage, PropertyAppliers appliers, String identifier) { - } @Override public void postBiomeEntryApplierEvent(JsonPropertyAppliers appliers, String identifier) { - } @Override public void postCancellationApplierEvent(JsonPropertyAppliers appliers, String identifier) { - } @Override public void postSpeciesPostGenerationEvent(PostGenerationContext context) { - } @Override @@ -68,27 +64,26 @@ public boolean postTransitionSaplingToTreeEvent(Species species, Level level, Bl @Override public boolean canCropGrow(Level level, BlockPos pos, BlockState state, boolean doGrow) { - return false; + return doGrow; } @Override public void cropGrowPost(Level level, BlockPos pos, BlockState state) { - } @Override public Species.BiomeSuitabilityEventResult postBiomeSuitabilityEvent(Level level, Biome biome, Species species, BlockPos pos) { - return null; + return new Species.BiomeSuitabilityEventResult(false, 0.0f); } @Override public Seed.VoluntaryPlantEventResult postSeedVoluntaryPlantEvent(ItemEntity entityItem, Species species, BlockPos pos, boolean willPlant) { - return new Seed.VoluntaryPlantEventResult(false, false); + return new Seed.VoluntaryPlantEventResult(false, willPlant); } @Override public PoissonDiscProvider postPoissonDiscProviderCreateEvent(LevelAccessor level, PoissonDiscProvider poissonDiscProvider) { - return null; + return poissonDiscProvider; } } diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricInteractionHelper.java b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricInteractionHelper.java index 64977db76..ed3a3a0a7 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricInteractionHelper.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricInteractionHelper.java @@ -1,5 +1,9 @@ package com.dtteam.dynamictrees.platform; +import com.dtteam.dynamictrees.block.branch.BranchBlock; +import com.dtteam.dynamictrees.block.branch.TrunkShellBlock; +import com.dtteam.dynamictrees.block.sapling.PottedSaplingBlock; +import com.dtteam.dynamictrees.block.soil.SoilBlock; import com.dtteam.dynamictrees.item.Seed; import com.dtteam.dynamictrees.platform.services.IInteractionHelper; import net.minecraft.core.BlockPos; @@ -8,6 +12,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.FluidState; @@ -32,6 +37,16 @@ public int setSeedItemEntityLifespan(ItemEntity entityItem, Seed seed) { @Override 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; } } diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricMiscHelper.java b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricMiscHelper.java index 1e1637815..c62d584e1 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricMiscHelper.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/platform/FabricMiscHelper.java @@ -1,25 +1,25 @@ package com.dtteam.dynamictrees.platform; -import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.model.FallingTreeEntityModel; +import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.platform.services.IMiscHelper; +import com.dtteam.dynamictrees.tree.species.Species; import com.dtteam.dynamictrees.worldgen.IDTBiomeHolderSet; import com.dtteam.dynamictrees.worldgen.holderset.DTBiomeHolderSet; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; public class FabricMiscHelper implements IMiscHelper { - @Override - public int getPixelRGBA(TextureAtlasSprite sprite, int x, int y) { - return 0; + public static void debugSpeciesRegistry() { + DynamicTrees.LOG.info("=== Species Registry Debug ==="); + DynamicTrees.LOG.info("Total species count: {}", Species.REGISTRY.getAll().size()); + Species cherry = Species.REGISTRY.get(DynamicTrees.location("cherry")); + DynamicTrees.LOG.info("Cherry species: {} (valid: {})", cherry, cherry != null && cherry.isValid()); + Species oak = Species.REGISTRY.get(DynamicTrees.location("oak")); + DynamicTrees.LOG.info("Oak species: {} (valid: {})", oak, oak != null && oak.isValid()); + DynamicTrees.LOG.info("=== End Species Registry Debug ==="); } - @Override - public FallingTreeEntityModel newFallingTreeEntityModel(FallingTreeEntity entity) { - return new FallingTreeEntityModel(entity); - } @Override public boolean isLevelRestoringBlockSnapshots(Level level) { diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java b/fabric/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java index 46c17c2ce..0e14f793e 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java @@ -1,8 +1,7 @@ package com.dtteam.dynamictrees.recipe; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.item.DendroPotion; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.registry.DTRegistries; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponents; @@ -35,12 +34,10 @@ public static boolean isIngredient(ItemStack stack){ } public static List getAllDendroRecipes() { - //If they have already been processed then don't process them again if (!brewingRecipes.isEmpty()) return brewingRecipes; - //Biochar potion ItemStack biocharIngredient = new ItemStack(Items.CHARCOAL); - final ItemStack baseStack = setPotion(new ItemStack(Items.POTION), Services.CONFIG.getStringConfig(IConfigHelper.BIOCHAR_BREWING_BASE)); + final ItemStack baseStack = setPotion(new ItemStack(Items.POTION), DTConfigs.COMMON.biocharBrewingBase.get()); brewingRecipes.add(getRecipe(baseStack, biocharIngredient, getPotionStack(DendroPotion.DendroPotionType.BIOCHAR))); ingredients.add(biocharIngredient); diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/registry/FabricRegistryHandler.java b/fabric/src/main/java/com/dtteam/dynamictrees/registry/FabricRegistryHandler.java index 40bd52824..659c3ff68 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/registry/FabricRegistryHandler.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/registry/FabricRegistryHandler.java @@ -1,6 +1,9 @@ package com.dtteam.dynamictrees.registry; -import com.dtteam.dynamictrees.api.registry.RegistryHandler; +import com.dtteam.dynamictrees.api.registry.*; +import net.minecraft.core.*; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; @@ -31,6 +34,7 @@ public FabricRegistryHandler() { public FabricRegistryHandler(String modId) { super(ResourceLocation.fromNamespaceAndPath(modId, modId)); + RegistryHandler.REGISTRY.register(this); } /** @@ -60,22 +64,34 @@ private boolean warnIfInvalid(final String type, final ResourceLocation registry @Override public @Nullable Supplier getBlock(ResourceLocation registryName) { - return null; + Block block = BuiltInRegistries.BLOCK.get(registryName); + return () -> block; } @Override public @Nullable Supplier getItem(ResourceLocation registryName) { - return null; + Item item = BuiltInRegistries.ITEM.get(registryName); + return () -> item; } @Override + @SuppressWarnings("unchecked") public Supplier putBlock(ResourceLocation registryName, Supplier blockSup) { - return null; + if (this.warnIfInvalid("Block", registryName)) { + return (Supplier) getBlock(registryName); + } + T block = Registry.register(BuiltInRegistries.BLOCK, registryName, blockSup.get()); + return () -> block; } @Override + @SuppressWarnings("unchecked") public Supplier putItem(ResourceLocation registryName, Supplier itemSup) { - return null; + if (this.warnIfInvalid("Item", registryName)) { + return (Supplier) getItem(registryName); + } + T item = Registry.register(BuiltInRegistries.ITEM, registryName, itemSup.get()); + return () -> item; } public static class RegisterEventHandler { diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/treepack/FabricModFileContainer.java b/fabric/src/main/java/com/dtteam/dynamictrees/treepack/FabricModFileContainer.java index 257139ac5..c102beb30 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/treepack/FabricModFileContainer.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/treepack/FabricModFileContainer.java @@ -2,7 +2,9 @@ import net.fabricmc.loader.api.ModContainer; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Optional; public class FabricModFileContainer extends ModFileContainer { @@ -15,7 +17,14 @@ public FabricModFileContainer(ModContainer modContainer) { @Override public Optional findResource(String strings) { - return modContainer.findPath(strings); + List rootPaths = modContainer.getRootPaths(); + for (Path rootPath : rootPaths) { + Path resourcePath = rootPath.resolve(strings); + if (Files.exists(resourcePath)) { + return Optional.of(resourcePath); + } + } + return Optional.empty(); } @Override diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/FabricBiomeModifications.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/FabricBiomeModifications.java new file mode 100644 index 000000000..e6a943bb7 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/FabricBiomeModifications.java @@ -0,0 +1,124 @@ +package com.dtteam.dynamictrees.worldgen; + +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.api.worldgen.BiomePropertySelectors; +import com.dtteam.dynamictrees.api.worldgen.FeatureCanceller; +import com.dtteam.dynamictrees.config.DTConfigs; +import com.dtteam.dynamictrees.registry.DTRegistries; +import com.dtteam.dynamictrees.worldgen.featurecancellation.FeatureCancellationRegistry; +import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext; +import net.fabricmc.fabric.api.biome.v1.BiomeModifications; +import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext; +import net.fabricmc.fabric.api.biome.v1.BiomeSelectors; +import net.fabricmc.fabric.api.biome.v1.ModificationPhase; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class FabricBiomeModifications { + + private static final ResourceLocation REMOVE_TREES_ID = DynamicTrees.location("remove_vanilla_trees"); + private static final ResourceLocation ADD_TREES_ID = DynamicTrees.location("add_dynamic_trees"); + public static final TagKey FEATURE_CANCELLER_EXCLUSIONS_KEY = TagKey.create( + net.minecraft.core.registries.Registries.PLACED_FEATURE, + DynamicTrees.location("feature_canceller_exclusions")); + + public static void register() { + BiomeModifications.create(REMOVE_TREES_ID) + .add(ModificationPhase.REMOVALS, BiomeSelectors.all(), (selectionContext, modificationContext) -> { + if(DTConfigs.SERVER_CONFIG.isLoaded()) { + if (!DTConfigs.SERVER.worldGen.get()) { + return; + } + } + removeVanillaTrees(selectionContext, modificationContext); + }); + + BiomeModifications.create(ADD_TREES_ID) + .add(ModificationPhase.ADDITIONS, BiomeSelectors.all(), (selectionContext, modificationContext) -> { + if(DTConfigs.SERVER_CONFIG.isLoaded()) { + if (!DTConfigs.SERVER.worldGen.get()) { + return; + } + } + addDynamicTrees(modificationContext); + }); + } + + private static void removeVanillaTrees(BiomeSelectionContext selectionContext, BiomeModificationContext context) { + ResourceKey biomeKey = selectionContext.getBiomeKey(); + + BiomePropertySelectors.NormalFeatureCancellation featureCancellations = new BiomePropertySelectors.NormalFeatureCancellation(); + + for (FeatureCancellationRegistry.Entry entry : FeatureCancellationRegistry.getCancellations()) { + if (entry.biomes().containsKey(biomeKey)) { + if (entry.operation() == BiomeDatabase.Operation.REPLACE) { + featureCancellations.reset(); + } + featureCancellations.addFrom(entry.cancellations()); + } + } + + List> featuresToRemove = new ArrayList<>(); + + for (GenerationStep.Decoration stage : featureCancellations.getDecorationSteps()) { + int stageIndex = stage.ordinal(); + List> features = selectionContext.getBiomeRegistryEntry() + .value() + .getGenerationSettings() + .features(); + + if (stageIndex >= features.size()) { + continue; + } + + HolderSet stageFeatures = features.get(stageIndex); + + for (Holder placedFeatureHolder : stageFeatures) { + if (placedFeatureHolder.is(FEATURE_CANCELLER_EXCLUSIONS_KEY)) { + continue; + } + + PlacedFeature placedFeature = placedFeatureHolder.value(); + + boolean shouldCancel = placedFeature.getFeatures().anyMatch(configuredFeature -> { + for (FeatureCanceller featureCanceller : featureCancellations.getCancellers()) { + if (featureCanceller.shouldCancel(configuredFeature, featureCancellations)) { + return true; + } + } + return false; + }); + + if (shouldCancel) { + Optional> keyOpt = selectionContext.getPlacedFeatureKey(placedFeature); + keyOpt.ifPresent(featuresToRemove::add); + } + } + } + + for (ResourceKey key : featuresToRemove) { + context.getGenerationSettings().removeFeature(key); + } + } + + private static void addDynamicTrees(BiomeModificationContext context) { + context.getGenerationSettings().addFeature( + GenerationStep.Decoration.VEGETAL_DECORATION, + DTRegistries.CAVE_ROOTED_TREE_PLACED_FEATURE + ); + context.getGenerationSettings().addFeature( + GenerationStep.Decoration.VEGETAL_DECORATION, + DTRegistries.DYNAMIC_TREE_PLACED_FEATURE + ); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DTBiomeHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DTBiomeHolderSet.java index 7efdc8791..b108b8ad7 100644 --- a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DTBiomeHolderSet.java +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DTBiomeHolderSet.java @@ -12,52 +12,94 @@ import net.minecraft.world.level.biome.Biome; import org.jetbrains.annotations.NotNull; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.function.Supplier; import java.util.stream.Stream; public class DTBiomeHolderSet implements IDTBiomeHolderSet { + private final List> includeComponents = new ArrayList<>(); + private final List> excludeComponents = new ArrayList<>(); + + private Set> getSet() { + Set> tempSet = null; + for (HolderSet component : this.includeComponents) { + if (tempSet == null) { + tempSet = new HashSet<>(); + component.forEach(tempSet::add); + } else { + Set> componentSet = new HashSet<>(); + component.forEach(componentSet::add); + tempSet.retainAll(componentSet); + } + } + if (tempSet == null) { + tempSet = new HashSet<>(); + } + for (HolderSet component : this.excludeComponents) { + component.forEach(tempSet::remove); + } + return tempSet; + } + @Override public boolean containsKey(ResourceKey biomeKey) { + Set> currentSet = this.getSet(); + for (Holder holder : currentSet) { + Optional> key = holder.unwrapKey(); + if (key.isPresent() && key.get().equals(biomeKey)) { + return true; + } + } return false; } @Override public Stream> stream() { - return Stream.empty(); + return this.getSet().stream(); } @Override public int size() { - return 0; + return this.getSet().size(); } @Override public Either, List>> unwrap() { - return null; + return Either.right(new ArrayList<>(this.getSet())); } @Override public Optional> getRandomElement(RandomSource random) { - return Optional.empty(); + Set> set = this.getSet(); + if (set.isEmpty()) { + return Optional.empty(); + } + int index = random.nextInt(set.size()); + Iterator> iterator = set.iterator(); + for (int i = 0; i < index; i++) { + iterator.next(); + } + return Optional.of(iterator.next()); } @Override public Holder get(int index) { - return null; + Iterator> iterator = this.getSet().iterator(); + for (int i = 0; i < index; i++) { + iterator.next(); + } + return iterator.next(); } @Override public boolean contains(Holder holder) { - return false; + return this.getSet().contains(holder); } @Override public boolean canSerializeIn(HolderOwner owner) { - return false; + return true; } @Override @@ -67,47 +109,50 @@ public Optional> unwrapKey() { @Override public List> getIncludeComponents() { - return List.of(); + return this.includeComponents; } @Override public List> getExcludeComponents() { - return List.of(); + return this.excludeComponents; } @Override - public void addHolderSet(List> components, HolderSet holderSetSupplier) { - + public void addHolderSet(List> components, HolderSet holderSet) { + components.add(holderSet); } @Override public void addDelayedHolderSet(List> components, Supplier> holderSetSupplier) { - + components.add(new DelayedHolderSet<>(holderSetSupplier)); } @Override public void addNameRegexMatch(List> components, Supplier> registryLookup, String regex) { - + Supplier> sup = () -> new NameRegexMatchHolderSet<>(registryLookup.get(), regex); + addDelayedHolderSet(components, sup); } @Override public void addTagsRegexMatch(List> components, Supplier> registryLookup, String regex) { - + Supplier> sup = () -> new TagsRegexMatchHolderSet<>(registryLookup.get(), regex); + addDelayedHolderSet(components, sup); } @Override public void addOr(List> components, List> values) { - + addHolderSet(components, new OrHolderSet<>(values)); } @Override public void clear() { - + this.includeComponents.clear(); + this.excludeComponents.clear(); } @NotNull @Override public Iterator> iterator() { - return null; + return this.getSet().iterator(); } } \ No newline at end of file diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DelayedHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DelayedHolderSet.java new file mode 100644 index 000000000..c70ab944e --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/DelayedHolderSet.java @@ -0,0 +1,81 @@ +package com.dtteam.dynamictrees.worldgen.holderset; + +import com.mojang.datafixers.util.Either; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderOwner; +import net.minecraft.core.HolderSet; +import net.minecraft.tags.TagKey; +import net.minecraft.util.RandomSource; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class DelayedHolderSet implements HolderSet { + private final Supplier> holderSetSupplier; + + public DelayedHolderSet(Supplier> holderSetSupplier) { + this.holderSetSupplier = holderSetSupplier; + } + + @Override + public Stream> stream() { + return this.holderSetSupplier.get().stream(); + } + + @Override + public int size() { + return this.holderSetSupplier.get().size(); + } + + @Override + public Either, List>> unwrap() { + return this.holderSetSupplier.get().unwrap(); + } + + @Override + public Optional> getRandomElement(RandomSource random) { + return this.holderSetSupplier.get().getRandomElement(random); + } + + @Override + public Holder get(int index) { + return this.holderSetSupplier.get().get(index); + } + + @Override + public boolean contains(Holder holder) { + return this.holderSetSupplier.get().contains(holder); + } + + @Override + public boolean canSerializeIn(HolderOwner owner) { + return this.holderSetSupplier.get().canSerializeIn(owner); + } + + @Override + public Optional> unwrapKey() { + return this.holderSetSupplier.get().unwrapKey(); + } + + @NotNull + @Override + public Iterator> iterator() { + return this.holderSetSupplier.get().iterator(); + } + + @Override + public void forEach(Consumer> action) { + this.holderSetSupplier.get().forEach(action); + } + + @Override + public Spliterator> spliterator() { + return this.holderSetSupplier.get().spliterator(); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/NameRegexMatchHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/NameRegexMatchHolderSet.java new file mode 100644 index 000000000..f0c897065 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/NameRegexMatchHolderSet.java @@ -0,0 +1,18 @@ +package com.dtteam.dynamictrees.worldgen.holderset; + +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; + +import java.util.stream.Stream; + +public class NameRegexMatchHolderSet extends RegexMatchHolderSet { + + public NameRegexMatchHolderSet(HolderLookup.RegistryLookup registryLookup, String regex) { + super(registryLookup, regex); + } + + @Override + protected Stream getInput(Holder holder) { + return holder.unwrapKey().stream().map(key -> key.location().toString()); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/OrHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/OrHolderSet.java new file mode 100644 index 000000000..279f2d5db --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/OrHolderSet.java @@ -0,0 +1,27 @@ +package com.dtteam.dynamictrees.worldgen.holderset; + +import net.minecraft.core.Holder; +import net.minecraft.core.HolderOwner; +import net.minecraft.core.HolderSet; + +import java.util.List; +import java.util.stream.Stream; + +public class OrHolderSet extends StreamBackedHolderSet { + + private final List> values; + + public OrHolderSet(List> values) { + this.values = values; + } + + @Override + public Stream> stream() { + return this.values.stream().flatMap(HolderSet::stream).distinct(); + } + + @Override + public boolean canSerializeIn(HolderOwner owner) { + return this.values.stream().allMatch(set -> set.canSerializeIn(owner)); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/RegexMatchHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/RegexMatchHolderSet.java new file mode 100644 index 000000000..eefc08c7c --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/RegexMatchHolderSet.java @@ -0,0 +1,49 @@ +package com.dtteam.dynamictrees.worldgen.holderset; + +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.HolderOwner; + +import java.util.regex.Pattern; +import java.util.stream.Stream; + +public abstract class RegexMatchHolderSet extends StreamBackedHolderSet { + + private final HolderLookup.RegistryLookup registryLookup; + private final String regex; + private Pattern pattern; + + public RegexMatchHolderSet(HolderLookup.RegistryLookup registryLookup, String regex) { + this.registryLookup = registryLookup; + this.regex = regex; + } + + public final HolderLookup.RegistryLookup registryLookup() { + return this.registryLookup; + } + + public final String regex() { + return this.regex; + } + + private Pattern getPattern() { + if (this.pattern == null) { + this.pattern = Pattern.compile(this.regex); + } + return this.pattern; + } + + @SuppressWarnings("unchecked") + @Override + public Stream> stream() { + return (Stream>) (Stream) this.registryLookup.listElements() + .filter(holder -> this.getInput(holder).anyMatch(input -> this.getPattern().matcher(input).matches())); + } + + @Override + public boolean canSerializeIn(HolderOwner owner) { + return this.registryLookup.canSerializeIn(owner); + } + + protected abstract Stream getInput(Holder holder); +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/StreamBackedHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/StreamBackedHolderSet.java new file mode 100644 index 000000000..a4b7ad1e0 --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/StreamBackedHolderSet.java @@ -0,0 +1,61 @@ +package com.dtteam.dynamictrees.worldgen.holderset; + +import com.mojang.datafixers.util.Either; +import net.minecraft.Util; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.tags.TagKey; +import net.minecraft.util.RandomSource; + +import java.util.*; +import java.util.stream.Collectors; + +public abstract class StreamBackedHolderSet implements HolderSet { + public List> contents() { + return this.stream().collect(Collectors.toList()); + } + + public Set> contentsSet() { + return this.stream().collect(Collectors.toSet()); + } + + @Override + public int size() { + return this.contents().size(); + } + + @Override + public Spliterator> spliterator() { + return this.stream().spliterator(); + } + + @Override + public Iterator> iterator() { + return this.stream().iterator(); + } + + @Override + public Optional> getRandomElement(RandomSource random) { + return Util.getRandomSafe(this.contents(), random); + } + + @Override + public Holder get(int index) { + return this.contents().get(index); + } + + @Override + public Either, List>> unwrap() { + return Either.right(this.contents()); + } + + @Override + public boolean contains(Holder holder) { + return this.stream().anyMatch(h -> Objects.equals(h, holder)); + } + + @Override + public Optional> unwrapKey() { + return Optional.empty(); + } +} diff --git a/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/TagsRegexMatchHolderSet.java b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/TagsRegexMatchHolderSet.java new file mode 100644 index 000000000..8dbc0cc2c --- /dev/null +++ b/fabric/src/main/java/com/dtteam/dynamictrees/worldgen/holderset/TagsRegexMatchHolderSet.java @@ -0,0 +1,18 @@ +package com.dtteam.dynamictrees.worldgen.holderset; + +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; + +import java.util.stream.Stream; + +public class TagsRegexMatchHolderSet extends RegexMatchHolderSet { + + public TagsRegexMatchHolderSet(HolderLookup.RegistryLookup registryLookup, String regex) { + super(registryLookup, regex); + } + + @Override + protected Stream getInput(Holder holder) { + return holder.tags().map(tagKey -> tagKey.location().toString()); + } +} diff --git a/fabric/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper b/fabric/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper new file mode 100644 index 000000000..9c4dd1730 --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper @@ -0,0 +1 @@ +com.dtteam.dynamictrees.platform.FabricClientHelper diff --git a/fabric/src/main/resources/dynamictrees.fabric.mixins.json b/fabric/src/main/resources/dynamictrees.fabric.mixins.json index bf37b7228..71eeb9a81 100644 --- a/fabric/src/main/resources/dynamictrees.fabric.mixins.json +++ b/fabric/src/main/resources/dynamictrees.fabric.mixins.json @@ -7,10 +7,14 @@ "mixins": [ "MixinBrewingStandBlockEntity", "MixinBrewingStandMenu", + "MixinBushBlock", "MixinChunkSerializer", - "MixinPotionBrewing" + "MixinMinecraftServer", + "MixinPotionBrewing", + "MixinSaplingBlock" + ], + "client": [ ], - "client": [], "server": [], "injectors": { "defaultRequire": 1 diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 94900879e..f43870697 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -1,36 +1,40 @@ { - "schemaVersion": 1, - "id": "${mod_id}", - "version": "${version}", - "name": "${mod_name}", - "description": "${description}", - "authors": [ - "${mod_author}" + "schemaVersion": 1, + "id": "${mod_id}", + "version": "${version}", + "name": "${mod_name}", + "description": "${description}", + "authors": [ + "${mod_author}" + ], + "contact": { + "homepage": "https://www.curseforge.com/minecraft/mc-mods/dynamictrees", + "sources": "https://github.com/DynamicTreesTeam/DynamicTrees" + }, + "license": "${license}", + "icon": "${mod_id}.png", + "environment": "*", + "accessWidener": "META-INF/${mod_id}.accesswidener", + "entrypoints": { + "main": [ + "com.dtteam.dynamictrees.DynamicTreesFabric" ], - "contact": { - "homepage": "https://fabricmc.net/", - "sources": "https://github.com/FabricMC/fabric-example-mod" - }, - "license": "${license}", - "icon": "${mod_id}.png", - "environment": "*", - "entrypoints": { - "main": [ - "com.dtteam.dynamictrees.DynamicTreesFabric" - ] - }, - "mixins": [ - "${mod_id}.mixins.json", - "${mod_id}.fabric.mixins.json" - ], - "depends": { - "fabricloader": ">=${fabric_loader_version}", - "fabric-api": "*", - "minecraft": "${minecraft_version}", - "java": ">=${java_version}" - }, - "suggests": { - "another-mod": "*" - } + "client": [ + "com.dtteam.dynamictrees.DynamicTreesFabricClient" + ] + }, + "mixins": [ + "${mod_id}.mixins.json", + "${mod_id}.fabric.mixins.json" + ], + "depends": { + "fabricloader": ">=${fabric_loader_version}", + "fabric-api": "*", + "minecraft": "${minecraft_version}", + "java": ">=${java_version}" + }, + "suggests": { + "dynamictreesplus": "*" + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ae4a04331..9cea40597 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,8 +25,8 @@ parchment_version=2024.11.10 java_version=21 # Fabric -fabric_version=0.109.0+1.21.1 -fabric_loader_version=0.16.9 +fabric_version=0.116.8+1.21.1 +fabric_loader_version=0.18.4 # Forge // Unused forge_version=52.0.28 @@ -39,3 +39,4 @@ neoforge_loader_version_range=[4,) # Gradle org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false +forge_config_api_port_version=21.1.6 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 94113f200..ca025c83a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 70abeb6ba..a76aa6e2b 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -107,13 +107,13 @@ publishMods { curseforge { projectId = "252818" projectSlug = "dynamictrees" // Required for discord webhook - accessToken = curseApiKey ?: System.getenv("CURSEFORGE_API_KEY") +// accessToken = curseApiKey ?: System.getenv("CURSEFORGE_API_KEY") minecraftVersions.add("1.21.1") optional("dynamictreesplus") } modrinth { projectId = "vdjF5PL5" - accessToken = modrinthToken ?: System.getenv("MODRINTH_TOKEN") +// accessToken = modrinthToken ?: System.getenv("MODRINTH_TOKEN") minecraftVersions.add("1.21.1") optional("qaO9Dqpu") } diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/DynamicTreesNeoForge.java b/neoforge/src/main/java/com/dtteam/dynamictrees/DynamicTreesNeoForge.java index e96883692..bdf491a32 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/DynamicTreesNeoForge.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/DynamicTreesNeoForge.java @@ -4,7 +4,7 @@ import com.dtteam.dynamictrees.block.leaves.LeavesProperties; import com.dtteam.dynamictrees.block.soil.SoilProperties; import com.dtteam.dynamictrees.client.BlockColorMultipliers; -import com.dtteam.dynamictrees.config.DTConfigs; +import com.dtteam.dynamictrees.config.*; import com.dtteam.dynamictrees.data.GatherDataHelper; import com.dtteam.dynamictrees.data.generator.DTExtraLangGenerator; import com.dtteam.dynamictrees.data.generator.DataGenerators; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/config/DTConfigEvents.java b/neoforge/src/main/java/com/dtteam/dynamictrees/config/DTConfigEvents.java new file mode 100644 index 000000000..c1e418b5a --- /dev/null +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/config/DTConfigEvents.java @@ -0,0 +1,25 @@ +package com.dtteam.dynamictrees.config; + +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.event.handler.OptionalHandlers; +import com.dtteam.dynamictrees.systems.season.SeasonCompatibilityHandler; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.config.ModConfigEvent; + +@EventBusSubscriber(modid = DynamicTrees.MOD_ID, bus = EventBusSubscriber.Bus.MOD) +public class DTConfigEvents { + + @SubscribeEvent + public static void onLoad(final ModConfigEvent.Loading event) { + OptionalHandlers.configReload(); + SeasonCompatibilityHandler.reloadSeasonManager(); + } + + @SubscribeEvent + public static void onReload(final ModConfigEvent.Reloading event) { + OptionalHandlers.configReload(); + SeasonCompatibilityHandler.reloadSeasonManager(); + } + +} diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java b/neoforge/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java deleted file mode 100644 index b7691045d..000000000 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/config/DTConfigs.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.dtteam.dynamictrees.config; - -import com.dtteam.dynamictrees.DynamicTrees; -import com.dtteam.dynamictrees.block.branch.ThickBranchBlock; -import com.dtteam.dynamictrees.event.handler.OptionalHandlers; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; -import com.dtteam.dynamictrees.systems.season.SeasonCompatibilityHandler; -import com.dtteam.dynamictrees.tree.species.SwampSpecies; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.fml.event.config.ModConfigEvent; -import net.neoforged.fml.loading.FMLPaths; -import net.neoforged.neoforge.common.ModConfigSpec; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -@EventBusSubscriber(modid = DynamicTrees.MOD_ID, bus = EventBusSubscriber.Bus.MOD) -public class DTConfigs { - - public static final File CONFIG_DIRECTORY; - - public static final Map> CONFIGS = new HashMap<>(); - - public static final ModConfigSpec SERVER_CONFIG; - public static final ModConfigSpec COMMON_CONFIG; - public static final ModConfigSpec CLIENT_CONFIG; - - private static > T registerConfig (T config){ - CONFIGS.put(config.getPath().getLast(), config); - return config; - } - - static { - CONFIG_DIRECTORY = new File(FMLPaths.CONFIGDIR.get().toUri()); - - final ModConfigSpec.Builder SERVER_BUILDER = new ModConfigSpec.Builder(); - final ModConfigSpec.Builder COMMON_BUILDER = new ModConfigSpec.Builder(); - final ModConfigSpec.Builder CLIENT_BUILDER = new ModConfigSpec.Builder(); - - SERVER_BUILDER.comment("Seed Settings").push("seeds"); - registerConfig(SERVER_BUILDER.comment("The rate at which seeds drop from leaves."). - defineInRange(IConfigHelper.LEAVES_SEED_DROP_RATE, 1.0, 0.0, 64.0)); - registerConfig(SERVER_BUILDER.comment("The minimum chance for seed dropping from leaves when a seasonal mod is installed. 0 = during the off season seeds never drop from leaves, 1 = seeds will drop at maximum rate during the entire year. Can be fractional."). - defineInRange(IConfigHelper.MIN_SEASONAL_LEAVES_SEED_DROP_RATE, 0.15, 0.0, 1.0)); - registerConfig(SERVER_BUILDER.comment("The rate at which seeds voluntarily drop from branches"). - defineInRange(IConfigHelper.VOLUNTARY_SEED_DROP_RATE, 0.01, 0.0, 1.0)); - registerConfig(SERVER_BUILDER.comment("The minimum chance for seed dropping voluntarily when a seasonal mod is installed. 0 = during the off season seeds never drop voluntarily, 1 = seeds will drop at maximum rate during the entire year. Can be fractional."). - defineInRange(IConfigHelper.MIN_SEASONAL_VOLUNTARY_SEED_DROP_RATE, 0.0, 0.0, 1.0)); - registerConfig(SERVER_BUILDER.comment("The rate at which seeds voluntarily plant themselves in their ideal biomes"). - defineInRange(IConfigHelper.SEED_PLANT_RATE, 1f / 6f, 0.0, 1.0)); - registerConfig(SERVER_BUILDER.comment("Ticks before a seed in the world attempts to plant itself or despawn. 1200 = 1 minute"). - defineInRange(IConfigHelper.SEED_TIME_TO_LIVE, 1200, 0, 6000)); - registerConfig(SERVER_BUILDER.comment("If enabled then seeds will only voluntarily plant themselves in forest-like biomes."). - define(IConfigHelper.SEED_ONLY_FOREST, true)); - registerConfig(SERVER_BUILDER.comment("The minimum forestness that non-forest-like biomes can have. 0 = is not at all a forest, 1 = may as well be a forest. Can be fractional."). - defineInRange(IConfigHelper.SEED_MIN_FORESTNESS, 0.0, 0.0, 1.0)); - registerConfig(SERVER_BUILDER.comment("If enabled, fruit and pod production will be affected by the current biome's climate."). - define(IConfigHelper.CLIMATE_AFFECTS_FRUITS_AND_PODS, true)); - SERVER_BUILDER.pop(); - - SERVER_BUILDER.comment("Tree Settings").push("trees"); - registerConfig(SERVER_BUILDER.comment("Factor that multiplies the rate at which trees grow. Use at own risk"). - defineInRange(IConfigHelper.TREE_GROWTH_MULTIPLIER, 0.5f, 0, 16f)); - registerConfig(SERVER_BUILDER.comment("Factor that multiplies the wood returned from harvesting a tree. You cheat."). - defineInRange(IConfigHelper.TREE_HARVEST_MULTIPLIER, 1f, 0f, 128f)); - registerConfig(SERVER_BUILDER.comment("Maximum harvesting hardness that can be calculated. Regardless of tree thickness."). - defineInRange(IConfigHelper.MAX_TREE_HARDNESS, 20f, 1f, 200f)); - registerConfig(SERVER_BUILDER.comment("A multiplier of tree hardness. Higher values make trees slower to chop, lower values makes them faster to chop."). - defineInRange(IConfigHelper.TREE_HARDNESS_MULTIPLIER, 1, (1/128f), 32f)); - registerConfig(SERVER_BUILDER.comment("If enabled then sticks will be dropped for partial logs"). - define(IConfigHelper.DROP_STICKS, true)); - registerConfig(SERVER_BUILDER.comment("Scales the growth for the environment. 0.5f is nominal. 0.0 trees only grow in their native biome. 1.0 trees grow anywhere like they are in their native biome"). - defineInRange(IConfigHelper.SCALE_BIOME_GROWTH_RATE, 0.5f, 0.0f, 1.0f)); - registerConfig(SERVER_BUILDER.comment("The chance of a tree on depleted soil to die. 1/256(~0.004) averages to about 1 death every 16 minecraft days"). - defineInRange(IConfigHelper.DISEASE_CHANCE, 0.0f, 0.0f, 1.0f)); - registerConfig(SERVER_BUILDER.comment("The maximum radius of a branch that is allowed to postRot away. 8 = Full block size. 24 = Full 3x3 thick size. Set to 0 to prevent rotting"). - defineInRange(IConfigHelper.MAX_BRANCH_ROT_RADIUS, 7, 0, ThickBranchBlock.MAX_RADIUS_THICK)); - registerConfig(SERVER_BUILDER.comment("How much harder it is to destroy a rooty block compared to its non-rooty state"). - defineInRange(IConfigHelper.ROOTY_BLOCK_HARDNESS_MULTIPLIER, 40f, 0f, 128f)); - registerConfig(SERVER_BUILDER.comment("Options for how oak trees generate in swamps. ROOTED: Swamp oak trees will generate on shallow water with mangrove-like roots. SUNK: Swamp oak trees will generate on shallow water one block under the surface. DISABLED: Swamp oaks will not generate on water."). - defineEnum(IConfigHelper.SWAMP_OAKS_IN_WATER, SwampSpecies.WaterSurfaceGenerationState.ROOTED)); - registerConfig(SERVER_BUILDER.comment("The amount of growth pulses to send when bone meal is applied to a tree. Warning: setting values higher than 64 is not recommended other than for testing purposes. "). - defineInRange(IConfigHelper.BONE_MEAL_GROWTH_PULSES, 1, 1, 512)); - SERVER_BUILDER.pop(); - - SERVER_BUILDER.comment("Interaction Settings").push("interaction"); - registerConfig(SERVER_BUILDER.comment("If enabled all leaves will be passable. If the Passable Foliage mod is installed this config is overridden"). - define(IConfigHelper.IS_LEAVES_PASSABLE, false)); - registerConfig(SERVER_BUILDER.comment("If enabled player movement on leaves will not be enhanced"). - define(IConfigHelper.VANILLA_LEAVES_COLLISION, false)); - registerConfig(SERVER_BUILDER.comment("If enabled then thinner branches can be climbed"). - define(IConfigHelper.ENABLE_BRANCH_CLIMBING, true)); - registerConfig(SERVER_BUILDER.comment("If enabled players receive reduced fall damage on leaves at the expense of the block(s) destruction"). - define(IConfigHelper.ENABLE_CANOPY_CRASH, true)); - registerConfig(SERVER_BUILDER.comment("Damage dealt to the axe item when cutting a tree down. VANILLA: Standard 1 Damage. THICKNESS: By Branch/Trunk Thickness. VOLUME: By Tree Volume."). - defineEnum(IConfigHelper.AXE_DAMAGE_MODE, DynamicTrees.AxeDamage.THICKNESS)); - registerConfig(SERVER_BUILDER.comment("If enabled then trees will fall over when harvested"). - define(IConfigHelper.ENABLE_FALLING_TREES, true)); - registerConfig(SERVER_BUILDER.comment("If enabled then trees will harm living entities when falling"). - define(IConfigHelper.ENABLE_FALLING_TREE_DAMAGE, true)); - registerConfig(SERVER_BUILDER.comment("Multiplier for damage incurred by a falling tree"). - defineInRange(IConfigHelper.FALLING_TREE_DAMAGE_MULTIPLIER, 1.0, 0.0, 100.0)); - registerConfig(SERVER_BUILDER.comment("If enabled the Dirt Bucket will place a dirt block on right-click"). - define(IConfigHelper.DIRT_BUCKET_PLACES_DIRT, true)); - registerConfig(SERVER_BUILDER.comment("If enabled then improperly broken trees(not by an entity) will still drop wood."). - define(IConfigHelper.SLOPPY_BREAK_DROPS, false)); - registerConfig(SERVER_BUILDER.comment("The minimum radius a branch must have before its able to be stripped. 8 = Full block size. Set to 0 to disable stripping trees"). - defineInRange(IConfigHelper.MIN_RADIUS_FOR_STRIP, 6, 0, 24)); - registerConfig(SERVER_BUILDER.comment("If enabled, stripping a branch will decrease its radius by one"). - define(IConfigHelper.ENABLE_STRIP_RADIUS_REDUCTION, true)); - registerConfig(SERVER_BUILDER.comment("Sets the default for whether or not fruit growing from dynamic trees can be bone-mealed. Note that this is a default; it can be overridden by the individual fruit."). - define(IConfigHelper.CAN_BONE_MEAL_FRUIT, false)); - registerConfig(SERVER_BUILDER.comment("Sets the default for whether or not pods growing from dynamic trees can be bone-mealed. Note that this is a default; it can be overridden by the individual pod."). - define(IConfigHelper.CAN_BONE_MEAL_PODS, true)); - registerConfig(SERVER_BUILDER.comment("If enabled, dynamic sapling blocks will drop their seed when broken."). - define(IConfigHelper.DYNAMIC_SAPLING_DROPS, true)); - SERVER_BUILDER.pop(); - - COMMON_BUILDER.comment("Vanilla Trees Settings").push("vanilla"); - registerConfig(COMMON_BUILDER.comment("Right clicking with a vanilla sapling places a dynamic sapling instead."). - define(IConfigHelper.REPLACE_VANILLA_SAPLINGS, false)); - registerConfig(COMMON_BUILDER.comment("Crimson Fungus and Warped Fungus that sprout from nylium will be dynamic instead."). - define(IConfigHelper.REPLACE_NYLIUM_FUNGI, true)); - registerConfig(COMMON_BUILDER.comment("If enabled, cancels the non-dynamic trees that spawn with vanilla villages."). - define(IConfigHelper.CANCEL_VANILLA_VILLAGE_TREES, true)); - registerConfig(COMMON_BUILDER.comment("The maximum number of leaves blocks that will fling particles when a falling tree crashes into the ground. Higher values might have a performance impact."). - defineInRange(IConfigHelper.MAX_FALLING_TREE_LEAVES_PARTICLES, 400, 0, 4096)); - COMMON_BUILDER.pop(); - - SERVER_BUILDER.comment("World Generation Settings").push("world"); - registerConfig(SERVER_BUILDER.comment("Randomly generate podzol under select trees like spruce."). - define(IConfigHelper.GENERATE_PODZOL, true)); - registerConfig(SERVER_BUILDER.comment("World Generation produces Dynamic Trees instead of Vanilla trees."). - define(IConfigHelper.WORLD_GEN, true)); - registerConfig(SERVER_BUILDER.comment("Blacklist of dimension registry names for disabling Dynamic Tree worldgen"). - define(IConfigHelper.DIMENSION_BLACK_LIST, new ArrayList<>())); - SERVER_BUILDER.pop(); - - COMMON_BUILDER.comment("Miscellaneous Settings").push("misc"); - registerConfig(COMMON_BUILDER.comment("If enabled, dirt bucket recipes will be automatically generated.") - .define(IConfigHelper.GENERATE_DIRT_BUCKET_RECIPES, true)); - registerConfig(COMMON_BUILDER.comment("If enabled, seeds for mega species can be crafted with four regular seeds.") - .define(IConfigHelper.GENERATE_MEGA_SEED_RECIPE, false)); - registerConfig(COMMON_BUILDER.comment("The base potion the Biochar Base is brewed from. Minecraft potions use 'awkward'. If you change this, don't forget to update the patchouli manual page too.") - .define(IConfigHelper.BIOCHAR_BREWING_BASE, "minecraft:thick")); - COMMON_BUILDER.pop(); - - COMMON_BUILDER.comment("Mod Integration Settings").push("integration"); - registerConfig(COMMON_BUILDER.comment("The mod ID of preferred season mod. If a season provider for this mod ID is present, it will be used for integration with seasons. Set this to \"!\" to disable integration or \"*\" to accept the any integration (the first available).") - .define(IConfigHelper.PREFERRED_SEASON_MOD, SeasonCompatibilityHandler.ANY)); - registerConfig(COMMON_BUILDER.comment("If enabled, seed drop rates will be multiplied based on the current season (requires serene seasons)."). - define(IConfigHelper.ENABLE_SEASONAL_SEED_DROP, true)); - registerConfig(COMMON_BUILDER.comment("If enabled, growth rates will be multiplied based on the current season (requires serene seasons)."). - define(IConfigHelper.ENABLE_SEASONAL_GROWTH, true)); - registerConfig(COMMON_BUILDER.comment("If enabled, fruit production rates will be multiplied based on the current season (requires serene seasons)."). - define(IConfigHelper.ENABLE_SEASONAL_SEED_FRUIT_PRODUCTION, true)); - registerConfig(COMMON_BUILDER.comment("The seasonal offset of the wet season relative to summer. Tropical and arid climates use wet/dry seasons instead of regular summer/fall/winter/spring seasons. Tree growth and fruit production usually peak during the wet season. If set to 0.0 the wet season happens at the same time as summer. The default of 2.5 means it happens between fall and winter."). - defineInRange(IConfigHelper.WET_SEASON_OFFSET, 2.5, 0.0, 4.0)); - - COMMON_BUILDER.pop(); - -// CLIENT_BUILDER.comment("Visual Settings").push("visuals"); -// fancyThickRings = CLIENT_BUILDER.comment("Rings of thick trees are rendered using a texture created with an expanded tangram construction technique. Otherwise the ring texture is simply stretched"). -// define("fancyThickRings", true); -// CLIENT_BUILDER.pop(); - - SERVER_BUILDER.comment("Debug Settings").push("debug"); - registerConfig(SERVER_BUILDER.comment("Enable to mark tree spawn locations with concrete circles."). - define(IConfigHelper.DEBUG, false)); - SERVER_BUILDER.pop(); - - SERVER_CONFIG = SERVER_BUILDER.build(); - COMMON_CONFIG = COMMON_BUILDER.build(); - CLIENT_CONFIG = CLIENT_BUILDER.build(); - } - - @SubscribeEvent - public static void onLoad(final ModConfigEvent.Loading event) { - OptionalHandlers.configReload(); - SeasonCompatibilityHandler.reloadSeasonManager(); - } - - @SubscribeEvent - public static void onReload(final ModConfigEvent.Reloading event) { - OptionalHandlers.configReload(); - SeasonCompatibilityHandler.reloadSeasonManager(); - } - -} diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientGameEventHandler.java b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientGameEventHandler.java index 3e24618e1..8a144a324 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientGameEventHandler.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientGameEventHandler.java @@ -12,7 +12,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.*; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientModEventHandler.java b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientModEventHandler.java index 70466e9d2..67bca1337 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientModEventHandler.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/ClientModEventHandler.java @@ -32,8 +32,7 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.FoliageColor; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.*; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.client.event.EntityRenderersEvent; @@ -53,7 +52,7 @@ public class ClientModEventHandler { // COLOR HANDLING /////////////////////////////////////////// - @OnlyIn(Dist.CLIENT) + public static void discoverWoodColors() { final Function bakedTextureGetter = Minecraft.getInstance() @@ -72,7 +71,7 @@ public static void discoverWoodColors() { } } - @OnlyIn(Dist.CLIENT) + private static int getFaceColor(BlockState state, Direction face, Function textureGetter) { final BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); List quads = model.getQuads(state, face, RandomSource.create(), ModelData.EMPTY, null); @@ -94,14 +93,14 @@ private static int getFaceColor(BlockState state, Direction face, Function FoliageColor.getBirchColor()); BlockColorMultipliers.register("spruce", (state, level, pos, tintIndex) -> FoliageColor.getEvergreenColor()); } @SubscribeEvent - @OnlyIn(Dist.CLIENT) + public static void registerItemColorHandlersEvent(RegisterColorHandlersEvent.Item event){ // Register Potion Colorizer event.register(DTRegistries.DENDRO_POTION.get()::getColor, DTRegistries.DENDRO_POTION.get()); @@ -110,7 +109,7 @@ public static void registerItemColorHandlersEvent(RegisterColorHandlersEvent.Ite } @SubscribeEvent - @OnlyIn(Dist.CLIENT) + public static void registerBlockColorHandlersEvent(RegisterColorHandlersEvent.Block event){ final int white = 0xFFFFFFFF; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/CommonGameEventHandler.java b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/CommonGameEventHandler.java index 4f039cfea..1d6857565 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/CommonGameEventHandler.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/CommonGameEventHandler.java @@ -3,8 +3,7 @@ import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.api.worldgen.LevelContext; import com.dtteam.dynamictrees.command.DTCommand; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.recipe.DendroPotionRecipeHandler; import com.dtteam.dynamictrees.systems.FutureBreak; import com.dtteam.dynamictrees.systems.poissondisc.UniversalPoissonDiscProvider; @@ -65,7 +64,7 @@ public static void onLevelUnload(LevelEvent.Unload event) { @SubscribeEvent public static void onChunkDataLoad(ChunkDataEvent.Load event) { - if (!Services.CONFIG.getBoolConfig(IConfigHelper.WORLD_GEN)) return; + if (!DTConfigs.SERVER.worldGen.get()) return; final LevelAccessor level = event.getLevel(); @@ -82,7 +81,7 @@ public static void onChunkDataLoad(ChunkDataEvent.Load event) { @SubscribeEvent public static void onChunkDataSave(ChunkDataEvent.Save event) { - if (!Services.CONFIG.getBoolConfig(IConfigHelper.WORLD_GEN)) return; + if (!DTConfigs.SERVER.worldGen.get()) return; final LevelContext levelContext = LevelContext.create(event.getLevel()); final UniversalPoissonDiscProvider discProvider = DynamicTreeFeature.DISC_PROVIDER; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/OptionalHandlers.java b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/OptionalHandlers.java index e37ac213b..f3f3ec142 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/OptionalHandlers.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/event/handler/OptionalHandlers.java @@ -3,7 +3,6 @@ import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import net.neoforged.bus.api.IEventBus; import net.neoforged.neoforge.common.NeoForge; @@ -31,10 +30,10 @@ public static void registerHandlers() { /** * Registers or unregisters event handlers based on config changes. Called when the config is loaded or reloaded in - * {@link DTConfigs}. + * {@link com.dtteam.dynamictrees.config.DTConfigEvents}. */ public static void configReload() { - registerOrUnregister(VANILLA_SAPLING_EVENT_HANDLER, Services.CONFIG.getBoolConfig(IConfigHelper.REPLACE_VANILLA_SAPLINGS)); + registerOrUnregister(VANILLA_SAPLING_EVENT_HANDLER, DTConfigs.COMMON.replaceVanillaSaplings.get()); } /** diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/QuadManipulator.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/QuadManipulator.java index c17ddb70a..69fbf3f87 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/QuadManipulator.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/QuadManipulator.java @@ -12,8 +12,6 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.model.data.ModelData; import org.jetbrains.annotations.Nullable; @@ -22,7 +20,7 @@ import java.util.Optional; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class QuadManipulator { public static final Direction[] everyFace = {Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, null}; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BakedModelBlockPottedSapling.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BakedModelBlockPottedSapling.java index 674af24d2..e78c06131 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BakedModelBlockPottedSapling.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BakedModelBlockPottedSapling.java @@ -14,8 +14,6 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.ChunkRenderTypeSet; import net.neoforged.neoforge.client.model.IDynamicBakedModel; import net.neoforged.neoforge.client.model.data.ModelData; @@ -27,7 +25,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -@OnlyIn(Dist.CLIENT) + public class BakedModelBlockPottedSapling implements IDynamicBakedModel { protected BakedModel basePotModel; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java index 295117303..1d988f3cc 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicBranchBlockBakedModel.java @@ -20,8 +20,6 @@ import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.ChunkRenderTypeSet; import net.neoforged.neoforge.client.NamedRenderTypeManager; import net.neoforged.neoforge.client.model.IDynamicBakedModel; @@ -36,7 +34,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class BasicBranchBlockBakedModel implements IDynamicBakedModel { protected final BlockModel blockModel; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java index 814528feb..e2a8b949f 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/BasicRootsBlockBakedModel.java @@ -18,8 +18,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.model.IModelBuilder; import net.neoforged.neoforge.client.model.data.ModelData; import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext; @@ -30,7 +28,7 @@ import java.util.*; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class BasicRootsBlockBakedModel extends BasicBranchBlockBakedModel { private static final int MIN_RADIUS_FOR_CROSS = 4; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/LargePalmLeavesBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/LargePalmLeavesBakedModel.java index 0fdfba2aa..380b4fa38 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/LargePalmLeavesBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/LargePalmLeavesBakedModel.java @@ -9,14 +9,12 @@ import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import java.util.ArrayList; import java.util.List; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class LargePalmLeavesBakedModel extends PalmLeavesBakedModel { public static List INSTANCES = new ArrayList<>(); diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/MediumPalmLeavesBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/MediumPalmLeavesBakedModel.java index fa31545db..ebc84e5cb 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/MediumPalmLeavesBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/MediumPalmLeavesBakedModel.java @@ -9,14 +9,12 @@ import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import java.util.ArrayList; import java.util.List; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class MediumPalmLeavesBakedModel extends PalmLeavesBakedModel { public static List INSTANCES = new ArrayList<>(); diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/PalmLeavesBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/PalmLeavesBakedModel.java index 9f4994e12..bec492253 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/PalmLeavesBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/PalmLeavesBakedModel.java @@ -14,8 +14,6 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.ChunkRenderTypeSet; import net.neoforged.neoforge.client.RenderTypeGroup; import net.neoforged.neoforge.client.model.IDynamicBakedModel; @@ -26,7 +24,7 @@ import java.util.*; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public abstract class PalmLeavesBakedModel implements IDynamicBakedModel { protected RenderTypeGroup renderGroup = new RenderTypeGroup(RenderType.cutout(), RenderType.cutout()); diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SmallPalmLeavesBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SmallPalmLeavesBakedModel.java index 43d5e40a1..a8a6dcc9a 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SmallPalmLeavesBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SmallPalmLeavesBakedModel.java @@ -9,14 +9,12 @@ import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import java.util.ArrayList; import java.util.List; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class SmallPalmLeavesBakedModel extends PalmLeavesBakedModel { public static List INSTANCES = new ArrayList<>(); diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java index 9dd53a933..61eba1557 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/SurfaceRootBlockBakedModel.java @@ -20,8 +20,6 @@ import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.model.IDynamicBakedModel; import net.neoforged.neoforge.client.model.IModelBuilder; import net.neoforged.neoforge.client.model.data.ModelData; @@ -32,7 +30,7 @@ import java.util.*; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class SurfaceRootBlockBakedModel implements IDynamicBakedModel { private final BlockModel blockModel; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java index b4f7a4836..b5a0e71b9 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/baked/ThickBranchBlockBakedModel.java @@ -27,8 +27,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.model.IModelBuilder; import net.neoforged.neoforge.client.model.data.ModelData; import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext; @@ -42,7 +40,7 @@ import java.util.Map; import java.util.function.Function; -@OnlyIn(Dist.CLIENT) + public class ThickBranchBlockBakedModel extends BasicBranchBlockBakedModel { private final BakedModel[] trunksBark = new BakedModel[16]; // The trunk will always feature bark on its sides. diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/geometry/BranchBlockModelGeometry.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/geometry/BranchBlockModelGeometry.java index 8491bd9c3..d4d7fb2d5 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/geometry/BranchBlockModelGeometry.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/geometry/BranchBlockModelGeometry.java @@ -11,8 +11,6 @@ import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelState; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext; import net.neoforged.neoforge.client.model.geometry.IUnbakedGeometry; import org.jetbrains.annotations.Nullable; @@ -30,7 +28,7 @@ * * @author Harley O'Connor */ -@OnlyIn(Dist.CLIENT) + public class BranchBlockModelGeometry implements IUnbakedGeometry { protected final Set textures = new HashSet<>(); protected final ResourceLocation barkTextureLocation; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/PalmLeavesModelLoader.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/PalmLeavesModelLoader.java index c99fa5cc1..8b944fa52 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/PalmLeavesModelLoader.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/PalmLeavesModelLoader.java @@ -6,13 +6,11 @@ import net.minecraft.ResourceLocationException; import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.client.model.geometry.IGeometryLoader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -@OnlyIn(Dist.CLIENT) + public class PalmLeavesModelLoader implements IGeometryLoader { public static final Logger LOGGER = LogManager.getLogger(); diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/RootsBlockModelLoader.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/RootsBlockModelLoader.java index d16ed9b3f..ba0d58061 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/RootsBlockModelLoader.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/RootsBlockModelLoader.java @@ -3,14 +3,12 @@ import com.dtteam.dynamictrees.model.geometry.BranchBlockModelGeometry; import com.dtteam.dynamictrees.model.geometry.RootsBlockModelGeometry; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import org.jetbrains.annotations.Nullable; /** * @author Harley O'Connor */ -@OnlyIn(Dist.CLIENT) + public class RootsBlockModelLoader extends BranchBlockModelLoader { protected BranchBlockModelGeometry getModelGeometry(final ResourceLocation barkTextureLocation, diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/SurfaceRootBlockModelLoader.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/SurfaceRootBlockModelLoader.java index 6b69a6a12..85f61c8ab 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/SurfaceRootBlockModelLoader.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/SurfaceRootBlockModelLoader.java @@ -4,13 +4,11 @@ import com.dtteam.dynamictrees.model.geometry.SurfaceRootBlockModelGeometry; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; /** * @author Harley O'Connor */ -@OnlyIn(Dist.CLIENT) + public class SurfaceRootBlockModelLoader extends BranchBlockModelLoader { @Override diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/ThickBranchBlockModelLoader.java b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/ThickBranchBlockModelLoader.java index 70d942153..a8234854d 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/ThickBranchBlockModelLoader.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/model/loader/ThickBranchBlockModelLoader.java @@ -2,14 +2,12 @@ import com.dtteam.dynamictrees.model.geometry.BranchBlockModelGeometry; import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import org.jetbrains.annotations.Nullable; /** * @author Harley O'Connor */ -@OnlyIn(Dist.CLIENT) + public class ThickBranchBlockModelLoader extends BranchBlockModelLoader { @Override diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeClientHelper.java b/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeClientHelper.java new file mode 100644 index 000000000..9bc79d41e --- /dev/null +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeClientHelper.java @@ -0,0 +1,27 @@ +package com.dtteam.dynamictrees.platform; + +import com.dtteam.dynamictrees.DynamicTrees; +import com.dtteam.dynamictrees.entity.FallingTreeEntity; +import com.dtteam.dynamictrees.model.FallingTreeEntityModel; +import com.dtteam.dynamictrees.platform.services.IClientHelper; +import com.dtteam.dynamictrees.registry.FallingTreeEntityModelNF; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +public class NeoForgeClientHelper implements IClientHelper { + + @Override + public int getPixelRGBA(TextureAtlasSprite sprite, int x, int y) { + try { + return sprite.getPixelRGBA(0, x, y); + } catch (IllegalStateException e) { + DynamicTrees.LOG.warn("Image {} is not allocated.", sprite); + return 0; + } + } + + @Override + public FallingTreeEntityModel newFallingTreeEntityModel(FallingTreeEntity entity) { + return new FallingTreeEntityModelNF(entity); + } + +} diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeConfigHelper.java b/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeConfigHelper.java index d152ad771..9a3b9eaca 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeConfigHelper.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeConfigHelper.java @@ -1,7 +1,7 @@ package com.dtteam.dynamictrees.platform; import com.dtteam.dynamictrees.DynamicTrees; -import com.dtteam.dynamictrees.config.DTConfigs; +import com.dtteam.dynamictrees.config.*; import com.dtteam.dynamictrees.platform.services.IConfigHelper; import java.util.List; diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeMiscHelper.java b/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeMiscHelper.java index ea969a101..d013b5375 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeMiscHelper.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/platform/NeoForgeMiscHelper.java @@ -1,35 +1,14 @@ package com.dtteam.dynamictrees.platform; -import com.dtteam.dynamictrees.DynamicTrees; -import com.dtteam.dynamictrees.entity.FallingTreeEntity; -import com.dtteam.dynamictrees.model.FallingTreeEntityModel; import com.dtteam.dynamictrees.platform.services.IMiscHelper; -import com.dtteam.dynamictrees.registry.FallingTreeEntityModelNF; import com.dtteam.dynamictrees.worldgen.IDTBiomeHolderSet; import com.dtteam.dynamictrees.worldgen.holderset.DTBiomeHolderSet; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.server.ServerLifecycleHooks; public class NeoForgeMiscHelper implements IMiscHelper { - @Override - public int getPixelRGBA(TextureAtlasSprite sprite, int x, int y) { - try{ - return sprite.getPixelRGBA(0, x, y); - } catch (IllegalStateException e){ - DynamicTrees.LOG.warn("Image {} is not allocated.", sprite); - return 0; - } - } - - @Override @OnlyIn(Dist.CLIENT) - public FallingTreeEntityModel newFallingTreeEntityModel(FallingTreeEntity entity) { - return new FallingTreeEntityModelNF(entity); - } @Override public boolean isLevelRestoringBlockSnapshots(Level level) { diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java b/neoforge/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java index 6c3f03af5..cab0ef2a8 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/recipe/DendroPotionRecipeHandler.java @@ -1,8 +1,7 @@ package com.dtteam.dynamictrees.recipe; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.item.DendroPotion; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; import com.dtteam.dynamictrees.registry.DTRegistries; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponents; @@ -24,11 +23,9 @@ public class DendroPotionRecipeHandler { private static final List brewingRecipes = new ArrayList<>(); public static List getAllDendroRecipes() { - //If they have already been processed then don't process them again if (!brewingRecipes.isEmpty()) return brewingRecipes; - //Biochar potion - final ItemStack baseStack = setPotion(new ItemStack(Items.POTION), Services.CONFIG.getStringConfig(IConfigHelper.BIOCHAR_BREWING_BASE)); + final ItemStack baseStack = setPotion(new ItemStack(Items.POTION), DTConfigs.COMMON.biocharBrewingBase.get()); brewingRecipes.add(getRecipe(baseStack, new ItemStack(Items.CHARCOAL), getPotionStack(DendroPotion.DendroPotionType.BIOCHAR))); //Regular potions diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/AddDynamicTreesBiomeModifier.java b/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/AddDynamicTreesBiomeModifier.java index 64dc74014..1b5d4bfcc 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/AddDynamicTreesBiomeModifier.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/AddDynamicTreesBiomeModifier.java @@ -1,7 +1,6 @@ package com.dtteam.dynamictrees.worldgen.biomemodifier; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.registry.DTRegistries; import com.dtteam.dynamictrees.registry.NeoForgeRegistryLoader; import com.mojang.serialization.MapCodec; @@ -18,7 +17,7 @@ public class AddDynamicTreesBiomeModifier implements BiomeModifier { @Override public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { - if (phase == Phase.ADD && Services.CONFIG.getBoolConfig(IConfigHelper.WORLD_GEN)) { + if (phase == Phase.ADD && DTConfigs.SERVER.worldGen.get()) { BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); var placedFeatures = ServerLifecycleHooks.getCurrentServer().registryAccess().registryOrThrow(Registries.PLACED_FEATURE); generationSettings.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, placedFeatures.getHolderOrThrow(DTRegistries.CAVE_ROOTED_TREE_PLACED_FEATURE)); diff --git a/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java b/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java index 8b1ddde10..bc9d62518 100644 --- a/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java +++ b/neoforge/src/main/java/com/dtteam/dynamictrees/worldgen/biomemodifier/RunFeatureCancellersBiomeModifier.java @@ -3,8 +3,7 @@ import com.dtteam.dynamictrees.DynamicTrees; import com.dtteam.dynamictrees.api.worldgen.BiomePropertySelectors; import com.dtteam.dynamictrees.api.worldgen.FeatureCanceller; -import com.dtteam.dynamictrees.platform.Services; -import com.dtteam.dynamictrees.platform.services.IConfigHelper; +import com.dtteam.dynamictrees.config.DTConfigs; import com.dtteam.dynamictrees.registry.NeoForgeRegistryLoader; import com.dtteam.dynamictrees.worldgen.BiomeDatabase; import com.dtteam.dynamictrees.worldgen.featurecancellation.FeatureCancellationRegistry; @@ -25,7 +24,7 @@ public class RunFeatureCancellersBiomeModifier implements BiomeModifier { @Override public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { - if (phase == Phase.REMOVE && Services.CONFIG.getBoolConfig(IConfigHelper.WORLD_GEN)) { + if (phase == Phase.REMOVE && DTConfigs.SERVER.worldGen.get()) { ResourceKey biomeKey = biome.unwrapKey().orElseThrow(); BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); diff --git a/neoforge/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper b/neoforge/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper new file mode 100644 index 000000000..e5d2a8ee0 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/com.dtteam.dynamictrees.platform.services.IClientHelper @@ -0,0 +1 @@ +com.dtteam.dynamictrees.platform.NeoForgeClientHelper diff --git a/settings.gradle b/settings.gradle index b390d1301..57a2a6d4d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,6 +11,7 @@ pluginManagement { } filter { includeGroup('net.fabricmc') + includeGroup('net.fabricmc.unpick') includeGroup('fabric-loom') } }