From 858adfe866dcbf80d2ee8087d6e7fdf5090464c7 Mon Sep 17 00:00:00 2001 From: Christian Bergschneider Date: Tue, 3 Jun 2025 22:41:31 +0200 Subject: [PATCH] feat: initial custom biome implementation --- .../terra/minestom/TerraMinestomPlatform.java | 26 +++- .../terra/minestom/addon/MinestomAddon.java | 47 ++++++ .../terra/minestom/biome/BiomeFactory.java | 9 ++ .../biome/MinestomCustomBiomeFactory.java | 73 +++++++++ .../biome/MinestomCustomBiomePool.java | 39 +++++ .../terra/minestom/biome/NativeBiome.java | 9 ++ .../config/BiomeAdditionsSoundTemplate.java | 24 +++ .../config/BiomeMoodSoundTemplate.java | 37 +++++ .../config/BiomeParticleConfigTemplate.java | 30 ++++ .../terra/minestom/config/KeyLoader.java | 32 ++++ .../terra/minestom/config/RGBLikeLoader.java | 30 ++++ .../minestom/config/SoundEventTemplate.java | 28 ++++ .../config/VanillaBiomeProperties.java | 140 ++++++++++++++++++ .../world/MinestomChunkGeneratorWrapper.java | 51 +++---- .../minestom/world/TerraMinestomWorld.java | 14 +- .../world/TerraMinestomWorldBuilder.java | 10 +- 16 files changed, 570 insertions(+), 29 deletions(-) create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/addon/MinestomAddon.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/BiomeFactory.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomeFactory.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomePool.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/NativeBiome.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeAdditionsSoundTemplate.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeMoodSoundTemplate.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeParticleConfigTemplate.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/KeyLoader.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/RGBLikeLoader.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/SoundEventTemplate.java create mode 100644 platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/VanillaBiomeProperties.java diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomPlatform.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomPlatform.java index bce7fe270..c699ff353 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomPlatform.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomPlatform.java @@ -4,13 +4,21 @@ import com.dfsek.tectonic.api.TypeRegistry; import com.dfsek.tectonic.api.loader.type.TypeLoader; import com.dfsek.terra.AbstractPlatform; +import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.entity.EntityType; import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.WorldHandle; import com.dfsek.terra.api.world.biome.PlatformBiome; +import com.dfsek.terra.minestom.addon.MinestomAddon; +import com.dfsek.terra.minestom.config.BiomeAdditionsSoundTemplate; +import com.dfsek.terra.minestom.config.BiomeParticleConfigTemplate; import com.dfsek.terra.minestom.biome.MinestomBiomeLoader; +import com.dfsek.terra.minestom.config.KeyLoader; +import com.dfsek.terra.minestom.config.BiomeMoodSoundTemplate; +import com.dfsek.terra.minestom.config.RGBLikeLoader; +import com.dfsek.terra.minestom.config.SoundEventTemplate; import com.dfsek.terra.minestom.entity.MinestomEntityType; import com.dfsek.terra.minestom.item.MinestomItemHandle; import com.dfsek.terra.minestom.world.MinestomChunkGeneratorWrapper; @@ -18,13 +26,18 @@ import com.dfsek.terra.minestom.world.MinestomWorldHandle; import com.dfsek.terra.minestom.world.TerraMinestomWorldBuilder; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.util.RGBLike; import net.minestom.server.MinecraftServer; import net.minestom.server.instance.Instance; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.world.biome.BiomeEffects; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.util.List; public final class TerraMinestomPlatform extends AbstractPlatform { @@ -50,8 +63,14 @@ public final class TerraMinestomPlatform extends AbstractPlatform { super.register(registry); registry .registerLoader(PlatformBiome.class, biomeTypeLoader) + .registerLoader(RGBLike.class, new RGBLikeLoader()) + .registerLoader(Key.class, new KeyLoader()) .registerLoader(EntityType.class, (TypeLoader) (annotatedType, o, configLoader, depthTracker) -> new MinestomEntityType((String) o)) - .registerLoader(BlockState.class, (TypeLoader) (annotatedType, o, configLoader, depthTracker) -> worldHandle.createBlockState((String) o)); + .registerLoader(BlockState.class, (TypeLoader) (annotatedType, o, configLoader, depthTracker) -> worldHandle.createBlockState((String) o)) + .registerLoader(BiomeEffects.Particle.class, BiomeParticleConfigTemplate::new) + .registerLoader(BiomeEffects.MoodSound.class, BiomeMoodSoundTemplate::new) + .registerLoader(BiomeEffects.AdditionsSound.class, BiomeAdditionsSoundTemplate::new) + .registerLoader(SoundEvent.class, SoundEventTemplate::new); } @Override @@ -103,4 +122,9 @@ public final class TerraMinestomPlatform extends AbstractPlatform { public TerraMinestomWorldBuilder worldBuilder() { return new TerraMinestomWorldBuilder(this, MinecraftServer.getInstanceManager().createInstanceContainer()); } + + @Override + protected Iterable platformAddon() { + return List.of(new MinestomAddon(this)); + } } \ No newline at end of file diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/addon/MinestomAddon.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/addon/MinestomAddon.java new file mode 100644 index 000000000..4d4adc4b8 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/addon/MinestomAddon.java @@ -0,0 +1,47 @@ +package com.dfsek.terra.minestom.addon; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.version.Version; + +import com.dfsek.terra.api.addon.BaseAddon; + +import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.world.biome.Biome; + +import com.dfsek.terra.minestom.TerraMinestomPlatform; + +import com.dfsek.terra.minestom.config.VanillaBiomeProperties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class MinestomAddon implements BaseAddon { + private static final Version VERSION = Versions.getVersion(1, 0, 0); + private static final Logger logger = LoggerFactory.getLogger(MinestomAddon.class); + private final TerraMinestomPlatform minestomPlatform; + + public MinestomAddon(TerraMinestomPlatform minestomPlatform) { + this.minestomPlatform = minestomPlatform; + } + + @Override + public void initialize() { + minestomPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigurationLoadEvent.class) + .then(event -> { + if(event.is(Biome.class)) { + event.getLoadedObject(Biome.class).getContext().put(event.load(new VanillaBiomeProperties())); + } + }) + .global(); + } + + @Override + public Version getVersion() { return VERSION; } + + @Override + public String getID() { return "terra-minestom"; } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/BiomeFactory.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/BiomeFactory.java new file mode 100644 index 000000000..832305e3a --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/BiomeFactory.java @@ -0,0 +1,9 @@ +package com.dfsek.terra.minestom.biome; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.Biome; + + +public interface BiomeFactory { + NativeBiome create(ConfigPack pack, Biome source); +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomeFactory.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomeFactory.java new file mode 100644 index 000000000..f33c5c9a2 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomeFactory.java @@ -0,0 +1,73 @@ +package com.dfsek.terra.minestom.biome; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.registry.key.RegistryKey; +import com.dfsek.terra.minestom.config.VanillaBiomeProperties; + +import net.kyori.adventure.key.Key; +import net.minestom.server.MinecraftServer; +import net.minestom.server.color.Color; +import net.minestom.server.registry.DynamicRegistry; +import net.minestom.server.world.biome.Biome; +import net.minestom.server.world.biome.BiomeEffects; +import org.intellij.lang.annotations.Subst; +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; +import java.util.Objects; + + +public class MinestomCustomBiomeFactory implements BiomeFactory { + private final DynamicRegistry biomeRegistry = MinecraftServer.getBiomeRegistry(); + private final @NotNull Biome plainsBiome = Objects.requireNonNull(biomeRegistry.get(Key.key("minecraft:plains"))); + + @Override + public NativeBiome create(ConfigPack pack, com.dfsek.terra.api.world.biome.Biome source) { + VanillaBiomeProperties properties = source.getContext().get(VanillaBiomeProperties.class); + DynamicRegistry.Key parentKey = ((MinestomBiome) source.getPlatformBiome()).getHandle(); + Biome parent = mergeNullable(biomeRegistry.get(parentKey), plainsBiome); + BiomeEffects parentEffects = parent.effects(); + Key key = Key.key("terra", createBiomeID(pack, source.getID())); + + BiomeEffects.Builder effectsBuilder = BiomeEffects.builder() + .fogColor(mergeNullable(properties.getFogColor(), parentEffects.fogColor())) + .skyColor(mergeNullable(properties.getSkyColor(), parentEffects.skyColor())) + .waterColor(mergeNullable(properties.getWaterColor(), parentEffects.waterColor())) + .waterFogColor(mergeNullable(properties.getWaterFogColor(), parentEffects.waterFogColor())) + .foliageColor(mergeNullable(properties.getFoliageColor(), parentEffects.foliageColor())) + .grassColor(mergeNullable(properties.getGrassColor(), parentEffects.grassColor())) + .grassColorModifier(mergeNullable(properties.getGrassColorModifier(), parentEffects.grassColorModifier())) + .biomeParticle(mergeNullable(properties.getParticleConfig(), parentEffects.biomeParticle())) + .ambientSound(mergeNullable(properties.getLoopSound(), parentEffects.ambientSound())) + .moodSound(mergeNullable(properties.getMoodSound(), parentEffects.moodSound())) + .additionsSound(mergeNullable(properties.getAdditionsSound(), parentEffects.additionsSound())) + // TODO music + .music(parentEffects.music()) + .musicVolume(parentEffects.musicVolume()); + + if (effectsBuilder.build().equals(BiomeEffects.PLAINS_EFFECTS)) { + effectsBuilder.fogColor(new Color(0xC0D8FE)); // circumvent a minestom bug + } + + Biome target = Biome.builder() + .downfall(mergeNullable(properties.getDownfall(), parent.downfall())) + .hasPrecipitation(mergeNullable(properties.getPrecipitation(), parent.hasPrecipitation())) + .temperature(mergeNullable(properties.getTemperature(), parent.temperature())) + .temperatureModifier(mergeNullable(properties.getTemperatureModifier(), parent.temperatureModifier())) + .effects(effectsBuilder.build()) + .build(); + + DynamicRegistry.Key registryKey = MinecraftServer.getBiomeRegistry().register(key, target); + return new NativeBiome(key, registryKey, source.getID(), target); + } + + private static T mergeNullable(T first, T second) { + if (first == null) return second; + return first; + } + + @Subst("value") + protected static String createBiomeID(ConfigPack pack, String biomeId) { + return pack.getID().toLowerCase() + "/" + biomeId.toLowerCase(Locale.ROOT); + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomePool.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomePool.java new file mode 100644 index 000000000..db0e48be6 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/MinestomCustomBiomePool.java @@ -0,0 +1,39 @@ +package com.dfsek.terra.minestom.biome; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.Biome; + +import java.util.HashMap; + + +public class MinestomCustomBiomePool { + private final HashMap biomes = new HashMap<>(); + private final MinestomCustomBiomeFactory factory; + private final ConfigPack configPack; + + public MinestomCustomBiomePool(ConfigPack configPack, MinestomCustomBiomeFactory factory) { + this.configPack = configPack; + this.factory = factory; + } + + public NativeBiome getBiome(Biome source) { + NativeBiome nativeBiome = biomes.get(source.getID()); + if(nativeBiome != null) return nativeBiome; + nativeBiome = factory.create(configPack, source); + biomes.put(source.getID(), nativeBiome); + return nativeBiome; + } + + public void preloadBiomes(Iterable biomesToLoad) { + biomesToLoad + .forEach(biome -> { + if(!this.biomes.containsKey(biome.getID())) { + this.biomes.put(biome.getID(), factory.create(configPack, biome)); + } + }); + } + + public void invalidate() { + biomes.clear(); + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/NativeBiome.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/NativeBiome.java new file mode 100644 index 000000000..e01728b7d --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/biome/NativeBiome.java @@ -0,0 +1,9 @@ +package com.dfsek.terra.minestom.biome; + +import net.kyori.adventure.key.Key; +import net.minestom.server.registry.DynamicRegistry; +import net.minestom.server.world.biome.Biome; + + +public record NativeBiome(Key key, DynamicRegistry.Key registry, String id, Biome biome) { +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeAdditionsSoundTemplate.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeAdditionsSoundTemplate.java new file mode 100644 index 000000000..85e4499fc --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeAdditionsSoundTemplate.java @@ -0,0 +1,24 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.world.biome.BiomeEffects; + + +public class BiomeAdditionsSoundTemplate implements ObjectTemplate { + @Value("sound") + @Default + private SoundEvent sound = null; + + @Value("sound-chance") + @Default + private Double soundChance = null; + + @Override + public BiomeEffects.AdditionsSound get() { + if(sound == null) return null; + return new BiomeEffects.AdditionsSound(sound, soundChance); + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeMoodSoundTemplate.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeMoodSoundTemplate.java new file mode 100644 index 000000000..a3b7bb3c8 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeMoodSoundTemplate.java @@ -0,0 +1,37 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.world.biome.BiomeEffects; + + +public class BiomeMoodSoundTemplate implements ObjectTemplate { + @Value("sound") + @Default + private SoundEvent sound = null; + + @Value("cultivation-ticks") + @Default + private Integer soundCultivationTicks = null; + + @Value("spawn-range") + @Default + private Integer soundSpawnRange = null; + + @Value("extra-distance") + @Default + private Double soundExtraDistance = null; + + @Override + public BiomeEffects.MoodSound get() { + if(sound == null) return null; + return new BiomeEffects.MoodSound( + sound, + soundCultivationTicks, + soundSpawnRange, + soundExtraDistance + ); + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeParticleConfigTemplate.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeParticleConfigTemplate.java new file mode 100644 index 000000000..c095b7893 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/BiomeParticleConfigTemplate.java @@ -0,0 +1,30 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.minestom.server.particle.Particle; +import net.minestom.server.world.biome.BiomeEffects; + + +public class BiomeParticleConfigTemplate implements ObjectTemplate { + @Value("particle") + @Default + private String particle = null; + + @Value("probability") + @Default + private Float probability = null; + + @Override + public BiomeEffects.Particle get() { + if(particle == null || probability == null) { + return null; + } + + return new BiomeEffects.Particle( + probability, + Particle.fromKey(particle) + ); + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/KeyLoader.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/KeyLoader.java new file mode 100644 index 000000000..406e64674 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/KeyLoader.java @@ -0,0 +1,32 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; +import com.dfsek.tectonic.api.loader.ConfigLoader; +import com.dfsek.tectonic.api.loader.type.TypeLoader; +import net.kyori.adventure.key.InvalidKeyException; +import net.kyori.adventure.key.Key; +import org.intellij.lang.annotations.Subst; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.AnnotatedType; + + +public class KeyLoader implements TypeLoader { + @Override + public Key load( + @NotNull AnnotatedType annotatedType, + @NotNull Object o, + @NotNull ConfigLoader configLoader, + DepthTracker depthTracker + ) throws LoadException { + if(!(o instanceof @Subst("a:o") String stringKey)) { + throw new LoadException("Value is not a String", depthTracker); + } + try { + return Key.key(stringKey); + } catch(InvalidKeyException e) { + throw new LoadException("Can't load key: Invalid Format", e, depthTracker); + } + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/RGBLikeLoader.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/RGBLikeLoader.java new file mode 100644 index 000000000..de998edb5 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/RGBLikeLoader.java @@ -0,0 +1,30 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; +import com.dfsek.tectonic.api.loader.ConfigLoader; +import com.dfsek.tectonic.api.loader.type.TypeLoader; +import net.kyori.adventure.key.InvalidKeyException; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.util.RGBLike; +import net.minestom.server.color.Color; +import org.intellij.lang.annotations.Subst; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.AnnotatedType; + + +public class RGBLikeLoader implements TypeLoader { + @Override + public RGBLike load( + @NotNull AnnotatedType annotatedType, + @NotNull Object o, + @NotNull ConfigLoader configLoader, + DepthTracker depthTracker + ) throws LoadException { + if(!(o instanceof @Subst("a:o") Integer value)) { + throw new LoadException("Value is not an integer", depthTracker); + } + return new Color(value); + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/SoundEventTemplate.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/SoundEventTemplate.java new file mode 100644 index 000000000..c8bd81a13 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/SoundEventTemplate.java @@ -0,0 +1,28 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; +import net.kyori.adventure.key.Key; +import net.minestom.server.sound.SoundEvent; + + +public class SoundEventTemplate implements ObjectTemplate { + @Value("id") + @Default + private Key id = null; + + @Value("distance-to-travel") + @Default + private Float distanceToTravel = null; + + @Override + public SoundEvent get() { + if(id == null) { + return null; + } else { + // distanceToTravel is specifically allowed to be null. + return SoundEvent.of(id, distanceToTravel); + } + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/VanillaBiomeProperties.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/VanillaBiomeProperties.java new file mode 100644 index 000000000..ea82cd7e2 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/config/VanillaBiomeProperties.java @@ -0,0 +1,140 @@ +package com.dfsek.terra.minestom.config; + +import com.dfsek.tectonic.api.config.template.ConfigTemplate; +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; + +import com.dfsek.terra.api.properties.Properties; + +import net.kyori.adventure.util.RGBLike; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.world.biome.Biome.TemperatureModifier; +import net.minestom.server.world.biome.BiomeEffects; +import net.minestom.server.world.biome.BiomeEffects.GrassColorModifier; + + +public class VanillaBiomeProperties implements ConfigTemplate, Properties { + @Value("colors.grass") + @Default + private RGBLike grassColor = null; + + @Value("colors.fog") + @Default + private RGBLike fogColor = null; + + @Value("colors.water") + @Default + private RGBLike waterColor = null; + + @Value("colors.water-fog") + @Default + private RGBLike waterFogColor = null; + + @Value("colors.foliage") + @Default + private RGBLike foliageColor = null; + + @Value("colors.sky") + @Default + private RGBLike skyColor = null; + + @Value("colors.modifier") + @Default + private GrassColorModifier grassColorModifier = null; + + @Value("particles") + @Default + private BiomeEffects.Particle particleConfig = null; + + @Value("climate.precipitation") + @Default + private Boolean precipitation = null; + + @Value("climate.temperature") + @Default + private Float temperature = null; + + @Value("climate.temperature-modifier") + @Default + private TemperatureModifier temperatureModifier = null; + + @Value("climate.downfall") + @Default + private Float downfall = null; + + @Value("sound.loop-sound.sound") + @Default + private SoundEvent loopSound = null; + + @Value("sound.mood-sound") + @Default + private BiomeEffects.MoodSound moodSound = null; + + @Value("sound.additions-sound") + @Default + private BiomeEffects.AdditionsSound additionsSound = null; + +// @Value("sound.music") +// @Default +// private MusicSound music = null; + + public RGBLike getGrassColor() { + return grassColor; + } + + public RGBLike getFogColor() { + return fogColor; + } + + public RGBLike getWaterColor() { + return waterColor; + } + + public RGBLike getWaterFogColor() { + return waterFogColor; + } + + public RGBLike getFoliageColor() { + return foliageColor; + } + + public RGBLike getSkyColor() { + return skyColor; + } + + public GrassColorModifier getGrassColorModifier() { + return grassColorModifier; + } + + public BiomeEffects.Particle getParticleConfig() { + return particleConfig; + } + + public Boolean getPrecipitation() { + return precipitation; + } + + public Float getTemperature() { + return temperature; + } + + public TemperatureModifier getTemperatureModifier() { + return temperatureModifier; + } + + public Float getDownfall() { + return downfall; + } + + public SoundEvent getLoopSound() { + return loopSound; + } + + public BiomeEffects.MoodSound getMoodSound() { + return moodSound; + } + + public BiomeEffects.AdditionsSound getAdditionsSound() { + return additionsSound; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java index f3829a65a..c3eba7b34 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java @@ -2,25 +2,25 @@ package com.dfsek.terra.minestom.world; import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage; import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; -import com.dfsek.terra.minestom.biome.MinestomBiome; +import com.dfsek.terra.minestom.biome.MinestomCustomBiomeFactory; +import com.dfsek.terra.minestom.biome.MinestomCustomBiomePool; +import com.dfsek.terra.minestom.biome.NativeBiome; import com.dfsek.terra.minestom.chunk.CachedChunk; import com.dfsek.terra.minestom.chunk.GeneratedChunkCache; +import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; +import net.minestom.server.entity.Player; import net.minestom.server.instance.generator.GenerationUnit; import net.minestom.server.instance.generator.Generator; import net.minestom.server.instance.generator.UnitModifier; -import net.minestom.server.registry.DynamicRegistry; import org.jetbrains.annotations.NotNull; -import java.util.Objects; - public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrapper { private final GeneratedChunkCache cache; @@ -28,14 +28,22 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe private final TerraMinestomWorld world; private final BiomeProvider biomeProvider; private ConfigPack pack; + private final MinestomCustomBiomePool biomePool; - public MinestomChunkGeneratorWrapper(Platform platform, ChunkGenerator generator, TerraMinestomWorld world, ConfigPack pack) { + public MinestomChunkGeneratorWrapper( + Platform platform, + ChunkGenerator generator, + TerraMinestomWorld world, + ConfigPack pack, + MinestomCustomBiomePool biomePool + ) { this.generator = generator; this.world = world; this.pack = pack; - + this.biomePool = biomePool; biomeProvider = pack.getBiomeProvider().caching(platform); this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world, biomeProvider); + preloadBiomes(); } public ChunkGenerator getGenerator() { @@ -53,30 +61,14 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe UnitModifier modifier = unit.modifier(); chunk.writeRelative(modifier); -// for(int dx = 0; dx < 16; dx++) { -// for(int dz = 0; dz < 16; dz++) { -// int globalX = dx + blockX; -// int globalZ = dz + blockZ; -// biomeProvider.getColumn(globalX, globalZ, world).forEach((y, biome) -> { -// MinestomBiome platformBiome = (MinestomBiome) biome.getPlatformBiome(); -// modifier.setBiome(globalX, 0, globalZ, DynamicRegistry.Key.of("minecraft:the_void")); -// }); -// } -// } + NativeBiome nativeBiome = biomePool.getBiome(biomeProvider.getBiome(blockX, 100, blockZ, world.getSeed())); + modifier.fillBiome(nativeBiome.registry()); unit.fork(setter -> { MinestomProtoWorld protoWorld = new MinestomProtoWorld(cache, x, z, world, setter); - var stages = world.getPack().getStages(); - - if(x==0 && z==0) { - System.out.println(stages); - System.out.println(protoWorld.getBlockState(-4, 73, -6).getAsString()); - } - for(GenerationStage stage : world.getPack().getStages()) { stage.populate(protoWorld); - if(x==0 && z==0) System.out.println(protoWorld.getBlockState(-4, 73, -6).getAsString()); } }); } @@ -88,6 +80,15 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe public void setPack(ConfigPack pack) { this.pack = pack; this.generator = pack.getGeneratorProvider().newInstance(pack); + this.biomePool.invalidate(); + preloadBiomes(); + } + + private void preloadBiomes() { + this.biomePool.preloadBiomes(world.getBiomeProvider().getBiomes()); + for(Player player : MinecraftServer.getConnectionManager().getOnlinePlayers()) { + player.startConfigurationPhase(); + } } public void displayStats() { diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java index 692f96b64..cbc80522a 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java @@ -16,6 +16,9 @@ import com.dfsek.terra.api.world.info.WorldProperties; import com.dfsek.terra.minestom.TerraMinestomPlatform; import com.dfsek.terra.minestom.api.BlockEntityFactory; import com.dfsek.terra.minestom.api.EntityFactory; +import com.dfsek.terra.minestom.biome.BiomeFactory; +import com.dfsek.terra.minestom.biome.MinestomCustomBiomeFactory; +import com.dfsek.terra.minestom.biome.MinestomCustomBiomePool; import com.dfsek.terra.minestom.block.MinestomBlockState; import com.dfsek.terra.minestom.entity.MinestomEntity; @@ -44,7 +47,8 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties { ConfigPack pack, long seed, EntityFactory entityFactory, - BlockEntityFactory blockEntityFactory + BlockEntityFactory blockEntityFactory, + BiomeFactory factory ) { this.instance = instance; this.pack = pack; @@ -53,7 +57,13 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties { this.dimensionType = MinecraftServer.getDimensionTypeRegistry().get(instance.getDimensionType()); this.blockEntityFactory = blockEntityFactory; - this.wrapper = new MinestomChunkGeneratorWrapper(platform, pack.getGeneratorProvider().newInstance(pack), this, pack); + this.wrapper = new MinestomChunkGeneratorWrapper( + platform, + pack.getGeneratorProvider().newInstance(pack), + this, + pack, + new MinestomCustomBiomePool(pack, new MinestomCustomBiomeFactory()) + ); this.entityFactory = entityFactory; instance.setGenerator(this.wrapper); diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java index c68b4b72f..1983bdee9 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java @@ -7,6 +7,8 @@ import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.minestom.TerraMinestomPlatform; import com.dfsek.terra.minestom.api.BlockEntityFactory; import com.dfsek.terra.minestom.api.EntityFactory; +import com.dfsek.terra.minestom.biome.BiomeFactory; +import com.dfsek.terra.minestom.biome.MinestomCustomBiomeFactory; import com.dfsek.terra.minestom.block.DefaultBlockEntityFactory; import com.dfsek.terra.minestom.entity.DefaultEntityFactory; @@ -24,6 +26,7 @@ public class TerraMinestomWorldBuilder { private long seed = new Random().nextLong(); private EntityFactory entityFactory = new DefaultEntityFactory(); private BlockEntityFactory blockEntityFactory = new DefaultBlockEntityFactory(); + private BiomeFactory biomeFactory = new MinestomCustomBiomeFactory(); public TerraMinestomWorldBuilder(TerraMinestomPlatform platform, Instance instance) { this.platform = platform; @@ -65,7 +68,12 @@ public class TerraMinestomWorldBuilder { return this; } + public TerraMinestomWorldBuilder biomeFactory(BiomeFactory factory) { + this.biomeFactory = factory; + return this; + } + public TerraMinestomWorld attach() { - return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory); + return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory, biomeFactory); } }