diff --git a/build.gradle b/build.gradle index 4bf3b960..07b21da3 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,8 @@ repositories { maven { name 'minelp-snapshot'; url 'https://repo.minelittlepony-mod.com/maven/snapshot' } maven { name 'minelp-releases'; url 'https://repo.minelittlepony-mod.com/maven/release' } maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' } + maven { name 'Modrinth'; url 'https://api.modrinth.com/maven' } + maven { name 'JitPack'; url 'https://jitpack.io'; content { includeGroup "com.github.Virtuoel" } } } dependencies { @@ -73,17 +75,22 @@ dependencies { modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}" include "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}" + modCompileOnly "maven.modrinth:farmers-delight-fabric:${project.farmers_delight_version}", { exclude group: "net.fabricmc.fabric-api" } + if (project.use_pehkui == '1') { + modCompileOnly "maven.modrinth:pehkui:${project.pehkui_version}", { exclude group: "net.fabricmc.fabric-api" } + modCompileOnly "com.github.Virtuoel:KanosConfig:0.4.1", { exclude group: "net.fabricmc.fabric-api" } + } + + if (project.use_sodium == '1') { + modCompileOnly "maven.modrinth:sodium:${project.sodium_version}", { exclude group: "net.fabricmc.fabric-api" } + modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" } + } + if (project.tmi_type == 'emi') { modCompileOnly "dev.emi:emi-fabric:${project.emi_version}" } else { modCompileOnly "dev.emi:emi-fabric-dummy:${project.emi_version}" } - - if (project.tmi_type == 'rei') { - // TODO: - } else { - // TODO: - } } processResources { diff --git a/gradle.properties b/gradle.properties index 10edc213..391a2830 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ org.gradle.daemon=false description=Magical Abilities for Mine Little Pony! # Publishing - minecraft_version_range=>=1.20.2 + minecraft_version_range=1.20.2 modrinth_loader_type=fabric modrinth_project_id=9K7RJlvM @@ -24,10 +24,19 @@ org.gradle.daemon=false modmenu_version=8.0.0-beta.1 minelp_version=4.11.1+1.20.2 kirin_version=1.16.0+1.20.2 - reach_attributes_version=2.3.3 + reach_attributes_version=2.3.4 trinkets_version=3.8.0 terraformer_api_version=8.0.0-beta.1 +# Testing + use_pehkui=0 + use_sodium=1 + + farmers_delight_version=1.4.3 + pehkui_version=3.7.8+1.14.4-1.20.1 + iris_version=1.6.8+1.20.1 + sodium_version=mc1.20.1-0.5.2 + # TMI Testing tmi_type=emi emi_version=1.0.21+1.20.2 diff --git a/lib/reach-entity-attributes-2.3.3.jar b/lib/reach-entity-attributes-2.3.3.jar deleted file mode 100644 index 40ddce21..00000000 Binary files a/lib/reach-entity-attributes-2.3.3.jar and /dev/null differ diff --git a/lib/reach-entity-attributes-2.3.4.jar b/lib/reach-entity-attributes-2.3.4.jar new file mode 100644 index 00000000..f8e834ae Binary files /dev/null and b/lib/reach-entity-attributes-2.3.4.jar differ diff --git a/src/main/java/com/minelittlepony/unicopia/Config.java b/src/main/java/com/minelittlepony/unicopia/Config.java index 3a128a0e..8ccae93c 100644 --- a/src/main/java/com/minelittlepony/unicopia/Config.java +++ b/src/main/java/com/minelittlepony/unicopia/Config.java @@ -48,6 +48,9 @@ public class Config extends com.minelittlepony.common.util.settings.Config { public final Setting simplifiedPortals = value("compatibility", "simplifiedPortals", false) .addComment("Disables dynamic portal rendering"); + public final Setting disableShaders = value("compatibility", "disableShaders", false) + .addComment("Disables post-effect shaders used by the corruption mechanic"); + public final Setting fancyPortalRefreshRate = value("client", "fancyPortalRefreshRate", -1L) .addComment("Sets the refresh rate of portals when using fancy portal rendering") .addComment("Set to -1 (default) for unlimited"); diff --git a/src/main/java/com/minelittlepony/unicopia/UnicopiaMixinPlugin.java b/src/main/java/com/minelittlepony/unicopia/UnicopiaMixinPlugin.java index df5394d9..8f33d14a 100644 --- a/src/main/java/com/minelittlepony/unicopia/UnicopiaMixinPlugin.java +++ b/src/main/java/com/minelittlepony/unicopia/UnicopiaMixinPlugin.java @@ -38,6 +38,9 @@ public class UnicopiaMixinPlugin implements IMixinConfigPlugin { if (mixinClassName.indexOf("minelp") != -1) { return FabricLoader.getInstance().isModLoaded("minelp"); } + if (mixinClassName.indexOf("forgified") != -1) { + return FabricLoader.getInstance().isModLoaded("connectormod"); + } } return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/block/FruitBearingBlock.java b/src/main/java/com/minelittlepony/unicopia/block/FruitBearingBlock.java index b9741cef..2009d87a 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/FruitBearingBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/FruitBearingBlock.java @@ -66,7 +66,7 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka return true; } - protected BlockState getPlacedFruitState(Random random) { + public BlockState getPlacedFruitState(Random random) { return fruit.get().getDefaultState(); } @@ -141,7 +141,7 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka return TintedBlock.blend(foliageColor, overlay); } - private boolean isPositionValidForFruit(BlockState state, BlockPos pos) { + public boolean isPositionValidForFruit(BlockState state, BlockPos pos) { return state.getRenderingSeed(pos) % 3 == 1; } diff --git a/src/main/java/com/minelittlepony/unicopia/block/GoldenOakLeavesBlock.java b/src/main/java/com/minelittlepony/unicopia/block/GoldenOakLeavesBlock.java index 1ae9ed61..fe09f0bd 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/GoldenOakLeavesBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/GoldenOakLeavesBlock.java @@ -20,7 +20,7 @@ public class GoldenOakLeavesBlock extends FruitBearingBlock { } @Override - protected BlockState getPlacedFruitState(Random random) { + public BlockState getPlacedFruitState(Random random) { return super.getPlacedFruitState(random).with(EnchantedFruitBlock.ENCHANTED, random.nextInt(1000) == 0); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java b/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java index 77175375..21df38bc 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java @@ -42,14 +42,24 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable } public void loadShader(@Nullable Identifier shaderId) { + if (shader != null) { - shader.close(); + try { + shader.close(); + } catch (Throwable ignored) { + } finally { + shader = null; + } } if (shaderId == null) { return; } + if (Unicopia.getConfig().disableShaders.get()) { + return; + } + try { shader = new LoadedShader(client, shaderId); } catch (IOException e) { @@ -66,6 +76,10 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable } public void render(float tickDelta) { + if (Unicopia.getConfig().disableShaders.get()) { + return; + } + if (shader != null && client.player != null) { RenderSystem.disableBlend(); RenderSystem.disableDepthTest(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java b/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java index 9bad7931..d2d65f3e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/collision/EntityCollisions.java @@ -17,7 +17,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.WorldAccess; +import net.minecraft.world.EntityView; public class EntityCollisions { @@ -40,7 +40,7 @@ public class EntityCollisions { } } - public static List getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box) { + public static List getColissonShapes(@Nullable Entity entity, EntityView world, Box box) { ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity); return collectCollisionBoxes(box, collector -> { world.getOtherEntities(entity, box.expand(50), e -> { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinBoatEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinBoatEntity.java index 17feb4fa..55685652 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinBoatEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinBoatEntity.java @@ -31,7 +31,12 @@ abstract class MixinBoatEntity extends Entity implements LavaAffine { "fall", "canAddPassenger" }, - at = @At(value = "FIELD", target = "net/minecraft/registry/tag/FluidTags.WATER:Lnet/minecraft/registry/tag/TagKey;", opcode = Opcodes.GETSTATIC) + at = @At( + value = "FIELD", + target = "net/minecraft/registry/tag/FluidTags.WATER:Lnet/minecraft/registry/tag/TagKey;", + opcode = Opcodes.GETSTATIC + ), + require = 0 // Forge ) private TagKey redirectFluidTag() { return isLavaAffine() ? FluidTags.LAVA : FluidTags.WATER; diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntityView.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntityView.java new file mode 100644 index 00000000..c2de6378 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntityView.java @@ -0,0 +1,32 @@ +package com.minelittlepony.unicopia.mixin; + +import java.util.List; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; +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.CallbackInfoReturnable; + +import com.minelittlepony.unicopia.entity.collision.EntityCollisions; + +import net.minecraft.entity.Entity; +import net.minecraft.util.math.Box; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.EntityView; + +@Mixin(EntityView.class) +interface MixinEntityView { + @Inject(method = "getEntityCollisions(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Box;)Ljava/util/List;", at = @At("RETURN"), cancellable = true) + private void onGetEntityCollisions(@Nullable Entity entity, Box box, CallbackInfoReturnable> info) { + if (box.getAverageSideLength() < 1.0E-7D) { + return; + } + + List shapes = EntityCollisions.getColissonShapes(entity, (EntityView)this, box); + if (!shapes.isEmpty()) { + info.setReturnValue(Stream.concat(shapes.stream(), info.getReturnValue().stream()).toList()); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinVanillaBiomeParameters.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinVanillaBiomeParameters.java new file mode 100644 index 00000000..5a1c0a72 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinVanillaBiomeParameters.java @@ -0,0 +1,23 @@ +package com.minelittlepony.unicopia.mixin; + +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import com.minelittlepony.unicopia.server.world.gen.BiomeSelectionInjector; +import com.mojang.datafixers.util.Pair; + +import net.minecraft.registry.RegistryKey; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.util.MultiNoiseUtil; +import net.minecraft.world.biome.source.util.VanillaBiomeParameters; + +@Mixin(VanillaBiomeParameters.class) +abstract class MixinVanillaBiomeParameters { + @ModifyVariable(method = "writeOverworldBiomeParameters", at = @At("HEAD")) + private Consumer>> onWriteOverworldBiomeParameters(Consumer>> parametersCollector) { + return new BiomeSelectionInjector(parametersCollector); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java index d3237ca4..eda9c5b4 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java @@ -1,26 +1,17 @@ package com.minelittlepony.unicopia.mixin; -import java.util.List; import java.util.Stack; import java.util.function.Supplier; -import java.util.stream.Stream; - -import org.jetbrains.annotations.Nullable; - 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.minelittlepony.unicopia.entity.collision.EntityCollisions; import com.minelittlepony.unicopia.entity.duck.RotatedView; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import net.minecraft.block.BlockState; -import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; @@ -47,18 +38,6 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source return destructions.get(); } - @Override - public List getEntityCollisions(@Nullable Entity entity, Box box) { - if (box.getAverageSideLength() >= 1.0E-7D) { - List shapes = EntityCollisions.getColissonShapes(entity, this, box); - if (!shapes.isEmpty()) { - return Stream.concat(shapes.stream(), WorldAccess.super.getEntityCollisions(entity, box).stream()).toList(); - } - } - - return WorldAccess.super.getEntityCollisions(entity, box); - } - @ModifyVariable(method = "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;II)Z", at = @At("HEAD")) private BlockPos modifyBlockPos(BlockPos pos) { pos = applyRotation(pos); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/forgified/MixinIForgeBoat.java b/src/main/java/com/minelittlepony/unicopia/mixin/forgified/MixinIForgeBoat.java new file mode 100644 index 00000000..dd7abfe8 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/forgified/MixinIForgeBoat.java @@ -0,0 +1,54 @@ +package com.minelittlepony.unicopia.mixin.forgified; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.*; +import com.minelittlepony.unicopia.entity.duck.LavaAffine; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; +import net.minecraft.registry.tag.FluidTags; + +@Pseudo +@Mixin(targets = "net.minecraftforge.common.extensions.IForgeBoat") +interface MixinIForgeBoat { + @ModifyVariable( + method = "canBoatInFluid(Lnet/minecraft/fluid/FluidState;)Z", + at = @At("HEAD"), + ordinal = 0, + argsOnly = true, + require = 0 + ) + private FluidState modifyFluidState(FluidState incoming) { + if (this instanceof LavaAffine a && a.isLavaAffine()) { + if (incoming.isIn(FluidTags.WATER)) { + return Fluids.LAVA.getDefaultState(); + } + if (incoming.isIn(FluidTags.LAVA)) { + return Fluids.WATER.getDefaultState(); + } + } + + return incoming; + } + @SuppressWarnings("deprecation") + @ModifyVariable( + method = "canBoatInFluid(Lnet/minecraft/fluid/Fluid;)Z", + at = @At("HEAD"), + ordinal = 0, + argsOnly = true, + require = 0 + ) + private Fluid modifyFluid(Fluid incoming) { + if (this instanceof LavaAffine a && a.isLavaAffine()) { + if (incoming.isIn(FluidTags.WATER)) { + return Fluids.LAVA; + } + if (incoming.isIn(FluidTags.LAVA)) { + return Fluids.WATER; + } + } + + return incoming; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Tree.java b/src/main/java/com/minelittlepony/unicopia/server/world/Tree.java index 885effb5..7128f919 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Tree.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Tree.java @@ -4,6 +4,7 @@ import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; import com.minelittlepony.unicopia.block.UBlocks; @@ -17,10 +18,11 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.random.Random; import net.minecraft.registry.*; import net.minecraft.registry.tag.BiomeTags; -import net.minecraft.world.gen.GenerationStep; +import net.minecraft.world.biome.BiomeKeys; import net.minecraft.world.gen.feature.*; import net.minecraft.world.gen.feature.size.TwoLayersFeatureSize; import net.minecraft.world.gen.foliage.FoliagePlacer; +import net.minecraft.world.gen.GenerationStep; import net.minecraft.world.gen.placementmodifier.PlacementModifier; import net.minecraft.world.gen.stateprovider.BlockStateProvider; import net.minecraft.world.gen.trunk.TrunkPlacer; @@ -29,9 +31,8 @@ public record Tree ( Identifier id, TreeFeatureConfig.Builder config, RegistryKey> configuredFeatureId, - Optional> placedFeatureId, - Optional sapling, - Optional placement + Set placements, + Optional sapling ) { public static final List REGISTRY = new ArrayList<>(); @@ -44,20 +45,22 @@ public record Tree ( }); registries.getOptional(RegistryKeys.PLACED_FEATURE).ifPresent(registry -> { var reg = registries.asDynamicRegistryManager().createRegistryLookup().getOrThrow(RegistryKeys.CONFIGURED_FEATURE); - REGISTRY.stream().filter(tree -> tree.placedFeatureId().isPresent()).forEach(tree -> { - var placedFeature = new PlacedFeature(reg.getOrThrow(tree.configuredFeatureId()), - VegetationPlacedFeatures.treeModifiersWithWouldSurvive(tree.placement().orElseThrow(), tree.sapling().orElse(Blocks.OAK_SAPLING)) - ); - - Registry.register(registry, tree.id, placedFeature); + REGISTRY.stream().forEach(tree -> { + tree.placements().forEach(placement -> { + Registry.register(registry, placement.id(), new PlacedFeature(reg.getOrThrow(tree.configuredFeatureId()), + VegetationPlacedFeatures.treeModifiersWithWouldSurvive(placement.count(), tree.sapling().orElse(Blocks.OAK_SAPLING)) + )); + }); }); }); }); - } public static class Builder { public static final Predicate IS_FOREST = BiomeSelectors.foundInOverworld().and(BiomeSelectors.tag(BiomeTags.IS_FOREST)); + public static final Predicate IS_OAK_FOREST = IS_FOREST + .and(BiomeSelectors.excludeByKey(BiomeKeys.BIRCH_FOREST, BiomeKeys.OLD_GROWTH_BIRCH_FOREST, BiomeKeys.DARK_FOREST)) + .and(BiomeSelectors.tag(BiomeTags.IS_TAIGA).negate()); public static Builder create(Identifier id, TrunkPlacer trunkPlacer, FoliagePlacer foliagePlacer) { return new Builder(id, trunkPlacer, foliagePlacer); @@ -73,8 +76,7 @@ public record Tree ( private final Identifier id; - private Optional> selector = Optional.empty(); - private Optional countModifier = Optional.empty(); + private Map placements = new HashMap<>(); private Function configParameters = Function.identity(); private Optional size = Optional.empty(); @@ -104,13 +106,18 @@ public record Tree ( return this; } - public Builder count(int count, float extraChance, int extraCount) { - countModifier = Optional.of(PlacedFeatures.createCountExtraModifier(count, extraChance, extraCount)); - return this; + public Builder placement(int count, float extraChance, int extraCount, Predicate selector) { + return placement("", count, extraChance, extraCount, selector); } - public Builder biomes(Predicate selector) { - this.selector = Optional.of(selector); + public Builder placement(String suffex, int count, float extraChance, int extraCount, Predicate selector) { + Identifier id = this.id.withSuffixedPath("/placed" + (suffex.isEmpty() ? "" : "/") + suffex); + placements.put(id, new Placement( + id, + PlacedFeatures.createCountExtraModifier(count, extraChance, extraCount), + RegistryKey.of(RegistryKeys.PLACED_FEATURE, id), + selector + )); return this; } @@ -119,7 +126,7 @@ public record Tree ( return this; } - public Builder farmingCondition(int yLevel, int sizeBelowY, int sizeAboveY) { + public Builder dimensions(int yLevel, int sizeBelowY, int sizeAboveY) { this.size = Optional.of(new TwoLayersFeatureSize(yLevel, Math.max(0, sizeBelowY), Math.max(0, sizeAboveY))); return this; } @@ -132,23 +139,28 @@ public record Tree ( BlockStateProvider.of(leavesType), foliagePlacer, size.get() - )), configuredFeatureId, selector.map(selector -> { - RegistryKey i = RegistryKey.of(RegistryKeys.PLACED_FEATURE, id); - BiomeModifications.addFeature(selector, GenerationStep.Feature.VEGETAL_DECORATION, i); - return i; - }), saplingId.map(id -> UBlocks.register(id, saplingConstructor.apply(new SaplingGenerator() { + )), configuredFeatureId, placements.values().stream() + .collect(Collectors.toUnmodifiableSet()), + saplingId.map(id -> UBlocks.register(id, saplingConstructor.apply(new SaplingGenerator() { @Override protected RegistryKey> getTreeFeature(Random rng, boolean flowersNearby) { return configuredFeatureId; } - }, FabricBlockSettings.copy(Blocks.OAK_SAPLING)), ItemGroups.NATURAL)), countModifier); + }, FabricBlockSettings.copy(Blocks.OAK_SAPLING)), ItemGroups.NATURAL))); if (REGISTRY.isEmpty()) { bootstrap(); } REGISTRY.add(tree); + tree.placements().forEach(placement -> { + BiomeModifications.addFeature(placement.selector(), GenerationStep.Feature.VEGETAL_DECORATION, placement.feature()); + }); return tree; } } + + public record Placement(Identifier id, PlacementModifier count, RegistryKey feature, Predicate selector) { + + } } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java b/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java index 0d456e02..7ad5aa26 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/UTreeGen.java @@ -3,7 +3,9 @@ package com.minelittlepony.unicopia.server.world; import com.google.common.collect.ImmutableList; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.block.UBlocks; +import com.minelittlepony.unicopia.server.world.gen.FruitBlobFoliagePlacer; +import net.fabricmc.fabric.api.biome.v1.BiomeSelectors; import net.minecraft.block.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.intprovider.ConstantIntProvider; @@ -39,19 +41,20 @@ public interface UTreeGen { .log(UBlocks.ZAP_LOG) .leaves(UBlocks.ZAP_LEAVES) .sapling(Unicopia.id("zapling")) - .biomes(Tree.Builder.IS_FOREST) - .count(0, 0.01F, 1) - .farmingCondition(6, 0, 8) + .placement(0, 0.01F, 1, Tree.Builder.IS_FOREST) + .dimensions(6, 0, 8) .build(); - Tree GREEN_APPLE_TREE = createAppleTree("green_apple", UBlocks.GREEN_APPLE_LEAVES, 2); - Tree SWEET_APPLE_TREE = createAppleTree("sweet_apple", UBlocks.SWEET_APPLE_LEAVES, 3); - Tree SOUR_APPLE_TREE = createAppleTree("sour_apple", UBlocks.SOUR_APPLE_LEAVES, 5); + Tree GREEN_APPLE_TREE = createAppleTree("green_apple", UBlocks.GREEN_APPLE_LEAVES, 2, 0.2F).build(); + Tree SWEET_APPLE_TREE = createAppleTree("sweet_apple", UBlocks.SWEET_APPLE_LEAVES, 3, 0.1F) + .placement("orchard", 6, 0.1F, 3, BiomeSelectors.includeByKey(UWorldGen.SWEET_APPLE_ORCHARD)) + .build(); + Tree SOUR_APPLE_TREE = createAppleTree("sour_apple", UBlocks.SOUR_APPLE_LEAVES, 5, 0.2F).build(); Tree GOLDEN_APPLE_TREE = Tree.Builder.create(Unicopia.id("golden_oak_tree"), new StraightTrunkPlacer(6, 1, 3), new BlobFoliagePlacer(ConstantIntProvider.create(3), ConstantIntProvider.create(0), 3) ) .configure(TreeFeatureConfig.Builder::forceDirt) - .farmingCondition(1, 3, 5) + .dimensions(1, 3, 5) .log(UBlocks.GOLDEN_OAK_LOG) .leaves(UBlocks.GOLDEN_OAK_LEAVES) .sapling(Unicopia.id("golden_oak_sapling")) @@ -60,7 +63,7 @@ public interface UTreeGen { new StraightTrunkPlacer(4, 5, 3), new FernFoliagePlacer(ConstantIntProvider.create(4), ConstantIntProvider.create(0)) ) - .farmingCondition(6, 0, 8) + .dimensions(6, 0, 8) .log(UBlocks.PALM_LOG) .leaves(UBlocks.PALM_LEAVES) .sapling(Unicopia.id("palm_sapling")).sapling((generator, settings) -> { @@ -72,36 +75,33 @@ public interface UTreeGen { }; }) .configure(builder -> builder.dirtProvider(BlockStateProvider.of(Blocks.SAND))) - .biomes(selector -> selector.hasTag(BiomeTags.IS_BEACH) || selector.hasTag(BiomeTags.IS_JUNGLE)) - .count(2, 0.01F, 1) + .placement(2, 0.01F, 1, selector -> selector.hasTag(BiomeTags.IS_BEACH) || selector.hasTag(BiomeTags.IS_JUNGLE)) .build(); Tree MANGO_TREE = Tree.Builder.create(Unicopia.id("mango_tree"), new StraightTrunkPlacer(4, 7, 3), new BlobFoliagePlacer(ConstantIntProvider.create(3), ConstantIntProvider.create(0), 3) ) - .farmingCondition(9, 0, 4) + .dimensions(9, 0, 4) .log(Blocks.JUNGLE_LOG) .leaves(UBlocks.MANGO_LEAVES) - .biomes(selector -> selector.hasTag(BiomeTags.IS_JUNGLE) && selector.getBiomeKey() != BiomeKeys.SPARSE_JUNGLE) .sapling(Unicopia.id("mango_sapling")) - .count(1, 1, 2) + .placement(1, 1, 2, selector -> selector.hasTag(BiomeTags.IS_JUNGLE) && selector.getBiomeKey() != BiomeKeys.SPARSE_JUNGLE) .configure(builder -> builder.decorators(ImmutableList.of(TrunkVineTreeDecorator.INSTANCE, new LeavesVineTreeDecorator(0.25f)))) .build(); - static Tree createAppleTree(String name, Block leaves, int preferredDensity) { + static Tree.Builder createAppleTree(String name, Block leaves, int preferredDensity, float spawnRate) { return Tree.Builder.create(Unicopia.id(name + "_tree"), new StraightTrunkPlacer(4, 3, 2), - new BlobFoliagePlacer(ConstantIntProvider.create(3), ConstantIntProvider.create(0), 3) + new FruitBlobFoliagePlacer(ConstantIntProvider.create(3), ConstantIntProvider.create(0), 3) ) .configure(TreeFeatureConfig.Builder::forceDirt) - .biomes(selector -> selector.hasTag(BiomeTags.IS_FOREST)) - .count(2, 0.01F, 1) - .farmingCondition(1, preferredDensity - 2, preferredDensity) + .placement(0, spawnRate, 4, Tree.Builder.IS_OAK_FOREST) + .dimensions(1, preferredDensity - 2, preferredDensity) .log(Blocks.OAK_LOG) .leaves(leaves) - .sapling(Unicopia.id(name + "_sapling")) - .build(); + .sapling(Unicopia.id(name + "_sapling")); } - static void bootstrap() { } + static void bootstrap() { + } } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java index 097fdc9f..69a7991e 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java @@ -5,6 +5,7 @@ import java.util.List; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.block.ShellsBlock; import com.minelittlepony.unicopia.block.UBlocks; +import com.minelittlepony.unicopia.server.world.gen.OverworldBiomeSelectionCallback; import net.fabricmc.fabric.api.biome.v1.BiomeModifications; import net.fabricmc.fabric.api.biome.v1.BiomeSelectors; @@ -13,11 +14,13 @@ import net.minecraft.block.Blocks; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.tag.BiomeTags; import net.minecraft.util.collection.DataPool; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.intprovider.UniformIntProvider; +import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeKeys; import net.minecraft.world.gen.GenerationStep; import net.minecraft.world.gen.blockpredicate.BlockPredicate; @@ -66,6 +69,8 @@ public interface UWorldGen { BiomePlacementModifier.of() )); + RegistryKey SWEET_APPLE_ORCHARD = RegistryKey.of(RegistryKeys.BIOME, Unicopia.id("sweet_apple_orchard")); + static void bootstrap() { BiomeModifications.addFeature(BiomeSelectors.tag(BiomeTags.IS_JUNGLE), GenerationStep.Feature.VEGETAL_DECORATION, PINEAPPLE_PLANT_PLACED_FEATURE); BiomeModifications.addFeature( @@ -75,5 +80,11 @@ public interface UWorldGen { .or(BiomeSelectors.includeByKey(BiomeKeys.STONY_SHORE)) ), GenerationStep.Feature.VEGETAL_DECORATION, SHELLS_PLACED_FEATURE); UTreeGen.bootstrap(); + + OverworldBiomeSelectionCallback.EVENT.register(context -> { + if (context.biomeKey() == BiomeKeys.FOREST) { + context.addOverride(context.referenceFrame().temperature().splitAbove(0.9F), SWEET_APPLE_ORCHARD); + } + }); } } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/BiomeSelectionContext.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/BiomeSelectionContext.java new file mode 100644 index 00000000..1ee71b66 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/BiomeSelectionContext.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.registry.RegistryKey; +import net.minecraft.world.biome.Biome; + +public interface BiomeSelectionContext { + RegistryKey biomeKey(); + + SplittableBiomeCoordinate referenceFrame(); + + @Nullable + RegistryKey addOverride(SplittableBiomeCoordinate coordinate, RegistryKey biome); + + public record SplittableBiomeCoordinate( + SplitableParameterRange temperature, + SplitableParameterRange humidity, + SplitableParameterRange continentalness, + SplitableParameterRange erosion, + SplitableParameterRange depth, + SplitableParameterRange weirdness, + long offset) { + } + + public interface SplitableParameterRange { + SplittableBiomeCoordinate splitAbove(float midpoint); + + SplittableBiomeCoordinate splitBelow(float midpoint); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/BiomeSelectionInjector.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/BiomeSelectionInjector.java new file mode 100644 index 00000000..1b94b690 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/BiomeSelectionInjector.java @@ -0,0 +1,185 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.include.com.google.common.base.Objects; + +import com.minelittlepony.unicopia.server.world.gen.BiomeSelectionContext.SplittableBiomeCoordinate; +import com.mojang.datafixers.util.Pair; + +import net.minecraft.registry.RegistryKey; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.util.MultiNoiseUtil; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.ParameterRange; + +public final class BiomeSelectionInjector implements Consumer>> { + + private final Consumer>> parameterConsumer; + + public BiomeSelectionInjector(Consumer>> parameterConsumer) { + this.parameterConsumer = parameterConsumer; + } + + @Override + public void accept(Pair> parameter) { + Context context = new Context(parameter); + OverworldBiomeSelectionCallback.EVENT.invoker().onSelectingBiome(context); + if (!context.overrides.isEmpty()) { + List>> subSections = List.of(parameter); + // sort splits from largest to smallest + var divisions = context.overrides.entrySet() + .stream() + .sorted(Comparator.>, Float>comparing(entry -> Context.getVolume(entry.getKey())).reversed()) + .toList(); + // recursively sub-divide into parts so every split gets a (kinda) fair share + for (Map.Entry> division : divisions) { + subSections = subSections.stream().flatMap(par -> Stream.of( + Pair.of(Context.write(division.getKey(), par.getFirst()), division.getValue()), + par + )).toList(); + } + // output the result + subSections.forEach(parameterConsumer); + } else { + parameterConsumer.accept(parameter); + } + } + + class Context implements BiomeSelectionContext { + private final Pair> parameter; + private final Map> overrides = new LinkedHashMap<>(); + + public Context(Pair> parameter) { + this.parameter = parameter; + } + + @Override + public RegistryKey biomeKey() { + return parameter.getSecond(); + } + + @Override + public SplittableBiomeCoordinate referenceFrame() { + return createStart(parameter.getFirst()); + } + + @Override + @Nullable + public RegistryKey addOverride(SplittableBiomeCoordinate coordinate, RegistryKey biome) { + return overrides.put(coordinate, biome); + } + + static float getVolume(SplittableBiomeCoordinate coordinate) { + return ((SplitableParameterRangeImpl)coordinate.temperature()).length() + * ((SplitableParameterRangeImpl)coordinate.humidity()).length() + * ((SplitableParameterRangeImpl)coordinate.continentalness()).length() + * ((SplitableParameterRangeImpl)coordinate.erosion()).length() + * ((SplitableParameterRangeImpl)coordinate.depth()).length() + * ((SplitableParameterRangeImpl)coordinate.weirdness()).length(); + } + + static NoiseHypercube write(SplittableBiomeCoordinate coordinate, NoiseHypercube referenceFrame) { + return new NoiseHypercube( + ((SplitableParameterRangeImpl)coordinate.temperature()).write(referenceFrame.temperature()), + ((SplitableParameterRangeImpl)coordinate.humidity()).write(referenceFrame.humidity()), + ((SplitableParameterRangeImpl)coordinate.continentalness()).write(referenceFrame.continentalness()), + ((SplitableParameterRangeImpl)coordinate.erosion()).write(referenceFrame.erosion()), + ((SplitableParameterRangeImpl)coordinate.depth()).write(referenceFrame.depth()), + ((SplitableParameterRangeImpl)coordinate.weirdness()).write(referenceFrame.weirdness()), + coordinate.offset() + ); + } + + static SplittableBiomeCoordinate createStart(NoiseHypercube referenceFrame) { + final SplittableBiomeCoordinate[] self = new SplittableBiomeCoordinate[1]; + return self[0] = new SplittableBiomeCoordinate( + new SplitableParameterRangeImpl(self, SplittableBiomeCoordinate::temperature, 0, 1), + new SplitableParameterRangeImpl(self, SplittableBiomeCoordinate::humidity, 0, 1), + new SplitableParameterRangeImpl(self, SplittableBiomeCoordinate::continentalness, 0, 1), + new SplitableParameterRangeImpl(self, SplittableBiomeCoordinate::erosion, 0, 1), + new SplitableParameterRangeImpl(self, SplittableBiomeCoordinate::depth, 0, 1), + new SplitableParameterRangeImpl(self, SplittableBiomeCoordinate::weirdness, 0, 1), + referenceFrame.offset() + ); + } + + static SplittableBiomeCoordinate createCopy(SplittableBiomeCoordinate old) { + final SplittableBiomeCoordinate[] self = new SplittableBiomeCoordinate[1]; + return self[0] = new SplittableBiomeCoordinate( + new SplitableParameterRangeImpl(self, (SplitableParameterRangeImpl)old.temperature()), + new SplitableParameterRangeImpl(self, (SplitableParameterRangeImpl)old.humidity()), + new SplitableParameterRangeImpl(self, (SplitableParameterRangeImpl)old.continentalness()), + new SplitableParameterRangeImpl(self, (SplitableParameterRangeImpl)old.erosion()), + new SplitableParameterRangeImpl(self, (SplitableParameterRangeImpl)old.depth()), + new SplitableParameterRangeImpl(self, (SplitableParameterRangeImpl)old.weirdness()), + old.offset() + ); + } + + private static final class SplitableParameterRangeImpl implements SplitableParameterRange { + private final SplittableBiomeCoordinate[] coordinate; + private final Function dimension; + private float min; + private float max; + + SplitableParameterRangeImpl(SplittableBiomeCoordinate[] coordinate, SplitableParameterRangeImpl original) { + this(coordinate, original.dimension, original.min, original.max); + } + + SplitableParameterRangeImpl(SplittableBiomeCoordinate[] coordinate, Function dimension, float min, float max) { + this.coordinate = coordinate; + this.dimension = dimension; + this.min = min; + this.max = max; + } + + @Override + public SplittableBiomeCoordinate splitAbove(float midpoint) { + return copyWithDifference(o -> o.min = MathHelper.lerp(midpoint, o.min, o.max)); + } + + @Override + public SplittableBiomeCoordinate splitBelow(float midpoint) { + return copyWithDifference(o -> o.max = MathHelper.lerp(midpoint, o.min, o.max)); + } + + private SplittableBiomeCoordinate copyWithDifference(Consumer mutator) { + SplittableBiomeCoordinate copy = createCopy(coordinate[0]); + mutator.accept((SplitableParameterRangeImpl)dimension.apply(copy)); + return copy; + } + + public ParameterRange write(ParameterRange range) { + return ParameterRange.of( + MultiNoiseUtil.toFloat(range.min()) * (1 + min), + MultiNoiseUtil.toFloat(range.max()) * max + ); + } + + public float length() { + return max - min; + } + + @Override + public boolean equals(Object o) { + return o instanceof SplitableParameterRangeImpl i + && MathHelper.approximatelyEquals(i.min, min) + && MathHelper.approximatelyEquals(i.max, max); + } + + @Override + public int hashCode() { + return Objects.hashCode(min, max); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/FruitBlobFoliagePlacer.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/FruitBlobFoliagePlacer.java new file mode 100644 index 00000000..db32594e --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/FruitBlobFoliagePlacer.java @@ -0,0 +1,51 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import java.util.HashMap; +import java.util.Map; + +import org.joml.Vector2i; + +import com.minelittlepony.unicopia.block.FruitBearingBlock; +import com.mojang.datafixers.util.Pair; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.intprovider.IntProvider; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.TestableWorld; +import net.minecraft.world.gen.feature.TreeFeatureConfig; +import net.minecraft.world.gen.foliage.BlobFoliagePlacer; + +public class FruitBlobFoliagePlacer extends BlobFoliagePlacer { + + public FruitBlobFoliagePlacer(IntProvider radius, IntProvider offset, int height) { + super(radius, offset, height); + } + + @Override + public void generate(TestableWorld world, BlockPlacer placer, Random random, TreeFeatureConfig config, int trunkHeight, TreeNode treeNode, int foliageHeight, int radius) { + final Map> leafPositions = new HashMap<>(); + super.generate(world, new BlockPlacer() { + @Override + public void placeBlock(BlockPos pos, BlockState state) { + placer.placeBlock(pos, state); + if (state.getBlock() instanceof FruitBearingBlock block + && block.isPositionValidForFruit(state, pos)) { + leafPositions.compute(new Vector2i(pos.getX(), pos.getZ()), (col, original) -> original == null || original.getSecond() > pos.getY() ? Pair.of(block, pos.getY()) : original); + } + } + + @Override + public boolean hasPlacedBlock(BlockPos pos) { + return placer.hasPlacedBlock(pos); + } + }, random, config, trunkHeight, treeNode, foliageHeight, radius); + BlockPos.Mutable mutable = new BlockPos.Mutable(); + leafPositions.entrySet().forEach(pos -> { + mutable.set(pos.getKey().x(), pos.getValue().getSecond() - 1, pos.getKey().y()); + if (!placer.hasPlacedBlock(mutable) && random.nextInt(12) == 0) { + placer.placeBlock(mutable, pos.getValue().getFirst().getPlacedFruitState(random)); + } + }); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/OverworldBiomeSelectionCallback.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/OverworldBiomeSelectionCallback.java new file mode 100644 index 00000000..b98f6826 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/OverworldBiomeSelectionCallback.java @@ -0,0 +1,23 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Provides a basic event for mods to inject their own biomes in place of vanilla overworld biomes. + *

+ * Mods are able to insert entries for their biomes into the ranges for existing ones by + * sub-dividing the provided section into pieces and assigning a new biome to one of the create + * segments. + */ +public interface OverworldBiomeSelectionCallback { + Event EVENT = EventFactory.createArrayBacked(OverworldBiomeSelectionCallback.class, delegates -> { + return context -> { + for (OverworldBiomeSelectionCallback delegate : delegates) { + delegate.onSelectingBiome(context); + } + }; + }); + + void onSelectingBiome(BiomeSelectionContext context); +} diff --git a/src/main/resources/assets/unicopia/blockstates/green_apple_leaves.json b/src/main/resources/assets/unicopia/blockstates/green_apple_leaves.json index 9b6325d5..635befb5 100644 --- a/src/main/resources/assets/unicopia/blockstates/green_apple_leaves.json +++ b/src/main/resources/assets/unicopia/blockstates/green_apple_leaves.json @@ -1,6 +1,15 @@ { "variants": { - "": { + "stage=flowering": { + "model": "unicopia:block/green_apple_leaves_flowering" + }, + "stage=idle": { + "model": "unicopia:block/green_apple_leaves" + }, + "stage=fruiting": { + "model": "unicopia:block/green_apple_leaves" + }, + "stage=withering": { "model": "unicopia:block/green_apple_leaves" } } diff --git a/src/main/resources/assets/unicopia/blockstates/sour_apple_leaves.json b/src/main/resources/assets/unicopia/blockstates/sour_apple_leaves.json index f9d40dd7..e15d3600 100644 --- a/src/main/resources/assets/unicopia/blockstates/sour_apple_leaves.json +++ b/src/main/resources/assets/unicopia/blockstates/sour_apple_leaves.json @@ -1,6 +1,15 @@ { "variants": { - "": { + "stage=flowering": { + "model": "unicopia:block/sour_apple_leaves_flowering" + }, + "stage=idle": { + "model": "unicopia:block/sour_apple_leaves" + }, + "stage=fruiting": { + "model": "unicopia:block/sour_apple_leaves" + }, + "stage=withering": { "model": "unicopia:block/sour_apple_leaves" } } diff --git a/src/main/resources/assets/unicopia/blockstates/sweet_apple_leaves.json b/src/main/resources/assets/unicopia/blockstates/sweet_apple_leaves.json index c6e7da22..e09ef0b9 100644 --- a/src/main/resources/assets/unicopia/blockstates/sweet_apple_leaves.json +++ b/src/main/resources/assets/unicopia/blockstates/sweet_apple_leaves.json @@ -1,6 +1,15 @@ { "variants": { - "": { + "stage=flowering": { + "model": "unicopia:block/sweet_apple_leaves_flowering" + }, + "stage=idle": { + "model": "unicopia:block/sweet_apple_leaves" + }, + "stage=fruiting": { + "model": "unicopia:block/sweet_apple_leaves" + }, + "stage=withering": { "model": "unicopia:block/sweet_apple_leaves" } } diff --git a/src/main/resources/assets/unicopia/lang/ru_ru.json b/src/main/resources/assets/unicopia/lang/ru_ru.json index 5c289ae3..c03f94db 100644 --- a/src/main/resources/assets/unicopia/lang/ru_ru.json +++ b/src/main/resources/assets/unicopia/lang/ru_ru.json @@ -232,6 +232,20 @@ "block.unicopia.zap_wood": "Зап-яблоня", "block.unicopia.stripped_zap_log": "Бревно обтёсанной зап-яблони", "block.unicopia.stripped_zap_wood": "Обтёсанная древесина зап-яблони", + "block.unicopia.zap_planks": "Зап-яблочные доски", + "block.unicopia.zap_stairs": "Зап-яблочные ступеньки", + "block.unicopia.zap_slab": "Зап-яблочная плита", + "block.unicopia.zap_fence": "Зап-яблочный забор", + "block.unicopia.zap_fence_gate": "Зап-яблочная калитка", + "block.unicopia.waxed_zap_log": "Вощёное бревно зап-яблони", + "block.unicopia.waxed_zap_wood": "Вощёная древесина зап-яблони", + "block.unicopia.waxed_stripped_zap_log": "Вощёное бревно обтёсанной зап-яблони", + "block.unicopia.waxed_stripped_zap_wood": "Вощёная древесина обтёсанной зап-яблони", + "block.unicopia.waxed_zap_planks": "Вощёные доски зап-яблони", + "block.unicopia.waxed_zap_stairs": "Вощёные ступеньки зап-яблони", + "block.unicopia.waxed_zap_slab": "Вощёная плита зап-яблони", + "block.unicopia.waxed_zap_fence": "Вощёный зап-яблочный забор", + "block.unicopia.waxed_zap_fence_gate": "Вощёная зап-яблочная калитка", "block.unicopia.zap_leaves": "Листья зап-яблони", "block.unicopia.flowering_zap_leaves": "Листья цветущей зап-яблони", "block.unicopia.zap_apple": "Зап-яблоня", @@ -1447,6 +1461,8 @@ "death.attack.unicopia.horseshoe.self": "%1$s зарядил подковой в себя", "death.attack.unicopia.horseshoe.item": "%2$s зарядил подковой в %1$s используя %3$s", "death.attack.unicopia.horseshoe.player": "%2$s зарядил подковой в %1$s", + "death.attack.unicopia.spikes": "%1$s был заколот до смерти", + "death.attack.unicopia.spikes.player": "%1$s упал на шипы, пытаясь спастись от %2$s", "death.fell.accident.ladder.pegasus": "%1$s забыл, что умеет летать, и упал с лестницы", "death.fell.accident.vines.pegasus": "%1$s забыл, что умеет летать, и упал с лозы", diff --git a/src/main/resources/assets/unicopia/models/block/green_apple_leaves_flowering.json b/src/main/resources/assets/unicopia/models/block/green_apple_leaves_flowering.json new file mode 100644 index 00000000..1ab7bd8c --- /dev/null +++ b/src/main/resources/assets/unicopia/models/block/green_apple_leaves_flowering.json @@ -0,0 +1,7 @@ +{ + "parent": "unicopia:block/sweet_apple_leaves_flowering", + "textures": { + "all": "unicopia:block/green_apple_leaves", + "overlay": "unicopia:block/green_apple_leaves_flowering" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/models/block/sour_apple_leaves_flowering.json b/src/main/resources/assets/unicopia/models/block/sour_apple_leaves_flowering.json new file mode 100644 index 00000000..42924cd9 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/block/sour_apple_leaves_flowering.json @@ -0,0 +1,7 @@ +{ + "parent": "unicopia:block/sweet_apple_leaves_flowering", + "textures": { + "all": "unicopia:block/sour_apple_leaves", + "overlay": "unicopia:block/sour_apple_leaves_flowering" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/models/block/sweet_apple_leaves_flowering.json b/src/main/resources/assets/unicopia/models/block/sweet_apple_leaves_flowering.json new file mode 100644 index 00000000..3d04aabc --- /dev/null +++ b/src/main/resources/assets/unicopia/models/block/sweet_apple_leaves_flowering.json @@ -0,0 +1,31 @@ +{ "parent": "minecraft:block/block", + "textures": { + "all": "unicopia:block/sweet_apple_leaves", + "particle": "#all", + "overlay": "unicopia:block/sweet_apple_leaves_flowering" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#all", "tintindex": 0, "cullface": "east" } + } + }, + { "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/unicopia/textures/block/green_apple_leaves_flowering.png b/src/main/resources/assets/unicopia/textures/block/green_apple_leaves_flowering.png new file mode 100644 index 00000000..f9975552 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/block/green_apple_leaves_flowering.png differ diff --git a/src/main/resources/assets/unicopia/textures/block/sour_apple_leaves_flowering.png b/src/main/resources/assets/unicopia/textures/block/sour_apple_leaves_flowering.png new file mode 100644 index 00000000..f741873e Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/block/sour_apple_leaves_flowering.png differ diff --git a/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves.png b/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves.png index 2f7822b4..46bad15f 100644 Binary files a/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves.png and b/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves.png differ diff --git a/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves_flowering.png b/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves_flowering.png new file mode 100644 index 00000000..c7a3f674 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/block/sweet_apple_leaves_flowering.png differ diff --git a/src/main/resources/data/minecraft/tags/worldgen/biome/is_forest.json b/src/main/resources/data/minecraft/tags/worldgen/biome/is_forest.json new file mode 100644 index 00000000..fec63434 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/worldgen/biome/is_forest.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "unicopia:sweet_apple_orchard" + ] +} diff --git a/src/main/resources/data/unicopia/recipes/spells/mimic.json b/src/main/resources/data/unicopia/recipes/spells/mimic.json index eca1681a..546c0908 100644 --- a/src/main/resources/data/unicopia/recipes/spells/mimic.json +++ b/src/main/resources/data/unicopia/recipes/spells/mimic.json @@ -4,7 +4,9 @@ "traits": { "knowledge": 19, "life": 10, "chaos": 4 }, - "ingredients": [], + "ingredients": [ + { "item": "unicopia:gemstone", "spell": "unicopia:transformation" } + ], "result": { "item": "unicopia:gemstone", "spell": "unicopia:mimic" diff --git a/src/main/resources/data/unicopia/worldgen/biome/sweet_apple_orchard.json b/src/main/resources/data/unicopia/worldgen/biome/sweet_apple_orchard.json new file mode 100644 index 00000000..f9a23e67 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/biome/sweet_apple_orchard.json @@ -0,0 +1,199 @@ +{ + "carvers": { + "air": [ + "minecraft:cave", + "minecraft:cave_extra_underground", + "minecraft:canyon" + ] + }, + "downfall": 0.8, + "effects": { + "fog_color": 12638463, + "mood_sound": { + "block_search_extent": 8, + "offset": 2.0, + "sound": "minecraft:ambient.cave", + "tick_delay": 6000 + }, + "music": { + "max_delay": 24000, + "min_delay": 12000, + "replace_current_music": false, + "sound": "minecraft:music.overworld.forest" + }, + "sky_color": 7972607, + "water_color": 4159204, + "water_fog_color": 329011 + }, + "features": [ + [], + [ + "minecraft:lake_lava_underground", + "minecraft:lake_lava_surface" + ], + [ + "minecraft:amethyst_geode" + ], + [ + "minecraft:monster_room", + "minecraft:monster_room_deep" + ], + [], + [], + [ + "minecraft:ore_dirt", + "minecraft:ore_gravel", + "minecraft:ore_granite_upper", + "minecraft:ore_granite_lower", + "minecraft:ore_diorite_upper", + "minecraft:ore_diorite_lower", + "minecraft:ore_andesite_upper", + "minecraft:ore_andesite_lower", + "minecraft:ore_tuff", + "minecraft:ore_coal_upper", + "minecraft:ore_coal_lower", + "minecraft:ore_iron_upper", + "minecraft:ore_iron_middle", + "minecraft:ore_iron_small", + "minecraft:ore_gold", + "minecraft:ore_gold_lower", + "minecraft:ore_redstone", + "minecraft:ore_redstone_lower", + "minecraft:ore_diamond", + "minecraft:ore_diamond_large", + "minecraft:ore_diamond_buried", + "minecraft:ore_lapis", + "minecraft:ore_lapis_buried", + "minecraft:ore_copper", + "minecraft:underwater_magma", + "minecraft:disk_sand", + "minecraft:disk_clay", + "minecraft:disk_gravel" + ], + [], + [ + "minecraft:spring_water", + "minecraft:spring_lava" + ], + [ + "minecraft:glow_lichen", + "minecraft:forest_flowers", + "minecraft:flower_default", + "minecraft:patch_grass_forest", + "minecraft:brown_mushroom_normal", + "minecraft:red_mushroom_normal", + "minecraft:patch_sugar_cane", + "minecraft:patch_pumpkin" + ], + [ + "minecraft:freeze_top_layer" + ] + ], + "has_precipitation": true, + "spawn_costs": {}, + "spawners": { + "ambient": [ + { + "type": "minecraft:bat", + "maxCount": 8, + "minCount": 8, + "weight": 10 + } + ], + "axolotls": [], + "creature": [ + { + "type": "minecraft:sheep", + "maxCount": 4, + "minCount": 4, + "weight": 12 + }, + { + "type": "minecraft:pig", + "maxCount": 4, + "minCount": 4, + "weight": 10 + }, + { + "type": "minecraft:chicken", + "maxCount": 4, + "minCount": 4, + "weight": 10 + }, + { + "type": "minecraft:cow", + "maxCount": 4, + "minCount": 4, + "weight": 8 + }, + { + "type": "minecraft:wolf", + "maxCount": 4, + "minCount": 4, + "weight": 5 + } + ], + "misc": [], + "monster": [ + { + "type": "minecraft:spider", + "maxCount": 4, + "minCount": 4, + "weight": 100 + }, + { + "type": "minecraft:zombie", + "maxCount": 4, + "minCount": 4, + "weight": 95 + }, + { + "type": "minecraft:zombie_villager", + "maxCount": 1, + "minCount": 1, + "weight": 5 + }, + { + "type": "minecraft:skeleton", + "maxCount": 4, + "minCount": 4, + "weight": 100 + }, + { + "type": "minecraft:creeper", + "maxCount": 4, + "minCount": 4, + "weight": 100 + }, + { + "type": "minecraft:slime", + "maxCount": 4, + "minCount": 4, + "weight": 100 + }, + { + "type": "minecraft:enderman", + "maxCount": 4, + "minCount": 1, + "weight": 10 + }, + { + "type": "minecraft:witch", + "maxCount": 1, + "minCount": 1, + "weight": 5 + } + ], + "underground_water_creature": [ + { + "type": "minecraft:glow_squid", + "maxCount": 6, + "minCount": 4, + "weight": 10 + } + ], + "water_ambient": [], + "water_creature": [] + }, + "temperature": 0.8 +} \ No newline at end of file diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index dc5da585..549625a7 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -20,6 +20,7 @@ "MixinEnchantmentHelper", "MixinFallLocation", "MixinEntity", + "MixinEntityView", "MixinEntityShapeContext", "MixinFallingBlock", "MixinFallingBlockEntity", @@ -48,6 +49,7 @@ "MixinStateManagerBuilder", "MixinBlockState", "MixinTargetPredicate", + "MixinVanillaBiomeParameters", "MixinWardenEntity", "MixinWorld", "MixinWorldChunk", @@ -56,7 +58,8 @@ "trinkets.MixinTrinketInventory", "trinkets.MixinScreenHandler", "seasons.MixinFertilizableUtil", - "ad_astra.MixinOxygenUtils" + "ad_astra.MixinOxygenUtils", + "forgified.MixinIForgeBoat" ], "client": [ "client.MixinAnimalModel",