diff --git a/build.gradle.kts b/build.gradle.kts index 38d9d68..8f3edf7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id("java") - id("com.github.johnrengelman.shadow") version "7.1.0" + id("com.gradleup.shadow") version "9.0.0-rc2" } tasks { @@ -20,12 +20,12 @@ repositories { } dependencies { - implementation("com.github.Minestom:Minestom:cb3892255e") + implementation("net.minestom:minestom:2025.07.27-1.21.8") implementation("de.articdive:jnoise-pipeline:4.0.0") implementation("io.prometheus:simpleclient:0.16.0") implementation("io.prometheus:simpleclient_hotspot:0.16.0") implementation("io.prometheus:simpleclient_httpserver:0.16.0") - implementation("net.kyori:adventure-text-minimessage:4.12.0") + implementation("net.kyori:adventure-text-minimessage:4.23.0") } tasks.withType { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb87..3ae1e2f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/minestom/arena/Items.java b/src/main/java/net/minestom/arena/Items.java index 39859f8..6169cfa 100644 --- a/src/main/java/net/minestom/arena/Items.java +++ b/src/main/java/net/minestom/arena/Items.java @@ -8,19 +8,19 @@ public final class Items { public static final ItemStack CLOSE = ItemUtils.stripItalics(ItemStack.builder(Material.BARRIER) - .displayName(Component.text("Close", NamedTextColor.RED)) + .customName(Component.text("Close", NamedTextColor.RED)) .lore(Component.text("Close this page", NamedTextColor.GRAY)) .build()); public static final ItemStack CONTINUE = ItemUtils.stripItalics(ItemStack.builder(Material.FEATHER) - .displayName(Component.text("Continue", NamedTextColor.GOLD)) + .customName(Component.text("Continue", NamedTextColor.GOLD)) .lore(Component.text("Continue to the next stage", NamedTextColor.GRAY)) .build()); public static final ItemStack BACK = ItemUtils.stripItalics(ItemStack.builder(Material.ARROW) - .displayName(Component.text("Back", NamedTextColor.AQUA)) + .customName(Component.text("Back", NamedTextColor.AQUA)) .lore(Component.text("Go back to the previous page", NamedTextColor.GRAY)) .build()); public static final ItemStack COIN = ItemUtils.stripItalics(ItemStack.builder(Material.SUNFLOWER) - .displayName(Component.text("Coin")) + .customName(Component.text("Coin")) .build()); private Items() {} diff --git a/src/main/java/net/minestom/arena/Main.java b/src/main/java/net/minestom/arena/Main.java index 21cf362..17ff57c 100644 --- a/src/main/java/net/minestom/arena/Main.java +++ b/src/main/java/net/minestom/arena/Main.java @@ -8,6 +8,7 @@ import net.minestom.arena.group.GroupCommand; import net.minestom.arena.group.GroupEvent; import net.minestom.arena.lobby.Lobby; +import net.minestom.arena.utils.FullbrightDimension; import net.minestom.arena.utils.ResourceUtils; import net.minestom.server.MinecraftServer; import net.minestom.server.adventure.audience.Audiences; @@ -16,18 +17,20 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.event.GlobalEventHandler; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; -import net.minestom.server.event.player.PlayerLoginEvent; import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.event.server.ServerTickMonitorEvent; import net.minestom.server.extras.MojangAuth; import net.minestom.server.extras.lan.OpenToLAN; import net.minestom.server.extras.velocity.VelocityProxy; import net.minestom.server.monitoring.TickMonitor; +import net.minestom.server.registry.RegistryKey; import net.minestom.server.sound.SoundEvent; import net.minestom.server.timer.TaskSchedule; import net.minestom.server.utils.MathUtils; +import net.minestom.server.world.DimensionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +46,9 @@ public static void main(String[] args) { MinecraftServer minecraftServer = MinecraftServer.init(); if (CONFIG.prometheus().enabled()) Metrics.init(); + // Register fullbright dimension before server start + RegistryKey instance = FullbrightDimension.INSTANCE; + try { ResourceUtils.extractResource("lobby"); } catch (Exception e) { @@ -69,7 +75,7 @@ public static void main(String[] args) { ServerList.hook(handler); // Login - handler.addListener(PlayerLoginEvent.class, event -> { + handler.addListener(AsyncPlayerConfigurationEvent.class, event -> { final Player player = event.getPlayer(); event.setSpawningInstance(Lobby.INSTANCE); player.setRespawnPoint(new Pos(0.5, 16, 0.5)); @@ -101,9 +107,9 @@ public static void main(String[] args) { // Chat handler.addListener(PlayerChatEvent.class, chatEvent -> { - chatEvent.setChatFormat((event) -> Component.text(event.getEntity().getUsername()) + chatEvent.setFormattedMessage(Component.text(chatEvent.getEntity().getUsername()) .append(Component.text(" | ", NamedTextColor.DARK_GRAY) - .append(Component.text(event.getMessage(), NamedTextColor.WHITE)))); + .append(Component.text(chatEvent.getRawMessage(), NamedTextColor.WHITE)))); }); // Monitoring diff --git a/src/main/java/net/minestom/arena/Metrics.java b/src/main/java/net/minestom/arena/Metrics.java index 2aaa7e8..eae1ac9 100644 --- a/src/main/java/net/minestom/arena/Metrics.java +++ b/src/main/java/net/minestom/arena/Metrics.java @@ -11,8 +11,8 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.entity.EntitySpawnEvent; import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; -import net.minestom.server.event.player.PlayerLoginEvent; import net.minestom.server.event.player.PlayerPacketEvent; import net.minestom.server.event.player.PlayerPacketOutEvent; @@ -62,7 +62,7 @@ public static void init() { MinecraftServer.getGlobalEventHandler() .addListener(PlayerPacketEvent.class, e -> Metrics.PACKETS.labels("in").inc()) .addListener(PlayerPacketOutEvent.class, e -> Metrics.PACKETS.labels("out").inc()) - .addListener(PlayerLoginEvent.class, e -> Metrics.ONLINE_PLAYERS.inc()) + .addListener(AsyncPlayerConfigurationEvent.class, e -> Metrics.ONLINE_PLAYERS.inc()) .addListener(PlayerDisconnectEvent.class, e -> Metrics.ONLINE_PLAYERS.dec()) .addListener(EntitySpawnEvent.class, e -> { if (!(e.getEntity() instanceof Player)) Metrics.ENTITIES.inc(); diff --git a/src/main/java/net/minestom/arena/ServerList.java b/src/main/java/net/minestom/arena/ServerList.java index dfb47fb..c244813 100644 --- a/src/main/java/net/minestom/arena/ServerList.java +++ b/src/main/java/net/minestom/arena/ServerList.java @@ -8,32 +8,35 @@ import net.minestom.server.event.Event; import net.minestom.server.event.EventNode; import net.minestom.server.event.server.ServerListPingEvent; -import net.minestom.server.ping.ResponseData; +import net.minestom.server.ping.Status; import java.io.InputStream; -import java.util.Base64; import java.util.List; final class ServerList { - private static final String FAVICON = favicon(); - private static Component motd = motd(); + private static final byte[] FAVICON = favicon(); + private static Component MOTD = motd(); public static void hook(EventNode eventNode) { eventNode.addListener(ServerListPingEvent.class, event -> { - final ResponseData responseData = event.getResponseData(); - responseData.setDescription(motd); - if (FAVICON != null) - responseData.setFavicon(FAVICON); - responseData.setMaxPlayer(100); - responseData.addEntries(MinecraftServer.getConnectionManager().getOnlinePlayers()); - }).addListener(ConfigurationReloadedEvent.class, e -> motd = motd()); + int onlinePlayers = MinecraftServer.getConnectionManager().getOnlinePlayers().size(); + + Status.Builder builder = Status.builder() + .description(MOTD) + .favicon(FAVICON) + .playerInfo(onlinePlayers, 100); + + if (FAVICON != null) builder.favicon(FAVICON); + + event.setStatus(builder.build()); + }).addListener(ConfigurationReloadedEvent.class, e -> MOTD = motd()); } - private static String favicon() { - String favicon = null; + private static byte[] favicon() { + byte[] favicon = null; try (InputStream stream = Main.class.getResourceAsStream("/favicon.png")) { if (stream != null) - favicon = "data:image/png;base64," + Base64.getEncoder().encodeToString(stream.readAllBytes()); + favicon = stream.readAllBytes(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/net/minestom/arena/SimpleCommands.java b/src/main/java/net/minestom/arena/SimpleCommands.java index e2fd4c7..a1ad862 100644 --- a/src/main/java/net/minestom/arena/SimpleCommands.java +++ b/src/main/java/net/minestom/arena/SimpleCommands.java @@ -40,7 +40,7 @@ private static List commands() { leave.setDefaultExecutor((sender, context) -> { final Player player = (Player) sender; player.setInstance(Lobby.INSTANCE); - player.setHealth(player.getMaxHealth()); + player.heal(); GroupManager.removePlayer(player); }); diff --git a/src/main/java/net/minestom/arena/feature/BowFeature.java b/src/main/java/net/minestom/arena/feature/BowFeature.java index 3db4a9f..4fc2abc 100644 --- a/src/main/java/net/minestom/arena/feature/BowFeature.java +++ b/src/main/java/net/minestom/arena/feature/BowFeature.java @@ -7,9 +7,10 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.EventListener; import net.minestom.server.event.EventNode; -import net.minestom.server.event.item.ItemUpdateStateEvent; -import net.minestom.server.event.player.PlayerItemAnimationEvent; +import net.minestom.server.event.item.PlayerBeginItemUseEvent; +import net.minestom.server.event.item.PlayerCancelItemUseEvent; import net.minestom.server.event.trait.InstanceEvent; +import net.minestom.server.item.ItemAnimation; import net.minestom.server.item.Material; import net.minestom.server.tag.Tag; import net.minestom.server.utils.MathUtils; @@ -26,11 +27,11 @@ record BowFeature(@NotNull BiFunction projecti @Override public void hook(@NotNull EventNode node) { - node.addListener(EventListener.builder(PlayerItemAnimationEvent.class) + node.addListener(EventListener.builder(PlayerBeginItemUseEvent.class) .handler(event -> event.getPlayer().setTag(CHARGE_SINCE_TAG, System.currentTimeMillis())) - .filter(event -> event.getItemAnimationType() == PlayerItemAnimationEvent.ItemAnimationType.BOW) + .filter(event -> event.getAnimation() == ItemAnimation.BOW) .build() - ).addListener(EventListener.builder(ItemUpdateStateEvent.class) + ).addListener(EventListener.builder(PlayerCancelItemUseEvent.class) .handler(event -> { final Player player = event.getPlayer(); final double chargedFor = (System.currentTimeMillis() - player.getTag(CHARGE_SINCE_TAG)) / 1000D; diff --git a/src/main/java/net/minestom/arena/feature/CombatFeature.java b/src/main/java/net/minestom/arena/feature/CombatFeature.java index 4871bb1..e0cee10 100644 --- a/src/main/java/net/minestom/arena/feature/CombatFeature.java +++ b/src/main/java/net/minestom/arena/feature/CombatFeature.java @@ -2,18 +2,14 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.entity.Entity; -import net.minestom.server.entity.EntityProjectile; -import net.minestom.server.entity.LivingEntity; -import net.minestom.server.entity.Player; -import net.minestom.server.entity.damage.DamageType; -import net.minestom.server.entity.hologram.Hologram; +import net.minestom.server.entity.*; +import net.minestom.server.entity.damage.Damage; +import net.minestom.server.entity.metadata.display.AbstractDisplayMeta; +import net.minestom.server.entity.metadata.display.TextDisplayMeta; import net.minestom.server.event.EventNode; import net.minestom.server.event.entity.EntityAttackEvent; import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent; import net.minestom.server.event.trait.InstanceEvent; -import net.minestom.server.instance.Instance; import net.minestom.server.tag.Tag; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.time.TimeUnit; @@ -49,7 +45,7 @@ public void hook(@NotNull EventNode node) { float damage = (float) damageFunction.applyAsDouble(projectile, target); - target.damage(DamageType.fromProjectile(projectile.getShooter(), projectile), damage); + target.damage(Damage.fromProjectile(projectile.getShooter(), projectile, damage)); target.setTag(INVULNERABLE_UNTIL_TAG, now + invulnerabilityFunction.applyAsLong(target)); takeKnockbackFromArrow(target, projectile); @@ -72,7 +68,7 @@ public void hook(@NotNull EventNode node) { float damage = (float) damageFunction.applyAsDouble(event.getEntity(), target); - target.damage(DamageType.fromEntity(event.getEntity()), damage); + target.damage(Damage.fromEntity(event.getEntity(), damage)); target.setTag(INVULNERABLE_UNTIL_TAG, now + invulnerabilityFunction.applyAsLong(target)); takeKnockback(target, event.getEntity()); @@ -96,27 +92,30 @@ private static void takeKnockbackFromArrow(Entity target, EntityProjectile sourc private static void spawnHologram(Entity target, float damage) { damage = MathUtils.round(damage, 2); - new DamageHologram( - target.getInstance(), - target.getPosition().add(0, target.getEyeHeight(), 0), - Component.text(damage, NamedTextColor.RED) - ); + Entity hologram = new DamageHologram(Component.text(damage, NamedTextColor.RED)); + hologram.setInstance(target.getInstance(), target.getPosition().add(0, target.getEyeHeight(), 0)); } - private static final class DamageHologram extends Hologram { - private DamageHologram(Instance instance, Pos spawnPosition, Component text) { - super(instance, spawnPosition, text, true, true); - getEntity().getEntityMeta().setHasNoGravity(false); + private static final class DamageHologram extends Entity { + private DamageHologram(Component text) { + super(EntityType.TEXT_DISPLAY); + + setNoGravity(true); + + editEntityMeta(TextDisplayMeta.class, meta -> { + meta.setBillboardRenderConstraints(AbstractDisplayMeta.BillboardConstraints.CENTER); + meta.setText(text); + }); Random random = ThreadLocalRandom.current(); - getEntity().setVelocity(getPosition() + setVelocity(getPosition() .direction() .withX(random.nextDouble(2)) .withY(3) .withZ(random.nextDouble(2)) .normalize().mul(3)); - getEntity().scheduleRemove(Duration.of(15, TimeUnit.SERVER_TICK)); + scheduleRemove(Duration.of(15, TimeUnit.SERVER_TICK)); } } } diff --git a/src/main/java/net/minestom/arena/game/ArenaCommand.java b/src/main/java/net/minestom/arena/game/ArenaCommand.java index 7f0f44f..e29b4a8 100644 --- a/src/main/java/net/minestom/arena/game/ArenaCommand.java +++ b/src/main/java/net/minestom/arena/game/ArenaCommand.java @@ -3,21 +3,24 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.arena.Items; -import net.minestom.arena.lobby.Lobby; import net.minestom.arena.Messenger; import net.minestom.arena.group.Group; +import net.minestom.arena.lobby.Lobby; import net.minestom.arena.utils.CommandUtils; import net.minestom.arena.utils.ItemUtils; import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.arguments.ArgumentEnum; import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.component.DataComponents; import net.minestom.server.entity.Player; +import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.inventory.click.ClickType; -import net.minestom.server.item.Enchantment; +import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.component.EnchantmentList; +import net.minestom.server.item.enchant.Enchantment; import net.minestom.server.tag.Tag; import org.jetbrains.annotations.NotNull; @@ -59,7 +62,7 @@ private static void play(@NotNull Player player, @NotNull ArenaType type, @NotNu private static final class ArenaInventory extends Inventory { private static final Tag ARENA_TAG = Tag.Integer("arena").defaultValue(-1); private static final ItemStack HEADER = ItemUtils.stripItalics(ItemStack.builder(Material.IRON_BARS) - .displayName(Component.text("Arena", NamedTextColor.RED)) + .customName(Component.text("Arena", NamedTextColor.RED)) .lore(Component.text("Select an arena to play in", NamedTextColor.GRAY)) .build()); @@ -79,21 +82,27 @@ private static final class ArenaInventory extends Inventory { ))) .withTag(ARENA_TAG, arenaType.ordinal()))); - addInventoryCondition((player, slot, clickType, result) -> { - result.setCancel(true); + eventNode().addListener(InventoryPreClickEvent.class, event -> { + event.setCancelled(true); + + int slot = event.getSlot(); + Click click = event.getClick(); + ItemStack clickedItem = event.getClickedItem(); + + Player player = event.getPlayer(); if (slot == 31) { // Close button player.closeInventory(); return; } - final int arena = result.getClickedItem().getTag(ARENA_TAG); + final int arena = clickedItem.getTag(ARENA_TAG); if (arena == -1) return; final ArenaType type = ArenaType.values()[arena]; - if (clickType == ClickType.RIGHT_CLICK) { + if (click instanceof Click.Right) { player.openInventory(new ArenaOptionInventory(this, type)); - } else{ + } else { player.closeInventory(); play(player, type, Set.of()); } @@ -103,7 +112,7 @@ private static final class ArenaInventory extends Inventory { private static final class ArenaOptionInventory extends Inventory { private static final ItemStack PLAY_ITEM = ItemUtils.stripItalics(ItemStack.builder(Material.NOTE_BLOCK) - .displayName(Component.text("Play", NamedTextColor.GREEN)) + .customName(Component.text("Play", NamedTextColor.GREEN)) .lore(Component.text("Play this arena", NamedTextColor.GRAY)) .build()); private static final Tag OPTION_TAG = Tag.Integer("option").defaultValue(-1); @@ -119,8 +128,12 @@ private static final class ArenaOptionInventory extends Inventory { draw(); - addInventoryCondition((player, slot, c, result) -> { - result.setCancel(true); + eventNode().addListener(InventoryPreClickEvent.class, event -> { + event.setCancelled(true); + + int slot = event.getSlot(); + Player player = event.getPlayer(); + ItemStack clickedItem = event.getClickedItem(); if (slot == 30) { // Play button player.closeInventory(); @@ -133,7 +146,7 @@ private static final class ArenaOptionInventory extends Inventory { return; } - final int index = result.getClickedItem().getTag(OPTION_TAG); + final int index = clickedItem.getTag(OPTION_TAG); if (index == -1) return; final ArenaOption option = availableOptions.get(index); @@ -152,10 +165,11 @@ private void draw() { final int start = 13 - availableOptions.size() / 2; int index = 0; - for (ArenaOption option : availableOptions) - setItemStack(start + index, option.item().withTag(OPTION_TAG, index++).withMeta(builder -> { - if (selectedOptions.contains(option)) builder.enchantment(Enchantment.PROTECTION, (short) 1); - })); + for (ArenaOption option : availableOptions) { + ItemStack itemStack = option.item().withTag(OPTION_TAG, index++); + if (selectedOptions.contains(option)) itemStack = itemStack.with(DataComponents.ENCHANTMENTS, new EnchantmentList(Enchantment.PROTECTION, 1)); + setItemStack(start + index, itemStack); + } } } } diff --git a/src/main/java/net/minestom/arena/game/ArenaOption.java b/src/main/java/net/minestom/arena/game/ArenaOption.java index 05f6095..cd82bb1 100644 --- a/src/main/java/net/minestom/arena/game/ArenaOption.java +++ b/src/main/java/net/minestom/arena/game/ArenaOption.java @@ -13,9 +13,9 @@ public record ArenaOption(@NotNull String name, @NotNull String description, public @NotNull ItemStack item() { return ItemUtils.stripItalics(ItemStack.builder(material) - .displayName(Component.text(name, color)) + .customName(Component.text(name, color)) .lore(Component.text(description, NamedTextColor.GRAY)) - .meta(ItemUtils::hideFlags) + .hideExtraTooltip() .build()); } } diff --git a/src/main/java/net/minestom/arena/game/ArenaType.java b/src/main/java/net/minestom/arena/game/ArenaType.java index 8e3cd72..1ef33ed 100644 --- a/src/main/java/net/minestom/arena/game/ArenaType.java +++ b/src/main/java/net/minestom/arena/game/ArenaType.java @@ -11,7 +11,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.BiFunction; enum ArenaType { @@ -36,8 +39,8 @@ enum ArenaType { @NotNull List availableOptions) { item = ItemUtils.stripItalics(ItemStack.builder(material) - .displayName(Component.text(name, color)) - .meta(ItemUtils::hideFlags) + .customName(Component.text(name, color)) + .hideExtraTooltip() .build()); this.supplier = supplier; this.name = name; diff --git a/src/main/java/net/minestom/arena/game/mob/ArenaClass.java b/src/main/java/net/minestom/arena/game/mob/ArenaClass.java index 2c3ac4c..6463619 100644 --- a/src/main/java/net/minestom/arena/game/mob/ArenaClass.java +++ b/src/main/java/net/minestom/arena/game/mob/ArenaClass.java @@ -15,13 +15,13 @@ public void apply(Player player) { public ItemStack itemStack() { return ItemUtils.stripItalics(ItemStack.builder(material) - .displayName(Component.text(icon + " " + name, color)) + .customName(Component.text(icon + " " + name, color)) .lore( Component.text(description, NamedTextColor.GRAY), Component.empty(), Component.text("Switch to this class for " + cost + " coins", NamedTextColor.GOLD) ) - .meta(ItemUtils::hideFlags) + .hideExtraTooltip() .build() ); } diff --git a/src/main/java/net/minestom/arena/game/mob/ArenaMob.java b/src/main/java/net/minestom/arena/game/mob/ArenaMob.java index f266ce8..03df257 100644 --- a/src/main/java/net/minestom/arena/game/mob/ArenaMob.java +++ b/src/main/java/net/minestom/arena/game/mob/ArenaMob.java @@ -1,10 +1,15 @@ package net.minestom.arena.game.mob; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.minestom.server.attribute.Attribute; +import net.minestom.server.component.DataComponents; import net.minestom.server.entity.EntityCreature; import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.entity.attribute.AttributeInstance; +import net.minestom.server.entity.attribute.AttributeModifier; +import net.minestom.server.entity.attribute.AttributeOperation; import net.minestom.server.event.entity.EntityDamageEvent; import net.minestom.server.event.entity.EntityDeathEvent; import org.jetbrains.annotations.Contract; @@ -21,19 +26,24 @@ class ArenaMob extends EntityCreature { private static final String FULL_BLOCK_CHAR = "█"; protected final MobGenerationContext context; + protected static final AttributeModifier BABY_SPEED_MODIFIER = + new AttributeModifier(Key.key("minecraft:baby"), 0.5, AttributeOperation.ADD_MULTIPLIED_BASE); + public ArenaMob(@NotNull EntityType entityType, MobGenerationContext context) { super(entityType); this.context = context; final float multi = context.hasOption(MobArena.TOUGH_MOBS_OPTION) ? 2 : 1; - getAttribute(Attribute.MAX_HEALTH).setBaseValue((getMaxHealth() + context.stage() * 2) * multi); + AttributeInstance maxHealthAttribute = getAttribute(Attribute.MAX_HEALTH); + double maxHealth = maxHealthAttribute.getBaseValue(); + maxHealthAttribute.setBaseValue((maxHealth + context.stage() * 2) * multi); getAttribute(Attribute.ATTACK_DAMAGE).setBaseValue((1 + context.stage() / 4f) * multi); heal(); - setCustomName(generateHealthBar(getMaxHealth(), getHealth())); + set(DataComponents.CUSTOM_NAME, generateHealthBar((float) maxHealth, getHealth())); setCustomNameVisible(true); eventNode().addListener(EntityDamageEvent.class, event -> - setCustomName(generateHealthBar(getMaxHealth(), getHealth()))) + set(DataComponents.CUSTOM_NAME, generateHealthBar((float) maxHealth, getHealth()))) .addListener(EntityDeathEvent.class, event -> - setCustomName(generateHealthBar(getMaxHealth(), 0))); + set(DataComponents.CUSTOM_NAME, generateHealthBar((float) maxHealth, 0))); } @Contract(pure = true) diff --git a/src/main/java/net/minestom/arena/game/mob/ArenaUpgrade.java b/src/main/java/net/minestom/arena/game/mob/ArenaUpgrade.java index 31b4e8a..2bd28af 100644 --- a/src/main/java/net/minestom/arena/game/mob/ArenaUpgrade.java +++ b/src/main/java/net/minestom/arena/game/mob/ArenaUpgrade.java @@ -4,10 +4,12 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.minestom.arena.utils.ItemUtils; +import net.minestom.server.component.DataComponents; import net.minestom.server.entity.Player; -import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.component.EnchantmentList; +import net.minestom.server.item.enchant.Enchantment; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,20 +21,20 @@ record ArenaUpgrade(String name, String description, TextColor color, Material m @Nullable BiConsumer apply, @Nullable Consumer remove, @NotNull IntFunction effect, int cost, float costMultiplier, int maxLevel) { public ItemStack itemStack(int level) { - return ItemUtils.stripItalics(ItemStack.builder(material) - .displayName(Component.text(name, color)) + ItemStack.Builder builder = ItemStack.builder(material) + .customName(Component.text(name, color)) .lore( Component.text(description, NamedTextColor.GRAY), Component.empty(), Component.text("Buy this team upgrade for " + cost(level) + " coins", NamedTextColor.GOLD), Component.text(effect.apply(level), NamedTextColor.YELLOW) ) - .meta(ItemUtils::hideFlags) - .meta(builder -> { - if (level >= maxLevel) builder.enchantment(Enchantment.PROTECTION, (short) 1); - }) - .build() - ); + + .hideExtraTooltip(); + + if (level >= maxLevel) builder.set(DataComponents.ENCHANTMENTS, new EnchantmentList(Enchantment.PROTECTION, 1)); + + return ItemUtils.stripItalics(builder.build()); } public int cost(int level) { diff --git a/src/main/java/net/minestom/arena/game/mob/EndermanMob.java b/src/main/java/net/minestom/arena/game/mob/EndermanMob.java index e25f055..c91f70a 100644 --- a/src/main/java/net/minestom/arena/game/mob/EndermanMob.java +++ b/src/main/java/net/minestom/arena/game/mob/EndermanMob.java @@ -1,6 +1,5 @@ package net.minestom.arena.game.mob; -import net.minestom.server.attribute.Attribute; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityCreature; @@ -9,6 +8,7 @@ import net.minestom.server.entity.ai.GoalSelector; import net.minestom.server.entity.ai.goal.MeleeAttackGoal; import net.minestom.server.entity.ai.target.ClosestEntityTarget; +import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.utils.time.Cooldown; import net.minestom.server.utils.time.TimeUnit; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/net/minestom/arena/game/mob/EvokerMob.java b/src/main/java/net/minestom/arena/game/mob/EvokerMob.java index 8c679e7..ca4e5b7 100644 --- a/src/main/java/net/minestom/arena/game/mob/EvokerMob.java +++ b/src/main/java/net/minestom/arena/game/mob/EvokerMob.java @@ -1,7 +1,7 @@ package net.minestom.arena.game.mob; -import net.minestom.server.attribute.Attribute; import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityCreature; import net.minestom.server.entity.EntityType; @@ -9,10 +9,12 @@ import net.minestom.server.entity.ai.GoalSelector; import net.minestom.server.entity.ai.goal.MeleeAttackGoal; import net.minestom.server.entity.ai.target.ClosestEntityTarget; +import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.entity.attribute.AttributeInstance; import net.minestom.server.entity.metadata.monster.raider.EvokerMeta; import net.minestom.server.entity.metadata.monster.raider.SpellcasterIllagerMeta; +import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.particle.Particle; -import net.minestom.server.particle.ParticleCreator; import net.minestom.server.timer.TaskSchedule; import net.minestom.server.utils.time.Cooldown; import net.minestom.server.utils.time.TimeUnit; @@ -42,16 +44,20 @@ public EvokerMob(MobGenerationContext context) { List.of(new MeleeAttackGoal(silverfish, 1.2, 20, TimeUnit.SERVER_TICK)), List.of(new ClosestEntityTarget(silverfish, 32, entity -> entity instanceof Player)) ); - silverfish.getAttribute(Attribute.MAX_HEALTH).setBaseValue(silverfish.getMaxHealth() / 4); + + AttributeInstance attribute = silverfish.getAttribute(Attribute.MAX_HEALTH); + attribute.setBaseValue(attribute.getBaseValue() / 4); silverfish.heal(); final Pos pos = position.add( random.nextFloat(-2, 2), 0, random.nextFloat(-2, 2) ); silverfish.setInstance(instance, pos); - instance.sendGroupedPacket(ParticleCreator.createParticlePacket( - Particle.POOF, true, pos.x(), pos.y(), pos.z(), - 0.2f, 0.2f, 0.2f, 0.1f, 10, null + + + instance.sendGroupedPacket(new ParticlePacket( + Particle.POOF, true, true, pos, + new Vec(0.2f, 0.2f, 0.2f), 0.1f, 10 )); } diff --git a/src/main/java/net/minestom/arena/game/mob/MobArena.java b/src/main/java/net/minestom/arena/game/mob/MobArena.java index 5ddb275..971c61d 100644 --- a/src/main/java/net/minestom/arena/game/mob/MobArena.java +++ b/src/main/java/net/minestom/arena/game/mob/MobArena.java @@ -1,6 +1,7 @@ package net.minestom.arena.game.mob; import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; @@ -8,7 +9,9 @@ import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.title.Title; -import net.minestom.arena.*; +import net.minestom.arena.Icons; +import net.minestom.arena.Items; +import net.minestom.arena.Messenger; import net.minestom.arena.feature.Feature; import net.minestom.arena.feature.Features; import net.minestom.arena.game.ArenaOption; @@ -19,15 +22,17 @@ import net.minestom.arena.lobby.LobbySidebarDisplay; import net.minestom.arena.utils.ItemUtils; import net.minestom.server.MinecraftServer; -import net.minestom.server.attribute.Attribute; -import net.minestom.server.attribute.AttributeInstance; -import net.minestom.server.attribute.AttributeModifier; -import net.minestom.server.attribute.AttributeOperation; +import net.minestom.server.ServerFlag; +import net.minestom.server.component.DataComponents; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.*; -import net.minestom.server.entity.damage.DamageType; -import net.minestom.server.entity.metadata.arrow.ArrowMeta; +import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.entity.attribute.AttributeInstance; +import net.minestom.server.entity.attribute.AttributeModifier; +import net.minestom.server.entity.attribute.AttributeOperation; +import net.minestom.server.entity.damage.Damage; +import net.minestom.server.entity.metadata.projectile.ArrowMeta; import net.minestom.server.event.entity.EntityAttackEvent; import net.minestom.server.event.entity.EntityDeathEvent; import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent; @@ -39,8 +44,8 @@ import net.minestom.server.instance.Instance; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.particle.Particle; -import net.minestom.server.particle.ParticleCreator; import net.minestom.server.sound.SoundEvent; import net.minestom.server.tag.Tag; import net.minestom.server.timer.TaskSchedule; @@ -71,10 +76,10 @@ public final class MobArena implements SingleInstanceArena { static final Tag MELEE_TAG = Tag.Integer("melee").defaultValue(-10); static final Tag ARMOR_TAG = Tag.Integer("armor").defaultValue(0); - private static final AttributeModifier ATTACK_SPEED_MODIFIER = new AttributeModifier("mobarena-attack-speed", 100f, AttributeOperation.ADDITION); + private static final AttributeModifier ATTACK_SPEED_MODIFIER = new AttributeModifier("mobarena-attack-speed", 100f, AttributeOperation.ADD_VALUE); private static final ItemStack WAND = ItemUtils.stripItalics(ItemStack.builder(Material.BLAZE_ROD) - .displayName(Component.text("Wand")) + .customName(Component.text("Wand")) .build()); private static final ArenaClass KNIGHT_CLASS = new ArenaClass("Knight", "Starter class with mediocre attack and defense.", @@ -115,23 +120,23 @@ public final class MobArena implements SingleInstanceArena { TextColor.color(0xf9ff87), Material.LAVA_BUCKET, null, null, level -> "Armor effectiveness is currently increased by " + MathUtils.round(Math.pow(1.15, level) * 100 - 100, 2) + "%", 10, 1.1f, 20); - private static final UUID HEALTHCARE_UUID = new UUID(9354678, 3425896); - private static final UUID COMBAT_TRAINING_UUID = new UUID(24539786, 23945687); + private static final Key HEALTHCARE_KEY = Key.key("mobarena-healthcare"); + private static final Key COMBAT_TRAINING_KEY = Key.key("mobarena-combat-training"); public static final List UPGRADES = List.of( new ArenaUpgrade("Improved Healthcare", "Increases max health by two hearts per level, and healing by one heart if you have the upgrade.", TextColor.color(0x63ff52), Material.POTION, (player, count) -> { final AttributeModifier modifier = new AttributeModifier( - HEALTHCARE_UUID, "mobarena-healthcare", 4 * count, - AttributeOperation.ADDITION + HEALTHCARE_KEY, 4 * count, + AttributeOperation.ADD_VALUE ); player.getAttribute(Attribute.MAX_HEALTH).removeModifier(modifier); player.getAttribute(Attribute.MAX_HEALTH).addModifier(modifier); }, player -> { AttributeInstance attribute = player.getAttribute(Attribute.MAX_HEALTH); - for (AttributeModifier modifier : attribute.getModifiers()) { - if (!modifier.getId().equals(HEALTHCARE_UUID)) continue; + for (AttributeModifier modifier : attribute.modifiers()) { + if (!modifier.id().equals(HEALTHCARE_KEY)) continue; attribute.removeModifier(modifier); } player.heal(); @@ -140,16 +145,16 @@ public final class MobArena implements SingleInstanceArena { new ArenaUpgrade("Combat Training", "All physical attacks deal 10% more damage", TextColor.color(0xff5c3c), Material.IRON_SWORD, (player, count) -> { final AttributeModifier modifier = new AttributeModifier( - COMBAT_TRAINING_UUID, "mobarena-combat-training", (float) (Math.pow(1.1, count) - 1), - AttributeOperation.MULTIPLY_TOTAL + COMBAT_TRAINING_KEY, (float) (Math.pow(1.1, count) - 1), + AttributeOperation.ADD_MULTIPLIED_TOTAL ); player.getAttribute(Attribute.ATTACK_DAMAGE).removeModifier(modifier); player.getAttribute(Attribute.ATTACK_DAMAGE).addModifier(modifier); }, player -> { AttributeInstance attribute = player.getAttribute(Attribute.ATTACK_DAMAGE); - for (AttributeModifier modifier : attribute.getModifiers()) { - if (!modifier.getId().equals(COMBAT_TRAINING_UUID)) continue; + for (AttributeModifier modifier : attribute.modifiers()) { + if (!modifier.id().equals(COMBAT_TRAINING_KEY)) continue; attribute.removeModifier(modifier); } }, level -> "Physical attacks now deal " + MathUtils.round(Math.pow(1.1, level) * 100 - 100, 2) + "% more damage", @@ -294,12 +299,11 @@ public MobArena(Group group, Set options) { }).addListener(InventoryPreClickEvent.class, event -> { final int slot = event.getSlot(); final ItemStack clickedItem = event.getClickedItem(); - final ItemStack cursorItem = event.getCursorItem(); if (!(slot >= PlayerInventoryUtils.HELMET_SLOT && slot <= PlayerInventoryUtils.BOOTS_SLOT)) return; - if (clickedItem.getTag(Kit.KIT_ITEM_TAG) || cursorItem.getTag(Kit.KIT_ITEM_TAG)) { + if (clickedItem.getTag(Kit.KIT_ITEM_TAG)) { event.setCancelled(true); } }); @@ -315,14 +319,14 @@ public void stop() { if (isStopping) return; isStopping = true; - if (stageInProgress && arenaInstance.getPlayers().size() > 0) { + if (stageInProgress && !arenaInstance.getPlayers().isEmpty()) { final Duration time = Duration.ofSeconds(30); final long timeoutAt = System.currentTimeMillis() + time.toMillis(); Messenger.warn(group(), "This arena is stopping. You have " + time.getSeconds() + " seconds to complete the stage"); //TODO: Use Messenger to provide nice countdowns MinecraftServer.getSchedulerManager().submitTask(() -> { - if (stageInProgress && arenaInstance.getPlayers().size() > 0 + if (stageInProgress && !arenaInstance.getPlayers().isEmpty() && System.currentTimeMillis() < timeoutAt) return TaskSchedule.duration(Duration.ofSeconds(1)); @@ -450,7 +454,7 @@ public void nextStage() { } for (Player member : group.members()) { - member.setHealth(member.getHealth() + (getUpgrade(UPGRADES.get(0)) > 0 ? 6 : 4)); // Heal 2 hearts + 1 heart if you have improved healthcare + member.setHealth(member.getHealth() + (getUpgrade(UPGRADES.getFirst()) > 0 ? 6 : 4)); // Heal 2 hearts + 1 heart if you have improved healthcare playerClass(member).apply(member); } @@ -458,7 +462,7 @@ public void nextStage() { entity.setInstance(arenaInstance, Vec.ONE .rotateAroundY(ThreadLocalRandom.current().nextDouble(2 * Math.PI)) .mul(SPAWN_RADIUS, 0, SPAWN_RADIUS) - .asPosition() + .asPos() .add(0, HEIGHT, 0)); } @@ -544,10 +548,10 @@ public boolean hasOption(@Nullable ArenaOption option) { }), Features.combat(false, (attacker, victim) -> { float damage = 1; if (attacker instanceof LivingEntity livingEntity) { - damage = livingEntity.getAttributeValue(Attribute.ATTACK_DAMAGE); + damage = (float) livingEntity.getAttributeValue(Attribute.ATTACK_DAMAGE); } else if (attacker instanceof EntityProjectile projectile && projectile.getShooter() instanceof Player player) { - final float movementSpeed = (float) (projectile.getVelocity().length() / MinecraftServer.TICK_PER_SECOND); - damage = movementSpeed * player.getAttributeValue(Attribute.ATTACK_DAMAGE); + final float movementSpeed = (float) (projectile.getVelocity().length() / ServerFlag.SERVER_TICKS_PER_SECOND); + damage = (float) (movementSpeed * player.getAttributeValue(Attribute.ATTACK_DAMAGE)); } if (attacker instanceof Player player) { @@ -568,7 +572,7 @@ public boolean hasOption(@Nullable ArenaOption option) { // 20 armor points = max reduction final float multi = (float) (-0.04f * armorPoints * Math.pow(1.15, getUpgrade(ALLOYING_UPGRADE))); - damage *= Math.max(1 + multi, 0.2); + damage *= (float) Math.max(1 + multi, 0.2); } return damage; @@ -579,7 +583,7 @@ public boolean hasOption(@Nullable ArenaOption option) { !item.getTag(Kit.KIT_ITEM_TAG) ), Features.functionalItem( // Normally you'd use a.isSimilar(b) but the tags are very much different on these items - item -> WAND.material() == item.material() && WAND.getDisplayName().equals(item.getDisplayName()), + item -> WAND.material() == item.material() && WAND.get(DataComponents.CUSTOM_NAME).equals(item.get(DataComponents.CUSTOM_NAME)), player -> { final Instance instance = player.getInstance(); final AtomicReference atomicPos = new AtomicReference<>(player.getPosition().add(0, player.getEyeHeight(), 0)); @@ -597,17 +601,17 @@ public boolean hasOption(@Nullable ArenaOption option) { .stream() .anyMatch(entity -> entity instanceof ArenaMob) || !instance.getBlock(pos).isAir() || - !instance.getWorldBorder().isInside(pos) || + !instance.getWorldBorder().inBounds(pos) || age >= 30) { - explosion(DamageType.fromPlayer(player), instance, pos, 5, 0.5f, 7, 1); + explosion(Damage.fromPlayer(player, 7), instance, pos, 5, 0.5f,1); return TaskSchedule.stop(); } - instance.sendGroupedPacket(ParticleCreator.createParticlePacket( - Particle.FIREWORK, true, pos.x(), pos.y(), pos.z(), - 0.3f, 0.3f, 0.3f, 0.01f, 50, null + instance.sendGroupedPacket(new ParticlePacket( + Particle.FIREWORK, true, true, pos, + new Vec(0.3f), 0.01f, 50 )); instance.playSound( Sound.sound(SoundEvent.ENTITY_AXOLOTL_SWIM, Sound.Source.NEUTRAL, 1, 1), @@ -627,24 +631,24 @@ public boolean hasOption(@Nullable ArenaOption option) { final Instance instance = event.getInstance(); final Pos pos = target.getPosition(); - explosion(DamageType.fromProjectile(shooter, projectile), instance, pos, 6, 1, 7, 0.3f); + explosion(Damage.fromProjectile(shooter, projectile, 7), instance, pos, 6, 1, 0.3f); }).addListener(EntityAttackEvent.class, event -> { if (!(event.getEntity() instanceof Player player)) return; if (!(event.getTarget() instanceof LivingEntity target)) return; final Instance instance = event.getInstance(); final Pos pos = target.getPosition(); - explosion(DamageType.fromPlayer(player), instance, pos, 3, 1f, 3, 0.3f); + explosion(Damage.fromPlayer(player, 3), instance, pos, 3, 1f, 0.3f); })); } return features; } - private static void explosion(DamageType damageType, Instance instance, Pos pos, int range, float offset, int damage, float volume) { - instance.sendGroupedPacket(ParticleCreator.createParticlePacket( - Particle.EXPLOSION, pos.x(), pos.y(), pos.z(), - offset, offset, offset, 5 + private static void explosion(Damage damageType, Instance instance, Pos pos, int range, float offset, float volume) { + instance.sendGroupedPacket(new ParticlePacket( + Particle.EXPLOSION, pos, + new Vec(offset), 5, 1 )); instance.playSound( Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.NEUTRAL, volume, 1), @@ -652,7 +656,7 @@ private static void explosion(DamageType damageType, Instance instance, Pos pos, ); for (Entity entity : instance.getNearbyEntities(pos, range)) { if (entity instanceof LivingEntity livingEntity && !(entity instanceof Player)) - livingEntity.damage(damageType, damage); + livingEntity.damage(damageType); } } } diff --git a/src/main/java/net/minestom/arena/game/mob/MobArenaInstance.java b/src/main/java/net/minestom/arena/game/mob/MobArenaInstance.java index f30a816..a61f1d7 100644 --- a/src/main/java/net/minestom/arena/game/mob/MobArenaInstance.java +++ b/src/main/java/net/minestom/arena/game/mob/MobArenaInstance.java @@ -1,6 +1,5 @@ package net.minestom.arena.game.mob; -import de.articdive.jnoise.core.api.pipeline.NoiseSource; import de.articdive.jnoise.generators.noisegen.opensimplex.FastSimplexNoiseGenerator; import de.articdive.jnoise.generators.noisegen.perlin.PerlinNoiseGenerator; import de.articdive.jnoise.modules.octavation.OctavationModule; @@ -24,7 +23,7 @@ final class MobArenaInstance extends InstanceContainer { MobArenaInstance() { super(UUID.randomUUID(), FullbrightDimension.INSTANCE); - getWorldBorder().setDiameter(100); + setWorldBorder(getWorldBorder().withDiameter(100)); setGenerator(unit -> { final Point start = unit.absoluteStart(); for (int x = 0; x < unit.size().x(); x++) { diff --git a/src/main/java/net/minestom/arena/game/mob/MobTestCommand.java b/src/main/java/net/minestom/arena/game/mob/MobTestCommand.java index 582c846..a8b7307 100644 --- a/src/main/java/net/minestom/arena/game/mob/MobTestCommand.java +++ b/src/main/java/net/minestom/arena/game/mob/MobTestCommand.java @@ -11,7 +11,7 @@ import net.minestom.server.command.builder.arguments.number.ArgumentNumber; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; -import net.minestom.server.entity.damage.DamageType; +import net.minestom.server.entity.damage.Damage; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.utils.MathUtils; @@ -83,7 +83,7 @@ public MobTestCommand() { .set(MobArena.MELEE_TAG, 10000).build() ), strong); - addSyntax((sender, context) -> ((Player) sender).damage(DamageType.VOID, 10), damageme); + addSyntax((sender, context) -> ((Player) sender).damage(Damage.fromPlayer((Player) sender, 10)), damageme); } private static @NotNull Optional arena(CommandSender sender) { diff --git a/src/main/java/net/minestom/arena/game/mob/NextStageInventory.java b/src/main/java/net/minestom/arena/game/mob/NextStageInventory.java index 51a13ae..41b149e 100644 --- a/src/main/java/net/minestom/arena/game/mob/NextStageInventory.java +++ b/src/main/java/net/minestom/arena/game/mob/NextStageInventory.java @@ -6,26 +6,29 @@ import net.minestom.arena.Items; import net.minestom.arena.Messenger; import net.minestom.arena.utils.ItemUtils; +import net.minestom.server.component.DataComponents; import net.minestom.server.entity.Player; +import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.TransactionOption; -import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.component.EnchantmentList; +import net.minestom.server.item.enchant.Enchantment; import net.minestom.server.sound.SoundEvent; final class NextStageInventory extends Inventory { private static final ItemStack HEADER = ItemUtils.stripItalics(ItemStack.builder(Material.PAPER) - .displayName(Component.text("Next Stage", NamedTextColor.GOLD)) + .customName(Component.text("Next Stage", NamedTextColor.GOLD)) .lore(Component.text("Buy a different class, team upgrades or just continue to the next stage", NamedTextColor.GRAY)) .build()); private static final ItemStack CLASS_SELECTION = ItemUtils.stripItalics(ItemStack.builder(Material.SHIELD) - .displayName(Component.text("Class Selection", NamedTextColor.GREEN)) + .customName(Component.text("Class Selection", NamedTextColor.GREEN)) .lore(Component.text("Buy a different class", NamedTextColor.GRAY)) .build()); private static final ItemStack TEAM_UPGRADES = ItemUtils.stripItalics(ItemStack.builder(Material.ANVIL) - .displayName(Component.text("Team Upgrades", NamedTextColor.LIGHT_PURPLE)) + .customName(Component.text("Team Upgrades", NamedTextColor.LIGHT_PURPLE)) .lore(Component.text("Buy upgrades for the whole team", NamedTextColor.GRAY)) .build()); @@ -45,8 +48,11 @@ final class NextStageInventory extends Inventory { setItemStack(30, Items.CLOSE); setItemStack(32, Items.CONTINUE); - addInventoryCondition((p, s, c, result) -> result.setCancel(true)); - addInventoryCondition((p, slot, c, r) -> { + eventNode().addListener(InventoryPreClickEvent.class, event -> { + event.setCancelled(true); + + int slot = event.getSlot(); + switch (slot) { case 12 -> player.openInventory(new ClassSelectionInventory(this)); case 14 -> player.openInventory(new TeamUpgradeInventory(this)); @@ -69,8 +75,11 @@ private final class ClassSelectionInventory extends Inventory { setItemStack(31, Items.BACK); - addInventoryCondition((p, s, c, result) -> result.setCancel(true)); - addInventoryCondition((p, slot, c, r) -> { + eventNode().addListener(InventoryPreClickEvent.class, event -> { + event.setCancelled(true); + + int slot = event.getSlot(); + if (slot == 31) player.openInventory(parent); else { final int length = MobArena.CLASSES.size(); @@ -91,11 +100,13 @@ private void draw() { for (int i = 0; i < length; i++) { ArenaClass arenaClass = MobArena.CLASSES.get(i); - setItemStack(13 - length / 2 + i, arenaClass.itemStack() - .withMeta(builder -> { - if (arena.playerClass(player).equals(arenaClass)) - builder.enchantment(Enchantment.PROTECTION, (short) 1); - })); + ItemStack itemStack = arenaClass.itemStack(); + if (arena.playerClass(player).equals(arenaClass)) { + itemStack = itemStack.with(DataComponents.ENCHANTMENTS, + new EnchantmentList(Enchantment.PROTECTION, 1)); + } + + setItemStack(13 - length / 2 + i, itemStack); } } @@ -127,8 +138,11 @@ private final class TeamUpgradeInventory extends Inventory { setItemStack(31, Items.BACK); - addInventoryCondition((p, s, c, result) -> result.setCancel(true)); - addInventoryCondition((p, slot, c, r) -> { + eventNode().addListener(InventoryPreClickEvent.class, event -> { + event.setCancelled(true); + + int slot = event.getSlot(); + if (slot == 31) player.openInventory(parent); else { final int length = MobArena.UPGRADES.size(); diff --git a/src/main/java/net/minestom/arena/game/mob/ZombieMob.java b/src/main/java/net/minestom/arena/game/mob/ZombieMob.java index 36a5973..815c353 100644 --- a/src/main/java/net/minestom/arena/game/mob/ZombieMob.java +++ b/src/main/java/net/minestom/arena/game/mob/ZombieMob.java @@ -1,10 +1,11 @@ package net.minestom.arena.game.mob; -import net.minestom.server.attribute.Attribute; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.Player; import net.minestom.server.entity.ai.goal.MeleeAttackGoal; import net.minestom.server.entity.ai.target.ClosestEntityTarget; +import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.entity.attribute.AttributeInstance; import net.minestom.server.entity.metadata.monster.zombie.ZombieMeta; import net.minestom.server.utils.time.TimeUnit; @@ -19,10 +20,16 @@ public ZombieMob(MobGenerationContext context) { List.of(new ClosestEntityTarget(this, 32, entity -> entity instanceof Player)) ); + AttributeInstance movementSpeedAttribute = getAttribute(Attribute.MOVEMENT_SPEED); + movementSpeedAttribute.setBaseValue(0.23); + boolean isBaby = context.stage() >= 5 && ThreadLocalRandom.current().nextBoolean(); ((ZombieMeta) entityMeta).setBaby(isBaby); if (isBaby) { - getAttribute(Attribute.MAX_HEALTH).setBaseValue(getMaxHealth() / 2); + movementSpeedAttribute.addModifier(ArenaMob.BABY_SPEED_MODIFIER); + + AttributeInstance attribute = getAttribute(Attribute.MAX_HEALTH); + attribute.setBaseValue(attribute.getBaseValue() / 2); heal(); } } diff --git a/src/main/java/net/minestom/arena/lobby/Lobby.java b/src/main/java/net/minestom/arena/lobby/Lobby.java index 372722b..a3b15dd 100644 --- a/src/main/java/net/minestom/arena/lobby/Lobby.java +++ b/src/main/java/net/minestom/arena/lobby/Lobby.java @@ -1,5 +1,6 @@ package net.minestom.arena.lobby; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.arena.group.Group; import net.minestom.arena.utils.FullbrightDimension; import net.minestom.server.MinecraftServer; @@ -9,9 +10,8 @@ import net.minestom.server.event.instance.AddEntityToInstanceEvent; import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.event.player.PlayerEntityInteractEvent; -import net.minestom.server.instance.AnvilLoader; import net.minestom.server.instance.Instance; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import net.minestom.server.instance.anvil.AnvilLoader; import java.nio.file.Path; @@ -50,6 +50,6 @@ private static void onArenaFinish(Player player) { player.refreshCommands(); player.getInventory().clear(); player.teleport(new Pos(0.5, 16, 0.5)); - player.tagHandler().updateContent(NBTCompound.EMPTY); + player.tagHandler().updateContent(CompoundBinaryTag.empty()); } } diff --git a/src/main/java/net/minestom/arena/lobby/Map.java b/src/main/java/net/minestom/arena/lobby/Map.java index 768dbc7..755b7a1 100644 --- a/src/main/java/net/minestom/arena/lobby/Map.java +++ b/src/main/java/net/minestom/arena/lobby/Map.java @@ -1,5 +1,6 @@ package net.minestom.arena.lobby; +import net.minestom.server.component.DataComponents; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Entity; @@ -8,9 +9,9 @@ import net.minestom.server.instance.Instance; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.metadata.MapMeta; import net.minestom.server.map.framebuffers.LargeGraphics2DFramebuffer; import net.minestom.server.network.packet.server.SendablePacket; +import net.minestom.server.utils.Direction; import org.jetbrains.annotations.NotNull; import javax.imageio.ImageIO; @@ -48,19 +49,18 @@ public static void create(@NotNull Instance instance, Point maximum) { final int maxX = maximum.blockX(); final int maxY = maximum.blockY(); final int z = maximum.blockZ(); - for (int i = 0; i < 15; i++) { - final int x = maxX - i % 5; - final int y = maxY - i / 5; - final int id = i; + for (int id = 0; id < 15; id++) { + final int x = maxX - id % 5; + final int y = maxY - id / 5; final Entity itemFrame = new Entity(EntityType.ITEM_FRAME); final ItemFrameMeta meta = (ItemFrameMeta) itemFrame.getEntityMeta(); itemFrame.setInstance(instance, new Pos(x, y, z, 180, 0)); meta.setNotifyAboutChanges(false); - meta.setOrientation(ItemFrameMeta.Orientation.NORTH); + meta.setDirection(Direction.NORTH); meta.setInvisible(true); meta.setItem(ItemStack.builder(Material.FILLED_MAP) - .meta(MapMeta.class, builder -> builder.mapId(id)) + .set(DataComponents.MAP_ID, id) .build()); meta.setNotifyAboutChanges(true); } diff --git a/src/main/java/net/minestom/arena/lobby/NPC.java b/src/main/java/net/minestom/arena/lobby/NPC.java index 1e7356a..461a96e 100644 --- a/src/main/java/net/minestom/arena/lobby/NPC.java +++ b/src/main/java/net/minestom/arena/lobby/NPC.java @@ -72,7 +72,7 @@ public void handle(@NotNull EntityAttackEvent event) { public void handle(@NotNull PlayerEntityInteractEvent event) { if (event.getTarget() != this) return; - if (event.getHand() != Player.Hand.MAIN) return; // Prevent duplicating event + if (event.getHand() != PlayerHand.MAIN) return; // Prevent duplicating event event.getEntity().playSound(Sound.sound() .type(SoundEvent.BLOCK_NOTE_BLOCK_PLING) @@ -90,7 +90,7 @@ public void updateNewViewer(@NotNull Player player) { player.sendPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.ADD_PLAYER, new PlayerInfoUpdatePacket.Entry( getUuid(), name, properties, false, 0, GameMode.SURVIVAL, null, - null) + null, 0) ) ); diff --git a/src/main/java/net/minestom/arena/utils/FullbrightDimension.java b/src/main/java/net/minestom/arena/utils/FullbrightDimension.java index cbc45c3..ae78fd6 100644 --- a/src/main/java/net/minestom/arena/utils/FullbrightDimension.java +++ b/src/main/java/net/minestom/arena/utils/FullbrightDimension.java @@ -1,15 +1,15 @@ package net.minestom.arena.utils; +import net.kyori.adventure.key.Key; import net.minestom.server.MinecraftServer; -import net.minestom.server.utils.NamespaceID; +import net.minestom.server.registry.RegistryKey; import net.minestom.server.world.DimensionType; public class FullbrightDimension { - public static final DimensionType INSTANCE = DimensionType.builder(NamespaceID.from("minestom:full_bright")) - .ambientLight(2.0f) - .build(); - - static { - MinecraftServer.getDimensionTypeManager().addDimension(INSTANCE); - } + public static final RegistryKey INSTANCE = MinecraftServer.getDimensionTypeRegistry() + .register(Key.key("minestom", "fullbright"), + DimensionType.builder() + .ambientLight(1.0f) + .build() + ); } diff --git a/src/main/java/net/minestom/arena/utils/ItemUtils.java b/src/main/java/net/minestom/arena/utils/ItemUtils.java index 3d4ddd0..a067ec9 100644 --- a/src/main/java/net/minestom/arena/utils/ItemUtils.java +++ b/src/main/java/net/minestom/arena/utils/ItemUtils.java @@ -2,11 +2,12 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextDecoration; -import net.minestom.server.item.ItemHideFlag; -import net.minestom.server.item.ItemMeta; +import net.minestom.server.component.DataComponents; import net.minestom.server.item.ItemStack; import org.jetbrains.annotations.Contract; +import java.util.List; + public final class ItemUtils { private ItemUtils() { } @@ -26,13 +27,11 @@ public static Component stripItalics(Component component) { public static ItemStack stripItalics(ItemStack itemStack) { if (itemStack == null) return null; - return itemStack.withDisplayName(ItemUtils::stripItalics) - .withLore(lore -> lore.stream() - .map(ItemUtils::stripItalics) - .toList()); - } + Component previousName = itemStack.get(DataComponents.CUSTOM_NAME); + List previousLore = itemStack.get(DataComponents.LORE); - public static ItemMeta.Builder hideFlags(ItemMeta.Builder builder) { - return builder.hideFlag(ItemHideFlag.values()); + return itemStack + .with(DataComponents.CUSTOM_NAME, stripItalics(previousName)) + .with(DataComponents.LORE, previousLore.stream().map(ItemUtils::stripItalics).toList()); } }