mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +01:00
Merge branch '1.20.2' into 1.20.4
# Conflicts: # gradle.properties # src/main/java/com/minelittlepony/unicopia/server/world/Tree.java
This commit is contained in:
commit
b28c89e202
38 changed files with 826 additions and 86 deletions
19
build.gradle
19
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 {
|
||||
|
|
|
@ -15,7 +15,7 @@ org.gradle.daemon=false
|
|||
description=Magical Abilities for Mine Little Pony!
|
||||
|
||||
# Publishing
|
||||
minecraft_version_range=>=1.20.3
|
||||
minecraft_version_range=1.20.4
|
||||
modrinth_loader_type=fabric
|
||||
modrinth_project_id=9K7RJlvM
|
||||
|
||||
|
@ -24,10 +24,19 @@ org.gradle.daemon=false
|
|||
modmenu_version=9.0.0-pre.1
|
||||
minelp_version=4.11.5+1.20.2
|
||||
kirin_version=1.17.0+1.20.4
|
||||
reach_attributes_version=2.4.1
|
||||
reach_attributes_version=2.4.2
|
||||
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.29+1.20.4
|
||||
|
|
Binary file not shown.
BIN
lib/reach-entity-attributes-2.4.2-sources.jar
Normal file
BIN
lib/reach-entity-attributes-2.4.2-sources.jar
Normal file
Binary file not shown.
Binary file not shown.
|
@ -48,6 +48,9 @@ public class Config extends com.minelittlepony.common.util.settings.Config {
|
|||
public final Setting<Boolean> simplifiedPortals = value("compatibility", "simplifiedPortals", false)
|
||||
.addComment("Disables dynamic portal rendering");
|
||||
|
||||
public final Setting<Boolean> disableShaders = value("compatibility", "disableShaders", false)
|
||||
.addComment("Disables post-effect shaders used by the corruption mechanic");
|
||||
|
||||
public final Setting<Long> fancyPortalRefreshRate = value("client", "fancyPortalRefreshRate", -1L)
|
||||
.addComment("Sets the refresh rate of portals when using fancy portal rendering")
|
||||
.addComment("Set to -1 (default) for unlimited");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,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();
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,14 +42,24 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable
|
|||
}
|
||||
|
||||
public void loadShader(@Nullable Identifier shaderId) {
|
||||
|
||||
if (shader != null) {
|
||||
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();
|
||||
|
|
|
@ -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<VoxelShape> getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box) {
|
||||
public static List<VoxelShape> 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 -> {
|
||||
|
|
|
@ -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<Fluid> redirectFluidTag() {
|
||||
return isLavaAffine() ? FluidTags.LAVA : FluidTags.WATER;
|
||||
|
|
|
@ -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<List<VoxelShape>> info) {
|
||||
if (box.getAverageSideLength() < 1.0E-7D) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<VoxelShape> shapes = EntityCollisions.getColissonShapes(entity, (EntityView)this, box);
|
||||
if (!shapes.isEmpty()) {
|
||||
info.setReturnValue(Stream.concat(shapes.stream(), info.getReturnValue().stream()).toList());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Pair<MultiNoiseUtil.NoiseHypercube, RegistryKey<Biome>>> onWriteOverworldBiomeParameters(Consumer<Pair<MultiNoiseUtil.NoiseHypercube, RegistryKey<Biome>>> parametersCollector) {
|
||||
return new BiomeSelectionInjector(parametersCollector);
|
||||
}
|
||||
}
|
|
@ -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<VoxelShape> getEntityCollisions(@Nullable Entity entity, Box box) {
|
||||
if (box.getAverageSideLength() >= 1.0E-7D) {
|
||||
List<VoxelShape> 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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
@ -15,10 +16,11 @@ import net.minecraft.item.*;
|
|||
import net.minecraft.util.Identifier;
|
||||
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;
|
||||
|
@ -27,9 +29,8 @@ public record Tree (
|
|||
Identifier id,
|
||||
TreeFeatureConfig.Builder config,
|
||||
RegistryKey<ConfiguredFeature<?, ?>> configuredFeatureId,
|
||||
Optional<RegistryKey<PlacedFeature>> placedFeatureId,
|
||||
Optional<Block> sapling,
|
||||
Optional<PlacementModifier> placement
|
||||
Set<Placement> placements,
|
||||
Optional<Block> sapling
|
||||
) {
|
||||
public static final List<Tree> REGISTRY = new ArrayList<>();
|
||||
|
||||
|
@ -42,20 +43,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<BiomeSelectionContext> IS_FOREST = BiomeSelectors.foundInOverworld().and(BiomeSelectors.tag(BiomeTags.IS_FOREST));
|
||||
public static final Predicate<BiomeSelectionContext> 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);
|
||||
|
@ -71,8 +74,7 @@ public record Tree (
|
|||
|
||||
private final Identifier id;
|
||||
|
||||
private Optional<Predicate<BiomeSelectionContext>> selector = Optional.empty();
|
||||
private Optional<PlacementModifier> countModifier = Optional.empty();
|
||||
private Map<Identifier, Placement> placements = new HashMap<>();
|
||||
private Function<TreeFeatureConfig.Builder, TreeFeatureConfig.Builder> configParameters = Function.identity();
|
||||
private Optional<TwoLayersFeatureSize> size = Optional.empty();
|
||||
|
||||
|
@ -102,13 +104,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<BiomeSelectionContext> selector) {
|
||||
return placement("", count, extraChance, extraCount, selector);
|
||||
}
|
||||
|
||||
public Builder biomes(Predicate<BiomeSelectionContext> selector) {
|
||||
this.selector = Optional.of(selector);
|
||||
public Builder placement(String suffex, int count, float extraChance, int extraCount, Predicate<BiomeSelectionContext> 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;
|
||||
}
|
||||
|
||||
|
@ -117,7 +124,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;
|
||||
}
|
||||
|
@ -130,18 +137,23 @@ public record Tree (
|
|||
BlockStateProvider.of(leavesType),
|
||||
foliagePlacer,
|
||||
size.get()
|
||||
)), configuredFeatureId, selector.map(selector -> {
|
||||
RegistryKey<PlacedFeature> 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("dark_oak", Optional.of(configuredFeatureId), Optional.empty(), Optional.empty()), FabricBlockSettings.copy(Blocks.OAK_SAPLING)), ItemGroups.NATURAL)), countModifier);
|
||||
)), configuredFeatureId, placements.values().stream()
|
||||
.collect(Collectors.toUnmodifiableSet()),
|
||||
saplingId.map(id -> UBlocks.register(id, saplingConstructor.apply(new SaplingGenerator(id.toString(), Optional.of(configuredFeatureId), Optional.empty(), Optional.empty()), 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<PlacedFeature> feature, Predicate<BiomeSelectionContext> selector) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Biome> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Biome> biomeKey();
|
||||
|
||||
SplittableBiomeCoordinate referenceFrame();
|
||||
|
||||
@Nullable
|
||||
RegistryKey<Biome> addOverride(SplittableBiomeCoordinate coordinate, RegistryKey<Biome> 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);
|
||||
}
|
||||
}
|
|
@ -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<Pair<MultiNoiseUtil.NoiseHypercube, RegistryKey<Biome>>> {
|
||||
|
||||
private final Consumer<Pair<MultiNoiseUtil.NoiseHypercube, RegistryKey<Biome>>> parameterConsumer;
|
||||
|
||||
public BiomeSelectionInjector(Consumer<Pair<MultiNoiseUtil.NoiseHypercube, RegistryKey<Biome>>> parameterConsumer) {
|
||||
this.parameterConsumer = parameterConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Pair<NoiseHypercube, RegistryKey<Biome>> parameter) {
|
||||
Context context = new Context(parameter);
|
||||
OverworldBiomeSelectionCallback.EVENT.invoker().onSelectingBiome(context);
|
||||
if (!context.overrides.isEmpty()) {
|
||||
List<Pair<NoiseHypercube, RegistryKey<Biome>>> subSections = List.of(parameter);
|
||||
// sort splits from largest to smallest
|
||||
var divisions = context.overrides.entrySet()
|
||||
.stream()
|
||||
.sorted(Comparator.<Map.Entry<SplittableBiomeCoordinate, RegistryKey<Biome>>, 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<SplittableBiomeCoordinate, RegistryKey<Biome>> 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<NoiseHypercube, RegistryKey<Biome>> parameter;
|
||||
private final Map<SplittableBiomeCoordinate, RegistryKey<Biome>> overrides = new LinkedHashMap<>();
|
||||
|
||||
public Context(Pair<NoiseHypercube, RegistryKey<Biome>> parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryKey<Biome> biomeKey() {
|
||||
return parameter.getSecond();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SplittableBiomeCoordinate referenceFrame() {
|
||||
return createStart(parameter.getFirst());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RegistryKey<Biome> addOverride(SplittableBiomeCoordinate coordinate, RegistryKey<Biome> 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<SplittableBiomeCoordinate, SplitableParameterRange> dimension;
|
||||
private float min;
|
||||
private float max;
|
||||
|
||||
SplitableParameterRangeImpl(SplittableBiomeCoordinate[] coordinate, SplitableParameterRangeImpl original) {
|
||||
this(coordinate, original.dimension, original.min, original.max);
|
||||
}
|
||||
|
||||
SplitableParameterRangeImpl(SplittableBiomeCoordinate[] coordinate, Function<SplittableBiomeCoordinate, SplitableParameterRange> 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<SplitableParameterRangeImpl> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Vector2i, Pair<FruitBearingBlock, Integer>> 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));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
* <p>
|
||||
* 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<OverworldBiomeSelectionCallback> EVENT = EventFactory.createArrayBacked(OverworldBiomeSelectionCallback.class, delegates -> {
|
||||
return context -> {
|
||||
for (OverworldBiomeSelectionCallback delegate : delegates) {
|
||||
delegate.onSelectingBiome(context);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
void onSelectingBiome(BiomeSelectionContext context);
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 забыл, что умеет летать, и упал с лозы",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"unicopia:sweet_apple_orchard"
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue