diff --git a/.gitignore b/.gitignore index c04d0e49..7f78afa0 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ hs_err_pid* .idea/ out/ .gradle/ +.gradel-home/ # Minestom /minecraft_data/ diff --git a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/BedBlockBehaviour.java b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/BedBlockBehaviour.java index 4b1e1586..d2d3494d 100644 --- a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/BedBlockBehaviour.java +++ b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/BedBlockBehaviour.java @@ -4,7 +4,7 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.entity.EntityPose; import net.minestom.server.entity.Player; -import net.minestom.server.entity.metadata.PlayerMeta; +import net.minestom.server.entity.metadata.avatar.PlayerMeta; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; @@ -12,10 +12,14 @@ import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.world.DimensionType; +import net.minestom.server.world.attribute.BedRule; +import net.minestom.server.world.attribute.EnvironmentAttribute; +import net.minestom.server.world.attribute.EnvironmentAttributeMap; import net.minestom.vanilla.blocks.VanillaBlockBehaviour; import net.minestom.vanilla.blocks.VanillaBlocks; import net.minestom.vanilla.instance.VanillaExplosion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @SuppressWarnings("UnstableApiUsage") public class BedBlockBehaviour extends VanillaBlockBehaviour { @@ -76,10 +80,26 @@ public boolean onInteract(@NotNull Interaction interaction) { Instance instance = interaction.getInstance(); Point pos = interaction.getBlockPosition(); Player player = interaction.getPlayer(); + var dimensionKey = instance.getDimensionType(); DimensionType dimension = MinecraftServer.getDimensionTypeRegistry().get(dimensionKey); + if (dimension == null) { + return false; + } + + BedRule bedRule = resolveBedRule(dimension); + if (bedRule == null) { + return false; + } + + // Closest replacement for old dimension.bedWorks(): + // beds "work" if they do not explode in this dimension. + if (!bedRule.explodes()) { + // Optional: only allow actual sleeping when the rule says so + if (bedRule.canSleep() == BedRule.Rule.NEVER) { + return false; + } - if (dimension.bedWorks()) { // TODO: make player sleep // TODO: checks for mobs // TODO: check for day @@ -116,6 +136,21 @@ public boolean onInteract(@NotNull Interaction interaction) { return true; } + @SuppressWarnings("unchecked") + private static @Nullable BedRule resolveBedRule(@NotNull DimensionType dimension) { + EnvironmentAttributeMap.Entry rawEntry = + dimension.attributes().entries().get(EnvironmentAttribute.BED_RULE); + + if (rawEntry == null) { + return null; + } + + EnvironmentAttributeMap.Entry entry = + (EnvironmentAttributeMap.Entry) rawEntry; + + return entry.modifier().modify(null, entry.argument()); + } + @Override public void onDestroy(@NotNull Destroy destroy) { Instance instance = destroy.getInstance(); diff --git a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/EndPortalBlockBehaviour.java b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/EndPortalBlockBehaviour.java index 36f7e919..2d7f5d66 100644 --- a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/EndPortalBlockBehaviour.java +++ b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/EndPortalBlockBehaviour.java @@ -59,7 +59,7 @@ public void onTouch(@NotNull Touch touch) { spawnPoint = new Pos(obsidianPlatformX, yLevel, obsidianPlatformZ); } - if (targetDimension.effects().equals("the_end")) { + if (targetInstance.getDimensionType().equals(DimensionType.THE_END)) { for (int x = -1; x <= 1; x++) { for (int z = -1; z <= 1; z++) { targetInstance.loadChunk(obsidianPlatformX / 16 + x, obsidianPlatformZ / 16 + z); diff --git a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/JukeboxBlockBehaviour.java b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/JukeboxBlockBehaviour.java index 97bd563f..169a5e36 100644 --- a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/JukeboxBlockBehaviour.java +++ b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/JukeboxBlockBehaviour.java @@ -12,7 +12,6 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.jukebox.JukeboxSong; import net.minestom.server.item.ItemStack; -import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.tag.Tag; import net.minestom.server.worldevent.WorldEvent; import net.minestom.vanilla.blocks.VanillaBlockBehaviour; @@ -84,8 +83,8 @@ public boolean onInteract(@NotNull Interaction interaction) { InventoryManipulation.consumeItemIfNotCreative(player, heldItem, hand); - JukeboxSong song = heldItem.get(DataComponents.JUKEBOX_PLAYABLE).holder().resolve(MinecraftServer.getJukeboxSongRegistry()); - DynamicRegistry.Key songKey = MinecraftServer.getJukeboxSongRegistry().getKey(song); + JukeboxSong song = heldItem.get(DataComponents.JUKEBOX_PLAYABLE).resolve(MinecraftServer.getJukeboxSongRegistry()); + net.minestom.server.registry.@Nullable RegistryKey songKey = MinecraftServer.getJukeboxSongRegistry().getKey(song); int songId = MinecraftServer.getJukeboxSongRegistry().getId(songKey); // TODO: Group packet? diff --git a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/NetherPortalBlockBehaviour.java b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/NetherPortalBlockBehaviour.java index ada1be76..a6064cb0 100644 --- a/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/NetherPortalBlockBehaviour.java +++ b/blocks/src/main/java/net/minestom/vanilla/blocks/behaviours/NetherPortalBlockBehaviour.java @@ -141,8 +141,7 @@ private void attemptTeleport(Instance instance, Entity touching, Block block, lo double targetZ = position.z() / 8; var key = instance.getDimensionType(); - DimensionType dimension = MinecraftServer.getDimensionTypeRegistry().get(key); - if (dimension.effects().equals("nether")) { + if (key == DimensionType.THE_NETHER) { targetDimension = MinecraftServer.getDimensionTypeRegistry().get(DimensionType.OVERWORLD); targetX = position.x() * 8; targetZ = position.z() * 8; diff --git a/build.gradle.kts b/build.gradle.kts index d8a207c7..e80b03c9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,24 +2,26 @@ plugins { java `java-library` `maven-publish` - id("com.github.harbby.gradle.serviceloader") version ("1.1.8") - id("io.github.goooler.shadow") version ("8.1.8") + id("com.github.harbby.gradle.serviceloader") version ("1.1.9") + id("com.gradleup.shadow") version "8.3.10" apply false } subprojects { - plugins.apply("java") plugins.apply("java-library") plugins.apply("maven-publish") plugins.apply("com.github.harbby.gradle.serviceloader") - plugins.apply("io.github.goooler.shadow") + plugins.apply("com.gradleup.shadow") group = "net.minestom.vanilla" version = "indev" java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + toolchain { + languageVersion = JavaLanguageVersion.of(25) + } + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 // withJavadocJar() withSourcesJar() @@ -37,6 +39,28 @@ subprojects { gradleVersion = rootProject.gradle.gradleVersion } + tasks.withType().configureEach { + options.release = 25 + } + + tasks.withType().configureEach { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + } + } + + tasks.withType().configureEach { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + } + } + + tasks.withType().configureEach { + javadocTool = javaToolchains.javadocToolFor { + languageVersion = JavaLanguageVersion.of(25) + } + } + repositories { mavenCentral() maven(url = "https://jitpack.io") @@ -44,6 +68,9 @@ subprojects { } dependencies { + testImplementation(platform("org.junit:junit-bom:5.13.4")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } publishing { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 9fd5f82b..7137c037 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -18,6 +18,8 @@ dependencies { api("com.squareup.moshi:moshi:1.14.0") api("com.squareup.moshi:moshi-adapters:1.14.0") + api("it.unimi.dsi:fastutil:8.5.18") + // Tests testImplementation(platform("org.junit:junit-bom:5.9.1")) testImplementation("org.junit.jupiter:junit-jupiter") diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/DatapackLoader.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/DatapackLoader.java index c1f7713d..7627bac2 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/DatapackLoader.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/DatapackLoader.java @@ -129,6 +129,7 @@ public void toJson(@NotNull JsonWriter writer, JsonUtils.SingleOrList value) register(builder, Datapack.Tag.TagValue.ObjectOrTagReference.class, Datapack.Tag.TagValue.ObjectOrTagReference::fromJson); register(builder, Biome.Effects.Particle.Options.class, Biome.Effects.Particle.Options::fromJson); register(builder, Biome.Sound.class, Biome.Sound::fromJson); + register(builder, Biome.Color.class, Biome.Color::fromJson); register(builder, Carver.class, Carver::fromJson); register(builder, FloatProvider.class, FloatProvider::fromJson); register(builder, Biome.CarversList.class, Biome.CarversList::fromJson); diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/dimension/DimensionType.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/dimension/DimensionType.java index da5b233a..912c69bb 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/dimension/DimensionType.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/dimension/DimensionType.java @@ -4,11 +4,9 @@ // { // "ambient_light": 0.0, -// "bed_works": true, // "coordinate_scale": 1.0, // "effects": "minecraft:overworld", // "has_ceiling": false, -// "has_raids": true, // "has_skylight": true, // "height": 384, // "infiniburn": "#minecraft:infiniburn_overworld", @@ -29,21 +27,14 @@ //} public record DimensionType( double ambient_light, - boolean bed_works, double coordinate_scale, - String effects, boolean has_ceiling, - boolean has_raids, boolean has_skylight, int height, String infiniburn, int logical_height, int min_y, int monster_spawn_block_light_limit, - NumberProvider.Int monster_spawn_light_level, - boolean natural, - boolean piglin_safe, - boolean respawn_anchor_works, - boolean ultrawarm + NumberProvider.Int monster_spawn_light_level ) { } diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/LootTable.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/LootTable.java index d4b7e20d..bf832d2b 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/LootTable.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/LootTable.java @@ -44,6 +44,7 @@ static Pool.Entry fromJson(JsonReader reader) throws IOException { case "minecraft:tag" -> Pool.Entry.Tag.class; case "minecraft:loot_table" -> Pool.Entry.LootTableNested.class; case "minecraft:dynamic" -> Pool.Entry.Dynamic.class; + case "minecraft:slots" -> Pool.Entry.Slots.class; case "minecraft:empty" -> Pool.Entry.Empty.class; case "minecraft:group" -> Pool.Entry.Group.class; case "minecraft:alternatives" -> Pool.Entry.Alternatives.class; @@ -183,6 +184,28 @@ public List> apply(Datapack datapack, LootContext context) { } } + /** + * slots -> Provides the items contained within slots selected by a slot source. + * • slot_source: A slot source describing where the items are located. + */ + record Slots(List conditions, + List functions, + NumberProvider weight, + NumberProvider quality, + SlotSource slot_source) implements ItemGenerator { + + @Override + public Key type() { + return Key.key("minecraft:slots"); + } + + @Override + public List> apply(Datapack datapack, LootContext context) { + // TODO: Resolve slot_source against loot context and produce items. + return List.of(List.of()); + } + } + /** * empty -> Provides a loot entry that generates nothing into the loot pool. * • functions: Invokes item functions to the item stack(s). diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/SlotSource.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/SlotSource.java new file mode 100644 index 00000000..4c1b96bc --- /dev/null +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/SlotSource.java @@ -0,0 +1,56 @@ +package net.minestom.vanilla.datapack.loot; + +import com.squareup.moshi.JsonReader; +import net.kyori.adventure.key.Key; +import net.minestom.vanilla.datapack.json.JsonUtils; +import net.minestom.vanilla.datapack.tags.ConditionsFor; + +import java.io.IOException; +import java.util.List; + +/** + * Slot source definitions introduced in datapack version 92.0. + */ +public sealed interface SlotSource { + static SlotSource fromJson(JsonReader reader) throws IOException { + return JsonUtils.typeMap(reader, token -> switch (token) { + case BEGIN_ARRAY -> json -> { + json.beginArray(); + java.util.ArrayList terms = new java.util.ArrayList<>(); + while (json.hasNext()) { + terms.add(fromJson(json)); + } + json.endArray(); + return new Group(List.copyOf(terms)); + }; + case BEGIN_OBJECT -> json -> JsonUtils.unionStringTypeAdapted(json, "type", type -> switch (type) { + case "minecraft:empty" -> Empty.class; + case "minecraft:group" -> Group.class; + case "minecraft:slot_range" -> SlotRange.class; + case "minecraft:contents" -> Contents.class; + case "minecraft:filtered" -> Filtered.class; + case "minecraft:limit_slots" -> LimitSlots.class; + default -> null; + }); + default -> null; + }); + } + + record Empty() implements SlotSource { + } + + record Group(List terms) implements SlotSource { + } + + record SlotRange(String source, String slots) implements SlotSource { + } + + record Contents(Key component, SlotSource slot_source) implements SlotSource { + } + + record Filtered(ConditionsFor.Item item_filter, SlotSource slot_source) implements SlotSource { + } + + record LimitSlots(int limit, SlotSource slot_source) implements SlotSource { + } +} diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltLootFunctions.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltLootFunctions.java index 47de7841..11fd1e0f 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltLootFunctions.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltLootFunctions.java @@ -27,6 +27,7 @@ import net.minestom.vanilla.datapack.loot.NBTPath; import net.minestom.vanilla.datapack.loot.context.LootContext; import net.minestom.vanilla.datapack.number.NumberProvider; +import net.minestom.vanilla.datapack.tags.ConditionsFor; import net.minestom.vanilla.tag.Tags; import net.minestom.vanilla.utils.JavaUtils; import net.minestom.vanilla.utils.MinestomUtils; @@ -38,6 +39,63 @@ @SuppressWarnings("unused") interface InBuiltLootFunctions { + // Replaces any item stack with empty one. + record Discard() implements LootFunction { + + @Override + public Key function() { + return Key.key("minecraft:discard"); + } + + @Override + public ItemStack apply(Context context) { + return ItemStack.AIR; + } + } + + // Conditionally applies different modifier chains based on item_filter. + // In 1.21.11+, `modifier` was split into `on_pass` and `on_fail`. + record Filtered(ConditionsFor.Item item_filter, + @Nullable JsonUtils.SingleOrList on_pass, + @Nullable JsonUtils.SingleOrList on_fail, + @Nullable JsonUtils.SingleOrList modifier) implements LootFunction { + + @Override + public Key function() { + return Key.key("minecraft:filtered"); + } + + @Override + public ItemStack apply(Context context) { + // TODO: Evaluate item_filter when item predicates are implemented. + boolean passesFilter = true; + JsonUtils.SingleOrList selected = passesFilter + ? Objects.requireNonNullElse(on_pass, modifier) + : on_fail; + + ItemStack current = context.itemStack(); + for (LootFunction function : selected == null ? List.of() : selected.list()) { + final ItemStack input = current; + current = function.apply(new Context() { + @Override + public RandomGenerator random() { + return context.random(); + } + + @Override + public ItemStack itemStack() { + return input; + } + + @Override + public @Nullable T get(LootContext.Trait trait) { + return context.get(trait); + } + }); + } + return current; + } + } // Applies a predefined bonus formula to the count of the item stack. interface ApplyBonus extends LootFunction { @@ -47,7 +105,7 @@ default Key function() { return Key.key("minecraft:apply_bonus"); } - Key enchantment(); + Enchantment enchantment(); Key formula(); @@ -59,7 +117,7 @@ static ApplyBonus fromJson(JsonReader reader) throws IOException { )); } - record BinomialWithBonusCount(Key enchantment, Parameters parameters) implements ApplyBonus { + record BinomialWithBonusCount(Enchantment enchantment, Parameters parameters) implements ApplyBonus { @Override public Key formula() { return Key.key("minecraft:binomial_with_bonus_count"); @@ -84,7 +142,7 @@ public ItemStack apply(Context context) { } } - record UniformBonusCount(Key enchantment, Parameters parameters) implements ApplyBonus { + record UniformBonusCount(Enchantment enchantment, Parameters parameters) implements ApplyBonus { @Override public Key formula() { @@ -103,7 +161,7 @@ public ItemStack apply(Context context) { } } - record OreDrops(Key enchantment) implements ApplyBonus { + record OreDrops(Enchantment enchantment) implements ApplyBonus { @Override public Key formula() { @@ -554,7 +612,7 @@ public ItemStack apply(Context context) { int looting; if (killer instanceof Player player) { ItemStack mainHand = player.getItemInMainHand(); - int lootingValue = MinestomUtils.getEnchantLevel(mainHand, Enchantment.LOOTING.key(), 0); + int lootingValue = MinestomUtils.getEnchantLevel(mainHand, Enchantment.LOOTING.asValue(), 0); if (lootingValue == 0) return itemStack; looting = lootingValue; } else { @@ -793,7 +851,7 @@ public ItemStack apply(Context context) { Enchantment enchantment = entry.getKey(); int count = entry.getValue().asInt().apply(context::random); - DynamicRegistry.Key key = MinestomUtils.getEnchantKey(enchantment); + net.minestom.server.registry.RegistryKey key = MinestomUtils.getEnchantKey(enchantment); if (add) { int previousValue = list.has(key) ? list.level(key) : 0; diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltPredicates.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltPredicates.java index 649a518a..8e0141a7 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltPredicates.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/InBuiltPredicates.java @@ -352,7 +352,7 @@ public boolean test(LootContext context) { * • enchantment: Resource location of enchantment. * • chances: List of probabilities for enchantment power, indexed from 0. */ - record TableBonus(Key enchantment, List chances) implements Predicate { + record TableBonus(Enchantment enchantment, List chances) implements Predicate { @Override public String condition() { return "table_bonus"; @@ -362,7 +362,7 @@ public String condition() { public boolean test(LootContext context) { ItemStack item = context.getOrThrow(LootContext.TOOL); EnchantmentList enchants = item.get(DataComponents.ENCHANTMENTS); - DynamicRegistry.Key enchantment = MinestomUtils.getEnchantKey(this.enchantment); + net.minestom.server.registry.RegistryKey enchantment = MinestomUtils.getEnchantKey(this.enchantment); int level = enchants == null || !enchants.has(enchantment) ? 0 : enchants.level(enchantment); return ThreadLocalRandom.current().nextFloat() < chances.get(level); diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/LootFunction.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/LootFunction.java index 267e6135..91e1a089 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/LootFunction.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/loot/function/LootFunction.java @@ -33,11 +33,13 @@ static LootFunction fromJson(JsonReader reader) throws IOException { Map.entry("minecraft:copy_name", CopyName.class), Map.entry("minecraft:copy_nbt", CopyNbt.class), Map.entry("minecraft:copy_state", CopyState.class), + Map.entry("minecraft:discard", Discard.class), Map.entry("minecraft:enchant_randomly", EnchantRandomly.class), Map.entry("minecraft:enchant_with_levels", EnchantWithLevels.class), Map.entry("minecraft:exploration_map", ExplorationMap.class), Map.entry("minecraft:explosion_decay", ExplosionDecay.class), Map.entry("minecraft:fill_player_head", FillPlayerHead.class), + Map.entry("minecraft:filtered", Filtered.class), Map.entry("minecraft:furnace_smelt", FurnaceSmelt.class), Map.entry("minecraft:limit_count", LimitCount.class), Map.entry("minecraft:looting_enchant", LootingEnchant.class), diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Biome.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Biome.java index d22dd5ea..540fbbaf 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Biome.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Biome.java @@ -98,13 +98,39 @@ public Key type() { /** * Represents the effects of a biome. */ + public sealed interface Color { + static Color fromJson(JsonReader reader) throws IOException { + return JsonUtils.typeMap(reader, token -> switch (token) { + case NUMBER -> json -> new IntColor(json.nextInt()); + case STRING -> json -> new HexColor(json.nextString()); + case BEGIN_ARRAY -> json -> { + json.beginArray(); + java.util.ArrayList values = new java.util.ArrayList<>(); + while (json.hasNext()) { + values.add((float) json.nextDouble()); + } + json.endArray(); + return new FloatArrayColor(List.copyOf(values)); + }; + default -> null; + }); + } + + record IntColor(int value) implements Color { + } + + record HexColor(String value) implements Color { + } + + record FloatArrayColor(List value) implements Color { + } + } + public record Effects( - int fog_color, - int sky_color, - int water_color, - int water_fog_color, - @Optional Integer foliage_color, - @Optional Integer grass_color, + Color water_color, + @Optional Color foliage_color, + @Optional Color dry_foliage_color, + @Optional Color grass_color, @Optional GrassColorModifier grass_color_modifier, @Optional Particle particle, @Optional Sound ambient_sound, diff --git a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Carver.java b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Carver.java index dd672b5c..1d167e38 100644 --- a/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Carver.java +++ b/datapack-loading/src/main/java/net/minestom/vanilla/datapack/worldgen/Carver.java @@ -9,10 +9,10 @@ import java.io.IOException; -// The root object. +// The root object. // -// type: The ID of carver type. -// config: Configuration values for the carver. +// type: The ID of carver type. +// config: Configuration values for the carver. public record Carver(Key type, BaseConfig config) { public static Carver fromJson(JsonReader reader) throws IOException { @@ -31,72 +31,105 @@ public static Carver fromJson(JsonReader reader) throws IOException { case "minecraft:canyon" -> DatapackLoader.moshi(CanyonConfig.class); default -> throw new IOException("Unknown carver type: " + type); }; + reader.beginObject(); var config = JsonUtils.findProperty(reader, "config", configReader); reader.endObject(); + if (config == null) { throw new IOException("Missing config"); } + return new Carver(Key.key(type), config); } - // cave - Carves a cave. A cave is a long tunnel that sometimes branches. Somtimes one or more tunnels start from a circular void. - // nether_cave - Similar to cave, but with a less frequency and wider tunnels. And aquifer doesn't work. The carved blocks below bottom_y + 32.0 are filled with lava. - // canyon - Carves a canyon. - + // cave - Carves a cave. + // A cave is a long tunnel that sometimes branches. Sometimes one or more tunnels start from a circular void. + // + // nether_cave - Similar to cave, but with a less frequency and wider tunnels. And aquifer doesn't work. + // The carved blocks below bottom_y + 32.0 are filled with lava. + // + // canyon - Carves a canyon. public interface BaseConfig { - - // probability: The probability that each chunk attempts to generate carvers. Value between 0 and 1 (both inclusive). + // probability: The probability that each chunk attempts to generate carvers. Value between 0 and 1 (both inclusive). float probability(); - // y: The height at which this carver attempts to generate. + // y: The height at which this carver attempts to generate. HeightProvider y(); - // lava_level: The Y-level below or equal to which the carved areas are filled with lava. Doesn't affect nether_cave (where lava level is always bottom_y + 31). (This field is seemingly ignored and always set to -56 (MC-237017), needs testing) + // lava_level: The Y-level below or equal to which the carved areas are filled with lava. + // Doesn't affect nether_cave (where lava level is always bottom_y + 31). + // (This field is seemingly ignored and always set to -56 (MC-237017), needs testing) HeightProvider lava_level(); - // replaceable: Blocks that can be carved. Can be a block ID, a block tag, or a list of block IDs. - JsonUtils.SingleOrList replaceable(); + // replaceable: Blocks that can be carved. + // Can be a block ID, a block tag, or a list of block IDs/tags. + JsonUtils.SingleOrList replaceable(); // debug_settings: (optional) Replaces blocks in the carved areas for debugging. // - // debug_mode: (optional, defauts to false) Enable debug mode for this carver. - // air_state: (optional, defaults to acacia button's default state) Replaces air blocks. - // water_state: (optional, defaults to acacia button's default state) Replaces water blocks and then waterlogs these blocks. - // lava_state: (optional, defaults to acacia button's default state) Replaces lava blocks. - // barrier_state: (optional, defaults to acacia button's default state) Replaces barriers of aquifers. - @Optional - BaseConfig.DebugSettings debug_settings(); - - record DebugSettings(@Optional Boolean debug_mode, @Optional Block air_state, - @Optional Block water_state, @Optional Block lava_state, - @Optional Block barrier_state) { + // debug_mode: (optional, defaults to false) Enable debug mode for this carver. + // air_state: (optional, defaults to acacia button's default state) Replaces air blocks. + // water_state: (optional, defaults to acacia button's default state) Replaces water blocks and then waterlogs these blocks. + // lava_state: (optional, defaults to acacia button's default state) Replaces lava blocks. + // barrier_state: (optional, defaults to acacia button's default state) Replaces barriers of aquifers. + @Optional DebugSettings debug_settings(); + + record DebugSettings( + @Optional Boolean debug_mode, + @Optional Block air_state, + @Optional Block water_state, + @Optional Block lava_state, + @Optional Block barrier_state + ) { } } - public record Config(float probability, HeightProvider y, HeightProvider lava_level, - JsonUtils.SingleOrList replaceable, @Optional BaseConfig.DebugSettings debug_settings) implements BaseConfig { + public record Config( + float probability, + HeightProvider y, + HeightProvider lava_level, + JsonUtils.SingleOrList replaceable, + @Optional BaseConfig.DebugSettings debug_settings + ) implements BaseConfig { } // If carver type is cave or nether_cave, additional fields are as follows: // // yScale: Vertically scales circular voids. // vertical_radius_multiplier: Vertically scales cave tunnels. Doesn't affect the length of tunnels. - // floor_level: Value between -1.0 and 1.0 (both inclusive). Change the shape of the cave's horizontal floor. If 0.0, carves the terrain with ellipsoids. If 1.0, carves with upper semi-ellipsoids, resulting in a level floor. - public record CaveConfig(float probability, HeightProvider y, HeightProvider lava_level, - JsonUtils.SingleOrList replaceable, @Optional BaseConfig.DebugSettings debug_settings, - FloatProvider yScale, FloatProvider vertical_radius_multiplier, - FloatProvider floor_level) implements BaseConfig { + // floor_level: Value between -1.0 and 1.0 (both inclusive). + // Change the shape of the cave's horizontal floor. + // If 0.0, carves the terrain with ellipsoids. + // If 1.0, carves with upper semi-ellipsoids, resulting in a level floor. + public record CaveConfig( + float probability, + HeightProvider y, + HeightProvider lava_level, + JsonUtils.SingleOrList replaceable, + @Optional BaseConfig.DebugSettings debug_settings, + FloatProvider yScale, + FloatProvider vertical_radius_multiplier, + FloatProvider floor_level + ) implements BaseConfig { } // If carver type is canyon, additional fields are as follows: - // yScale: Vertically scales canyons. + // yScale: Vertically scales canyons. // vertical_rotation: Vertical rotation as a canyon extends. - // shape: The shape to use for the ravine. - public record CanyonConfig(float probability, HeightProvider y, HeightProvider lava_level, - JsonUtils.SingleOrList replaceable, @Optional BaseConfig.DebugSettings debug_settings, - FloatProvider yScale, FloatProvider vertical_rotation, Shape shape) implements BaseConfig { - // distance_factor: Scales the length of canyons. Higher values make canyons longer. + // shape: The shape to use for the ravine. + public record CanyonConfig( + float probability, + HeightProvider y, + HeightProvider lava_level, + JsonUtils.SingleOrList replaceable, + @Optional BaseConfig.DebugSettings debug_settings, + FloatProvider yScale, + FloatProvider vertical_rotation, + Shape shape + ) implements BaseConfig { + + // distance_factor: Scales the length of canyons. Higher values make canyons longer. // thickness: Scales the breadth and height of canyons. // horizontal_radius_factor: Scales the breadth of canyons. Higher values make canyons wider. // vertical_radius_default_factor: Vertically scales canyons. Higher values make canyons deeper. @@ -108,8 +141,8 @@ public record Shape( FloatProvider horizontal_radius_factor, float vertical_radius_default_factor, float vertical_radius_center_factor, - int width_smoothness) { + int width_smoothness + ) { } } - -} +} \ No newline at end of file diff --git a/datapack-tests/build.gradle.kts b/datapack-tests/build.gradle.kts index 90f24cfe..fac6e586 100644 --- a/datapack-tests/build.gradle.kts +++ b/datapack-tests/build.gradle.kts @@ -18,7 +18,7 @@ tasks.test { } minecraft { - version("1.21.5") + version("1.21.11") runs { server() } diff --git a/datapack-tests/src/test/java/net/minestom/vanilla/datapack/loot/LootTableTestData.java b/datapack-tests/src/test/java/net/minestom/vanilla/datapack/loot/LootTableTestData.java index 6761edd1..7c97d9c7 100644 --- a/datapack-tests/src/test/java/net/minestom/vanilla/datapack/loot/LootTableTestData.java +++ b/datapack-tests/src/test/java/net/minestom/vanilla/datapack/loot/LootTableTestData.java @@ -163,7 +163,7 @@ public class LootTableTestData { expected.put("cauldron", List.of(ItemStack.of(Material.CAULDRON, 1))); expected.put("cave_vines", List.of()); expected.put("cave_vines_plant", List.of()); - expected.put("chain", List.of(ItemStack.of(Material.CHAIN, 1))); + expected.put("iron_chain", List.of(ItemStack.of(Material.IRON_CHAIN, 1))); expected.put("cherry_button", List.of(ItemStack.of(Material.CHERRY_BUTTON, 1))); expected.put("cherry_door", List.of()); expected.put("cherry_fence", List.of(ItemStack.of(Material.CHERRY_FENCE, 1))); diff --git a/fluid-simulation/src/main/java/io/github/togar2/fluids/FlowableFluid.java b/fluid-simulation/src/main/java/io/github/togar2/fluids/FlowableFluid.java index 2769093c..517cc4b1 100644 --- a/fluid-simulation/src/main/java/io/github/togar2/fluids/FlowableFluid.java +++ b/fluid-simulation/src/main/java/io/github/togar2/fluids/FlowableFluid.java @@ -2,18 +2,17 @@ import it.unimi.dsi.fastutil.shorts.Short2BooleanMap; import it.unimi.dsi.fastutil.shorts.Short2BooleanOpenHashMap; +import net.kyori.adventure.key.Key; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; -import net.minestom.server.gamedata.tags.Tag; -import net.minestom.server.gamedata.tags.TagManager; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import net.minestom.server.item.Material; +import net.minestom.server.registry.RegistryTag; import net.minestom.server.utils.Direction; import java.util.EnumMap; import java.util.Map; -import java.util.Objects; public abstract class FlowableFluid extends Fluid { @@ -242,7 +241,7 @@ private int getAdjacentSourceCount(Instance instance, Point point) { */ private boolean canFill(Instance instance, Point point, Block block, Block flowing) { //TODO check waterloggable - TagManager tags = MinecraftServer.getTagManager(); + RegistryTag signs = MinecraftServer.process().blocks().getTag(Key.key("minecraft:signs")); if (block.compare(Block.LADDER) || block.compare(Block.SUGAR_CANE) || block.compare(Block.BUBBLE_COLUMN) @@ -254,7 +253,7 @@ private boolean canFill(Instance instance, Point point, Block block, Block flowi || block.compare(Block.SEAGRASS) || block.compare(Block.TALL_SEAGRASS) || block.compare(Block.SEA_PICKLE) - || Objects.requireNonNull(tags.getTag(Tag.BasicType.BLOCKS, "minecraft:signs")).contains(block.key()) + || (signs != null && signs.contains(block)) || block.name().contains("door") || block.name().contains("coral")) { return false; diff --git a/gradle.properties b/gradle.properties index 73724aba..a3cb9cf2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -minestom_version=2025.07.04-1.21.5 +minestom_version=2026.03.25-1.21.11 rayfast_version=684e854a48 jnoise_version=4.0.0 annotations_version=23.0.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd491..8bdaf60c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a..2e111328 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/items/src/main/java/net/minestom/vanilla/items/FlintAndSteelHandler.java b/items/src/main/java/net/minestom/vanilla/items/FlintAndSteelHandler.java index ec647926..1e19abea 100644 --- a/items/src/main/java/net/minestom/vanilla/items/FlintAndSteelHandler.java +++ b/items/src/main/java/net/minestom/vanilla/items/FlintAndSteelHandler.java @@ -40,6 +40,7 @@ public boolean onUseOnBlock(PlayerUseItemOnBlockEvent event) { // BlockFace blockFace, float cursorX, float cursorY, float cursorZ instance.placeBlock(new BlockHandler.PlayerPlacement( Block.FIRE, + Block.AIR, instance, firePosition, player, diff --git a/jitpack.yml b/jitpack.yml index 727c9abd..aaa58906 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,2 +1,2 @@ jdk: - - openjdk21 + - openjdk25 diff --git a/loot-table/src/main/java/net/minestom/vanilla/loot/LootFunction.java b/loot-table/src/main/java/net/minestom/vanilla/loot/LootFunction.java index 0e746154..0c0726c4 100644 --- a/loot-table/src/main/java/net/minestom/vanilla/loot/LootFunction.java +++ b/loot-table/src/main/java/net/minestom/vanilla/loot/LootFunction.java @@ -25,6 +25,7 @@ import net.minestom.server.item.component.*; import net.minestom.server.item.enchant.Enchantment; import net.minestom.server.item.instrument.Instrument; +import net.minestom.server.network.player.ResolvableProfile; import net.minestom.server.potion.PotionEffect; import net.minestom.server.potion.PotionType; import net.minestom.server.registry.DynamicRegistry; @@ -621,7 +622,7 @@ record FillPlayerHead(@NotNull List predicates, @NotNull Relevant PlayerSkin skin = player.getSkin(); if (skin == null) return input; - return input.with(DataComponents.PROFILE, new HeadProfile(skin)); + return input.with(DataComponents.PROFILE, new ResolvableProfile(skin)); } @Override diff --git a/mojang-data/src/main/java/io/github/pesto/MojangDataFeature.java b/mojang-data/src/main/java/io/github/pesto/MojangDataFeature.java index 36a74356..350b5f21 100644 --- a/mojang-data/src/main/java/io/github/pesto/MojangDataFeature.java +++ b/mojang-data/src/main/java/io/github/pesto/MojangDataFeature.java @@ -10,7 +10,7 @@ public class MojangDataFeature implements VanillaReimplementation.Feature { - private static final String LATEST = "1.21.5"; + private static final String LATEST = "1.21.11"; private final MojangAssets assets = new MojangAssets(); private final CompletableFuture> latest = new CompletableFuture<>(); diff --git a/server/src/main/java/net/minestom/vanilla/server/VanillaEvents.java b/server/src/main/java/net/minestom/vanilla/server/VanillaEvents.java index 890509c9..2a38c245 100644 --- a/server/src/main/java/net/minestom/vanilla/server/VanillaEvents.java +++ b/server/src/main/java/net/minestom/vanilla/server/VanillaEvents.java @@ -1,5 +1,6 @@ package net.minestom.vanilla.server; +import net.minestom.server.Auth; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; @@ -14,7 +15,6 @@ import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.event.item.PickupItemEvent; import net.minestom.server.event.player.*; -import net.minestom.server.extras.MojangAuth; import net.minestom.server.instance.ExplosionSupplier; import net.minestom.server.instance.Instance; import net.minestom.server.inventory.PlayerInventory; @@ -93,7 +93,7 @@ public static void register(VanillaServer server, ServerProperties properties, E }); if (Boolean.parseBoolean(properties.get("online-mode"))) { - MojangAuth.init(); + MinecraftServer.init(new Auth.Online()); } ConnectionManager connectionManager = MinecraftServer.getConnectionManager();