diff --git a/pom.xml b/pom.xml index 07cfb89..9f2a475 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ com.loohp Limbo Limbo - 0.6.19-ALPHA + 0.6.20-ALPHA Standalone Limbo Minecraft Server. https://github.com/LOOHP/Limbo @@ -256,31 +256,31 @@ net.kyori adventure-text-serializer-gson - 4.10.1 + 4.12.0 compile net.kyori adventure-text-serializer-legacy - 4.10.1 + 4.12.0 compile net.kyori adventure-text-serializer-plain - 4.10.1 + 4.12.0 compile net.kyori adventure-api - 4.10.1 + 4.12.0 compile net.kyori adventure-nbt - 4.10.1 + 4.12.0 compile diff --git a/src/main/java/com/loohp/limbo/Limbo.java b/src/main/java/com/loohp/limbo/Limbo.java index 8eef992..3f83cbf 100644 --- a/src/main/java/com/loohp/limbo/Limbo.java +++ b/src/main/java/com/loohp/limbo/Limbo.java @@ -19,42 +19,9 @@ package com.loohp.limbo; -import java.awt.GraphicsEnvironment; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeMap; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.loohp.limbo.bossbar.KeyedBossBar; import com.loohp.limbo.commands.CommandSender; import com.loohp.limbo.commands.DefaultCommands; import com.loohp.limbo.consolegui.GUI; @@ -66,6 +33,7 @@ import com.loohp.limbo.network.ServerConnection; import com.loohp.limbo.network.protocol.packets.Packet; import com.loohp.limbo.network.protocol.packets.PacketIn; import com.loohp.limbo.network.protocol.packets.PacketOut; +import com.loohp.limbo.network.protocol.packets.PacketPlayOutBoss; import com.loohp.limbo.permissions.PermissionsManager; import com.loohp.limbo.player.Player; import com.loohp.limbo.plugins.LimboPlugin; @@ -74,21 +42,56 @@ import com.loohp.limbo.scheduler.LimboScheduler; import com.loohp.limbo.scheduler.Tick; import com.loohp.limbo.utils.CustomStringUtils; import com.loohp.limbo.utils.ImageUtils; +import com.loohp.limbo.utils.NamespacedKey; import com.loohp.limbo.utils.NetworkUtils; import com.loohp.limbo.world.DimensionRegistry; import com.loohp.limbo.world.Environment; import com.loohp.limbo.world.Schematic; import com.loohp.limbo.world.World; - +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.querz.nbt.io.NBTUtil; import net.querz.nbt.tag.CompoundTag; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import javax.swing.UnsupportedLookAndFeelException; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; -public class Limbo { +public final class Limbo { public static final String LIMBO_BRAND = "Limbo"; @@ -135,39 +138,41 @@ public class Limbo { public final int SERVER_IMPLEMENTATION_PROTOCOL = 761; public final String LIMBO_IMPLEMENTATION_VERSION; - private AtomicBoolean isRunning; + private final AtomicBoolean isRunning; - private ServerConnection server; - private Console console; + private final ServerConnection server; + private final Console console; - private List worlds = new ArrayList<>(); - private Map playersByName = new HashMap<>(); - private Map playersByUUID = new HashMap<>(); + private final List worlds = new CopyOnWriteArrayList<>(); + final Map playersByName = new ConcurrentHashMap<>(); + final Map playersByUUID = new ConcurrentHashMap<>(); + private final Map bossBars = new ConcurrentHashMap<>(); - private ServerProperties properties; + private final ServerProperties properties; - private PluginManager pluginManager; - private EventsManager eventsManager; - private PermissionsManager permissionManager; - private File pluginFolder; + private final PluginManager pluginManager; + private final EventsManager eventsManager; + private final PermissionsManager permissionManager; + private final File pluginFolder; - private File internalDataFolder; + private final File internalDataFolder; - private DimensionRegistry dimensionRegistry; + private final DimensionRegistry dimensionRegistry; - private Tick tick; - private LimboScheduler scheduler; + private final Tick tick; + private final LimboScheduler scheduler; - private Metrics metrics; + private final Metrics metrics; - public AtomicInteger entityIdCount = new AtomicInteger(); + public final AtomicInteger entityIdCount = new AtomicInteger(); @SuppressWarnings("deprecation") - private Unsafe unsafe = new Unsafe(); + private Unsafe unsafe; @SuppressWarnings("unchecked") public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException { instance = this; + unsafe = new Unsafe(this); isRunning = new AtomicBoolean(true); if (!noGui) { @@ -305,7 +310,7 @@ public class Limbo { e.printStackTrace(); } } - + scheduler = new LimboScheduler(); tick = new Tick(this); @@ -428,7 +433,31 @@ public class Limbo { worlds.remove(world); } } - + + public KeyedBossBar createBossBar(NamespacedKey namespacedKey, Component name, float progress, BossBar.Color color, BossBar.Overlay overlay, BossBar.Flag... flags) { + KeyedBossBar keyedBossBar = new KeyedBossBar(namespacedKey, BossBar.bossBar(name, progress, color, overlay, new HashSet<>(Arrays.asList(flags)))); + bossBars.put(namespacedKey, keyedBossBar); + return keyedBossBar; + } + + public void removeBossBar(NamespacedKey namespacedKey) { + KeyedBossBar keyedBossBar = bossBars.remove(namespacedKey); + keyedBossBar.getProperties().removeListener(keyedBossBar.getUnsafe().getLimboListener()); + keyedBossBar.getUnsafe().invalidate(); + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(keyedBossBar, PacketPlayOutBoss.BossBarAction.REMOVE); + for (Player player : keyedBossBar.getPlayers()) { + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public Map getBossBars() { + return Collections.unmodifiableMap(bossBars); + } + public ServerProperties getServerProperties() { return properties; } @@ -457,16 +486,6 @@ public class Limbo { return playersByUUID.get(uuid); } - public void addPlayer(Player player) { - playersByName.put(player.getName(), player); - playersByUUID.put(player.getUniqueId(), player); - } - - public void removePlayer(Player player) { - playersByName.remove(player.getName()); - playersByUUID.remove(player.getUniqueId()); - } - public List getWorlds() { return new ArrayList<>(worlds); } diff --git a/src/main/java/com/loohp/limbo/Unsafe.java b/src/main/java/com/loohp/limbo/Unsafe.java index a76779d..c148ea0 100644 --- a/src/main/java/com/loohp/limbo/Unsafe.java +++ b/src/main/java/com/loohp/limbo/Unsafe.java @@ -28,13 +28,16 @@ import com.loohp.limbo.player.Player; import com.loohp.limbo.utils.GameMode; import com.loohp.limbo.world.World; +@SuppressWarnings("DeprecatedIsStillUsed") @Deprecated public class Unsafe { - + + private final Limbo instance; private com.loohp.limbo.player.Unsafe playerUnsafe; private com.loohp.limbo.world.Unsafe worldUnsafe; - protected Unsafe() { + protected Unsafe(Limbo instance) { + this.instance = instance; try { Constructor playerConstructor = com.loohp.limbo.player.Unsafe.class.getDeclaredConstructor(); playerConstructor.setAccessible(true); @@ -78,4 +81,17 @@ public class Unsafe { playerUnsafe.a(player, location); } + @Deprecated + public void addPlayer(Player player) { + instance.playersByName.put(player.getName(), player); + instance.playersByUUID.put(player.getUniqueId(), player); + } + + @Deprecated + public void removePlayer(Player player) { + instance.getBossBars().values().forEach(each -> each.hidePlayer(player)); + instance.playersByName.remove(player.getName()); + instance.playersByUUID.remove(player.getUniqueId()); + } + } diff --git a/src/main/java/com/loohp/limbo/bossbar/KeyedBossBar.java b/src/main/java/com/loohp/limbo/bossbar/KeyedBossBar.java new file mode 100644 index 0000000..06edd31 --- /dev/null +++ b/src/main/java/com/loohp/limbo/bossbar/KeyedBossBar.java @@ -0,0 +1,176 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.bossbar; + +import com.loohp.limbo.network.protocol.packets.PacketPlayOutBoss; +import com.loohp.limbo.player.Player; +import com.loohp.limbo.utils.NamespacedKey; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.Collections; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +public class KeyedBossBar { + + private final UUID uuid; + private final NamespacedKey key; + private final BossBar properties; + private final Set players; + protected final LimboBossBarHandler listener; + protected final AtomicBoolean valid; + private final Unsafe unsafe; + + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated + public KeyedBossBar(NamespacedKey key, BossBar properties) { + this.uuid = UUID.randomUUID(); + this.key = key; + this.properties = properties; + this.players = ConcurrentHashMap.newKeySet(); + this.listener = new LimboBossBarHandler(this); + this.properties.addListener(listener); + this.valid = new AtomicBoolean(true); + this.unsafe = new Unsafe(this); + } + + public UUID getUniqueId() { + return uuid; + } + + public NamespacedKey getKey() { + return key; + } + + public BossBar getProperties() { + return properties; + } + + public Set getPlayers() { + return Collections.unmodifiableSet(players); + } + + public UUID getUuid() { + return uuid; + } + + public boolean isValid() { + return valid.get(); + } + + @Deprecated + public Unsafe getUnsafe() { + return unsafe; + } + + public boolean showPlayer(Player player) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(this, PacketPlayOutBoss.BossBarAction.ADD); + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException ignore) { + } + return players.add(player); + } + + public boolean hidePlayer(Player player) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(this, PacketPlayOutBoss.BossBarAction.REMOVE); + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException ignore) { + } + return players.remove(player); + } + + public static class LimboBossBarHandler implements BossBar.Listener { + + private final KeyedBossBar parent; + + private LimboBossBarHandler(KeyedBossBar parent) { + this.parent = parent; + } + + @Override + public void bossBarNameChanged(@NotNull BossBar bar, @NotNull Component oldName, @NotNull Component newName) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(parent, PacketPlayOutBoss.BossBarAction.UPDATE_NAME); + for (Player player : parent.getPlayers()) { + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void bossBarProgressChanged(@NotNull BossBar bar, float oldProgress, float newProgress) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(parent, PacketPlayOutBoss.BossBarAction.UPDATE_PROGRESS); + for (Player player : parent.getPlayers()) { + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void bossBarColorChanged(@NotNull BossBar bar, BossBar.@NotNull Color oldColor, BossBar.@NotNull Color newColor) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(parent, PacketPlayOutBoss.BossBarAction.UPDATE_STYLE); + for (Player player : parent.getPlayers()) { + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void bossBarOverlayChanged(@NotNull BossBar bar, BossBar.@NotNull Overlay oldOverlay, BossBar.@NotNull Overlay newOverlay) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(parent, PacketPlayOutBoss.BossBarAction.UPDATE_STYLE); + for (Player player : parent.getPlayers()) { + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void bossBarFlagsChanged(@NotNull BossBar bar, @NotNull Set flagsAdded, @NotNull Set flagsRemoved) { + PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(parent, PacketPlayOutBoss.BossBarAction.UPDATE_PROPERTIES); + for (Player player : parent.getPlayers()) { + try { + player.clientConnection.sendPacket(packetPlayOutBoss); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + } + +} diff --git a/src/main/java/com/loohp/limbo/bossbar/Unsafe.java b/src/main/java/com/loohp/limbo/bossbar/Unsafe.java new file mode 100644 index 0000000..1322f52 --- /dev/null +++ b/src/main/java/com/loohp/limbo/bossbar/Unsafe.java @@ -0,0 +1,42 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.bossbar; + +@SuppressWarnings("DeprecatedIsStillUsed") +@Deprecated +public class Unsafe { + + private final KeyedBossBar instance; + + protected Unsafe(KeyedBossBar instance) { + this.instance = instance; + } + + @Deprecated + public KeyedBossBar.LimboBossBarHandler getLimboListener() { + return instance.listener; + } + + @Deprecated + public void invalidate() { + instance.valid.set(false); + } + +} diff --git a/src/main/java/com/loohp/limbo/commands/CommandSender.java b/src/main/java/com/loohp/limbo/commands/CommandSender.java index 97d0870..77ceedb 100644 --- a/src/main/java/com/loohp/limbo/commands/CommandSender.java +++ b/src/main/java/com/loohp/limbo/commands/CommandSender.java @@ -34,46 +34,46 @@ import net.md_5.bungee.api.chat.BaseComponent; public interface CommandSender extends Audience { - public void sendMessage(BaseComponent[] component, UUID uuid); + void sendMessage(BaseComponent[] component, UUID uuid); - public void sendMessage(BaseComponent component, UUID uuid); + void sendMessage(BaseComponent component, UUID uuid); - public void sendMessage(String message, UUID uuid); + void sendMessage(String message, UUID uuid); - public void sendMessage(BaseComponent[] component); + void sendMessage(BaseComponent[] component); - public void sendMessage(BaseComponent component); + void sendMessage(BaseComponent component); - public void sendMessage(String message); + void sendMessage(String message); - public boolean hasPermission(String permission); + boolean hasPermission(String permission); - public String getName(); - - public void sendMessage(Identity source, Component message, MessageType type); - - public void openBook(Book book); - - public void stopSound(SoundStop stop); - - public void playSound(Sound sound, Sound.Emitter emitter); - - public void playSound(Sound sound, double x, double y, double z); - - public void playSound(Sound sound); - - public void sendActionBar(Component message); - - public void sendPlayerListHeaderAndFooter(Component header, Component footer); - - public void sendTitlePart(TitlePart part, T value); - - public void clearTitle(); - - public void resetTitle(); - - public void showBossBar(BossBar bar); + String getName(); - public void hideBossBar(BossBar bar); + void sendMessage(Identity source, Component message, MessageType type); + + void openBook(Book book); + + void stopSound(SoundStop stop); + + void playSound(Sound sound, Sound.Emitter emitter); + + void playSound(Sound sound, double x, double y, double z); + + void playSound(Sound sound); + + void sendActionBar(Component message); + + void sendPlayerListHeaderAndFooter(Component header, Component footer); + + void sendTitlePart(TitlePart part, T value); + + void clearTitle(); + + void resetTitle(); + + void showBossBar(BossBar bar); + + void hideBossBar(BossBar bar); } diff --git a/src/main/java/com/loohp/limbo/entity/Entity.java b/src/main/java/com/loohp/limbo/entity/Entity.java index 1c26d77..eb6dac2 100644 --- a/src/main/java/com/loohp/limbo/entity/Entity.java +++ b/src/main/java/com/loohp/limbo/entity/Entity.java @@ -28,11 +28,12 @@ import com.loohp.limbo.location.Location; import com.loohp.limbo.utils.BungeecordAdventureConversionUtils; import com.loohp.limbo.world.World; +import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.md_5.bungee.api.chat.BaseComponent; -public abstract class Entity { +public abstract class Entity implements Sound.Emitter { @WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x01) protected boolean onFire = false; diff --git a/src/main/java/com/loohp/limbo/network/Channel.java b/src/main/java/com/loohp/limbo/network/Channel.java index fc24e25..5df2265 100644 --- a/src/main/java/com/loohp/limbo/network/Channel.java +++ b/src/main/java/com/loohp/limbo/network/Channel.java @@ -48,7 +48,7 @@ public class Channel implements AutoCloseable { private void ensureOpen() { if (!valid.get()) { - throw new IllegalStateException("Channel already closed!"); + close(); } } @@ -106,10 +106,13 @@ public class Channel implements AutoCloseable { } @Override - public synchronized void close() throws Exception { + public synchronized void close() { if (valid.compareAndSet(true, false)) { - input.close(); - output.close(); + try { + input.close(); + output.close(); + } catch (Exception ignore) { + } } } diff --git a/src/main/java/com/loohp/limbo/network/ClientConnection.java b/src/main/java/com/loohp/limbo/network/ClientConnection.java index 2ebb860..fd16033 100644 --- a/src/main/java/com/loohp/limbo/network/ClientConnection.java +++ b/src/main/java/com/loohp/limbo/network/ClientConnection.java @@ -491,7 +491,7 @@ public class ClientConnection extends Thread { player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager()); player.setSkinLayers((byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40)); - Limbo.getInstance().addPlayer(player); + Limbo.getInstance().getUnsafe().addPlayer(player); break; } else if (packetIn instanceof PacketLoginInPluginMessaging) { PacketLoginInPluginMessaging response = (PacketLoginInPluginMessaging) packetIn; @@ -519,7 +519,7 @@ public class ClientConnection extends Thread { player = new Player(this, data.getUsername(), data.getUuid(), Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager()); player.setSkinLayers((byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40)); - Limbo.getInstance().addPlayer(player); + Limbo.getInstance().getUnsafe().addPlayer(player); break; } @@ -757,7 +757,7 @@ public class ClientConnection extends Thread { state = ClientState.DISCONNECTED; if (player != null) { - Limbo.getInstance().removePlayer(player); + Limbo.getInstance().getUnsafe().removePlayer(player); } Limbo.getInstance().getServerConnection().getClients().remove(this); running = false; diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/ClientboundSetActionBarTextPacket.java b/src/main/java/com/loohp/limbo/network/protocol/packets/ClientboundSetActionBarTextPacket.java new file mode 100644 index 0000000..63d6088 --- /dev/null +++ b/src/main/java/com/loohp/limbo/network/protocol/packets/ClientboundSetActionBarTextPacket.java @@ -0,0 +1,53 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.network.protocol.packets; + +import com.loohp.limbo.utils.DataTypeIO; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class ClientboundSetActionBarTextPacket extends PacketOut { + + private Component actionBar; + + public ClientboundSetActionBarTextPacket(Component actionBar) { + this.actionBar = actionBar; + } + + public Component getActionBar() { + return actionBar; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + DataTypeIO.writeString(output, GsonComponentSerializer.gson().serialize(actionBar), StandardCharsets.UTF_8); + + return buffer.toByteArray(); + } +} diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutBoss.java b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutBoss.java new file mode 100644 index 0000000..6a81aba --- /dev/null +++ b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutBoss.java @@ -0,0 +1,117 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.network.protocol.packets; + +import com.loohp.limbo.bossbar.KeyedBossBar; +import com.loohp.limbo.utils.DataTypeIO; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class PacketPlayOutBoss extends PacketOut { + + public enum BossBarAction { + ADD, + REMOVE, + UPDATE_PROGRESS, + UPDATE_NAME, + UPDATE_STYLE, + UPDATE_PROPERTIES; + } + + private static int encodeProperties(boolean darkenScreen, boolean playMusic, boolean createWorldFog) { + int i = 0; + if (darkenScreen) { + i |= 1; + } + if (playMusic) { + i |= 2; + } + if (createWorldFog) { + i |= 4; + } + return i; + } + + private KeyedBossBar bossBar; + private BossBarAction action; + + public PacketPlayOutBoss(KeyedBossBar bossBar, BossBarAction action) { + this.bossBar = bossBar; + this.action = action; + } + + public KeyedBossBar getBossBar() { + return bossBar; + } + + public BossBarAction getAction() { + return action; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + + DataTypeIO.writeUUID(output, bossBar.getUniqueId()); + DataTypeIO.writeVarInt(output, action.ordinal()); + + BossBar properties = bossBar.getProperties(); + switch (action) { + case ADD: { + DataTypeIO.writeString(output, GsonComponentSerializer.gson().serialize(properties.name()), StandardCharsets.UTF_8); + output.writeFloat(properties.progress()); + DataTypeIO.writeVarInt(output, properties.color().ordinal()); + DataTypeIO.writeVarInt(output, properties.overlay().ordinal()); + output.writeByte(encodeProperties(properties.hasFlag(BossBar.Flag.DARKEN_SCREEN), properties.hasFlag(BossBar.Flag.PLAY_BOSS_MUSIC), properties.hasFlag(BossBar.Flag.CREATE_WORLD_FOG))); + break; + } + case REMOVE: { + break; + } + case UPDATE_PROGRESS: { + output.writeFloat(properties.progress()); + break; + } + case UPDATE_NAME: { + DataTypeIO.writeString(output, GsonComponentSerializer.gson().serialize(properties.name()), StandardCharsets.UTF_8); + break; + } + case UPDATE_STYLE: { + DataTypeIO.writeVarInt(output, properties.color().ordinal()); + DataTypeIO.writeVarInt(output, properties.overlay().ordinal()); + break; + } + case UPDATE_PROPERTIES: { + output.writeByte(encodeProperties(properties.hasFlag(BossBar.Flag.DARKEN_SCREEN), properties.hasFlag(BossBar.Flag.PLAY_BOSS_MUSIC), properties.hasFlag(BossBar.Flag.CREATE_WORLD_FOG))); + break; + } + } + + return buffer.toByteArray(); + } +} diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutNamedSoundEffect.java b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutNamedSoundEffect.java new file mode 100644 index 0000000..d175e84 --- /dev/null +++ b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutNamedSoundEffect.java @@ -0,0 +1,112 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.network.protocol.packets; + +import com.loohp.limbo.sounds.SoundEffect; +import com.loohp.limbo.utils.DataTypeIO; +import net.kyori.adventure.sound.Sound; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +public class PacketPlayOutNamedSoundEffect extends PacketOut { + + private SoundEffect sound; + private Sound.Source source; + private int x; + private int y; + private int z; + private float volume; + private float pitch; + private long seed; + + public PacketPlayOutNamedSoundEffect(SoundEffect sound, Sound.Source source, double x, double y, double z, float volume, float pitch, long seed) { + this.sound = sound; + this.source = source; + this.x = (int) (x * 8.0); + this.y = (int) (y * 8.0); + this.z = (int) (z * 8.0); + this.volume = volume; + this.pitch = pitch; + this.seed = seed; + } + + public SoundEffect getSound() { + return sound; + } + + public Sound.Source getSource() { + return source; + } + + public double getX() { + return (float) this.x / 8.0F; + } + + public double getY() { + return (float) this.y / 8.0F; + } + + public double getZ() { + return (float) this.z / 8.0F; + } + + public float getVolume() { + return volume; + } + + public float getPitch() { + return pitch; + } + + public long getSeed() { + return seed; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + + DataTypeIO.writeVarInt(output, 0); + DataTypeIO.writeString(output, sound.getSound().toString(), StandardCharsets.UTF_8); + Optional fixedRange = sound.fixedRange(); + if (fixedRange.isPresent()) { + output.writeBoolean(true); + output.writeFloat(fixedRange.get()); + } else { + output.writeBoolean(false); + } + DataTypeIO.writeVarInt(output, source.ordinal()); + output.writeInt(x); + output.writeInt(y); + output.writeInt(z); + output.writeFloat(volume); + output.writeFloat(pitch); + output.writeLong(seed); + + return buffer.toByteArray(); + } +} diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutStopSound.java b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutStopSound.java new file mode 100644 index 0000000..2201d49 --- /dev/null +++ b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutStopSound.java @@ -0,0 +1,74 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.network.protocol.packets; + +import com.loohp.limbo.utils.DataTypeIO; +import com.loohp.limbo.utils.NamespacedKey; +import net.kyori.adventure.sound.Sound; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class PacketPlayOutStopSound extends PacketOut { + + private NamespacedKey sound; + private Sound.Source source; + + public PacketPlayOutStopSound(NamespacedKey sound, Sound.Source source) { + this.sound = sound; + this.source = source; + } + + public NamespacedKey getSound() { + return sound; + } + + public Sound.Source getSource() { + return source; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + + if (source != null) { + if (sound != null) { + output.writeByte(3); + DataTypeIO.writeVarInt(output, source.ordinal()); + DataTypeIO.writeString(output, sound.toString(), StandardCharsets.UTF_8); + } else { + output.writeByte(1); + DataTypeIO.writeVarInt(output, source.ordinal()); + } + } else if (sound != null) { + output.writeByte(2); + DataTypeIO.writeString(output, sound.toString(), StandardCharsets.UTF_8); + } else { + output.writeByte(0); + } + + return buffer.toByteArray(); + } +} diff --git a/src/main/java/com/loohp/limbo/player/Player.java b/src/main/java/com/loohp/limbo/player/Player.java index dac915e..a2e854d 100644 --- a/src/main/java/com/loohp/limbo/player/Player.java +++ b/src/main/java/com/loohp/limbo/player/Player.java @@ -31,6 +31,7 @@ import com.loohp.limbo.events.player.PlayerTeleportEvent; import com.loohp.limbo.location.Location; import com.loohp.limbo.network.ClientConnection; import com.loohp.limbo.network.protocol.packets.ClientboundClearTitlesPacket; +import com.loohp.limbo.network.protocol.packets.ClientboundSetActionBarTextPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSetSubtitleTextPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSetTitleTextPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSetTitlesAnimationPacket; @@ -38,10 +39,13 @@ import com.loohp.limbo.network.protocol.packets.ClientboundSystemChatPacket; import com.loohp.limbo.network.protocol.packets.PacketOut; import com.loohp.limbo.network.protocol.packets.PacketPlayOutGameState; import com.loohp.limbo.network.protocol.packets.PacketPlayOutHeldItemChange; +import com.loohp.limbo.network.protocol.packets.PacketPlayOutNamedSoundEffect; import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerListHeaderFooter; import com.loohp.limbo.network.protocol.packets.PacketPlayOutPositionAndLook; import com.loohp.limbo.network.protocol.packets.PacketPlayOutResourcePackSend; import com.loohp.limbo.network.protocol.packets.PacketPlayOutRespawn; +import com.loohp.limbo.network.protocol.packets.PacketPlayOutStopSound; +import com.loohp.limbo.sounds.SoundEffect; import com.loohp.limbo.utils.BungeecordAdventureConversionUtils; import com.loohp.limbo.utils.GameMode; import com.loohp.limbo.utils.MessageSignature; @@ -50,6 +54,7 @@ import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.inventory.Book; +import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.sound.Sound.Emitter; import net.kyori.adventure.sound.SoundStop; @@ -65,6 +70,7 @@ import java.io.IOException; import java.time.Duration; import java.time.Instant; import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; public class Player extends LivingEntity implements CommandSender { @@ -448,7 +454,13 @@ public class Player extends LivingEntity implements CommandSender { @Override public void stopSound(SoundStop stop) { - throw new UnsupportedOperationException("This function has not been implemented yet."); + Key sound = stop.sound(); + PacketPlayOutStopSound stopSound = new PacketPlayOutStopSound(sound == null ? null : NamespacedKey.fromKey(sound), stop.source()); + try { + clientConnection.sendPacket(stopSound); + } catch (IOException e) { + e.printStackTrace(); + } } @Override @@ -458,27 +470,37 @@ public class Player extends LivingEntity implements CommandSender { @Override public void playSound(Sound sound, double x, double y, double z) { - throw new UnsupportedOperationException("This function has not been implemented yet."); + PacketPlayOutNamedSoundEffect namedSoundEffect = new PacketPlayOutNamedSoundEffect( + SoundEffect.createVariableRangeEvent(NamespacedKey.fromKey(sound.name())), + sound.source(), x, y, z, sound.volume(), sound.pitch(), sound.seed().orElse(ThreadLocalRandom.current().nextLong()) + ); + try { + clientConnection.sendPacket(namedSoundEffect); + } catch (IOException e) { + e.printStackTrace(); + } } @Override public void playSound(Sound sound) { - throw new UnsupportedOperationException("This function has not been implemented yet."); + playSound(sound, x, y, z); } @Override public void sendActionBar(Component message) { try { - ClientboundSystemChatPacket chat = new ClientboundSystemChatPacket(message, true); - clientConnection.sendPacket(chat); - } catch (IOException ignored) {} + ClientboundSetActionBarTextPacket setActionBar = new ClientboundSetActionBarTextPacket(message); + clientConnection.sendPacket(setActionBar); + } catch (IOException e) { + e.printStackTrace(); + } } @Override public void sendPlayerListHeaderAndFooter(Component header, Component footer) { try { - PacketPlayOutPlayerListHeaderFooter packsend = new PacketPlayOutPlayerListHeaderFooter(header, footer); - clientConnection.sendPacket(packsend); + PacketPlayOutPlayerListHeaderFooter listHeaderFooter = new PacketPlayOutPlayerListHeaderFooter(header, footer); + clientConnection.sendPacket(listHeaderFooter); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/com/loohp/limbo/scheduler/Tick.java b/src/main/java/com/loohp/limbo/scheduler/Tick.java index 4f668ed..7c4619f 100644 --- a/src/main/java/com/loohp/limbo/scheduler/Tick.java +++ b/src/main/java/com/loohp/limbo/scheduler/Tick.java @@ -40,88 +40,82 @@ public class Tick { private Queue asyncTasksQueue = new ConcurrentLinkedQueue<>(); public Tick(Limbo instance) { - new Thread(new Runnable() { - @Override - public void run() { - tickingInterval = (int) Math.round(1000.0 / Limbo.getInstance().getServerProperties().getDefinedTicksPerSecond()); - - for (int i = 0; i < 4; i++) { - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - while (instance.isRunning()) { - LimboSchedulerTask task = asyncTasksQueue.poll(); - if (task == null) { - try { - TimeUnit.NANOSECONDS.sleep(10000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } else { - LimboTask limboTask = task.getTask(); - try { - limboTask.run(); - } catch (Throwable e) { - System.err.println("Task " + task.getTaskId() + " threw an exception: " + e.getLocalizedMessage()); - e.printStackTrace(); - } - } - } - } - }); - thread.start(); - threads.add(thread); - } - - while (instance.isRunning()) { - long start = System.currentTimeMillis(); - tick.incrementAndGet(); - instance.getPlayers().forEach(each -> { - if (each.clientConnection.isReady()) { + new Thread(() -> { + tickingInterval = (int) Math.round(1000.0 / Limbo.getInstance().getServerProperties().getDefinedTicksPerSecond()); + + for (int i = 0; i < 4; i++) { + Thread thread = new Thread(() -> { + while (instance.isRunning()) { + LimboSchedulerTask task = asyncTasksQueue.poll(); + if (task == null) { try { - each.playerInteractManager.update(); - } catch (IOException e) { + TimeUnit.NANOSECONDS.sleep(10000); + } catch (InterruptedException e) { e.printStackTrace(); } - /* - try { - each.getDataWatcher().update(); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - */ - } - }); - instance.getWorlds().forEach(each -> { - try { - each.update(); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - }); - - CurrentSchedulerTask tasks = instance.getScheduler().collectTasks(getCurrentTick()); - if (tasks != null) { - asyncTasksQueue.addAll(tasks.getAsyncTasks()); - - tasks.getSyncedTasks().forEach(task -> { - LimboTask limboTask = task.getTask(); + } else { + LimboTask limboTask = task.getTask(); try { limboTask.run(); } catch (Throwable e) { System.err.println("Task " + task.getTaskId() + " threw an exception: " + e.getLocalizedMessage()); e.printStackTrace(); } - }); - } - - long end = System.currentTimeMillis(); - try { - TimeUnit.MILLISECONDS.sleep(tickingInterval - (end - start)); - } catch (InterruptedException e) { + } + } + }); + thread.start(); + threads.add(thread); + } + + while (instance.isRunning()) { + long start = System.currentTimeMillis(); + tick.incrementAndGet(); + instance.getPlayers().forEach(each -> { + if (each.clientConnection.isReady()) { + try { + each.playerInteractManager.update(); + } catch (IOException e) { + e.printStackTrace(); + } + /* + try { + each.getDataWatcher().update(); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + */ + } + }); + instance.getWorlds().forEach(each -> { + try { + each.update(); + } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } - } + }); + + CurrentSchedulerTask tasks = instance.getScheduler().collectTasks(getCurrentTick()); + if (tasks != null) { + asyncTasksQueue.addAll(tasks.getAsyncTasks()); + + tasks.getSyncedTasks().forEach(task -> { + LimboTask limboTask = task.getTask(); + try { + limboTask.run(); + } catch (Throwable e) { + System.err.println("Task " + task.getTaskId() + " threw an exception: " + e.getLocalizedMessage()); + e.printStackTrace(); + } + }); + } + + long end = System.currentTimeMillis(); + try { + TimeUnit.MILLISECONDS.sleep(tickingInterval - (end - start)); + } catch (InterruptedException e) { + e.printStackTrace(); + } } }).start(); } diff --git a/src/main/java/com/loohp/limbo/sounds/SoundEffect.java b/src/main/java/com/loohp/limbo/sounds/SoundEffect.java new file mode 100644 index 0000000..bd1feba --- /dev/null +++ b/src/main/java/com/loohp/limbo/sounds/SoundEffect.java @@ -0,0 +1,61 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * Copyright (C) 2022. Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.loohp.limbo.sounds; + +import com.loohp.limbo.utils.NamespacedKey; + +import java.util.Optional; + +public class SoundEffect { + + public static SoundEffect createVariableRangeEvent(NamespacedKey namespacedKey) { + return new SoundEffect(namespacedKey, 16.0F, false); + } + + public static SoundEffect createFixedRangeEvent(NamespacedKey namespacedKey, float range) { + return new SoundEffect(namespacedKey, range, true); + } + + private final NamespacedKey sound; + private final float range; + private final boolean newSystem; + + private SoundEffect(NamespacedKey sound, float range, boolean newSystem) { + this.sound = sound; + this.range = range; + this.newSystem = newSystem; + } + + public NamespacedKey getSound() { + return sound; + } + + public float getRange() { + return range; + } + + public boolean isNewSystem() { + return newSystem; + } + + public Optional fixedRange() { + return this.newSystem ? Optional.of(this.range) : Optional.empty(); + } +} diff --git a/src/main/java/com/loohp/limbo/utils/NamespacedKey.java b/src/main/java/com/loohp/limbo/utils/NamespacedKey.java index 7733d2b..721babd 100644 --- a/src/main/java/com/loohp/limbo/utils/NamespacedKey.java +++ b/src/main/java/com/loohp/limbo/utils/NamespacedKey.java @@ -19,12 +19,25 @@ package com.loohp.limbo.utils; +import com.loohp.limbo.plugins.LimboPlugin; +import net.kyori.adventure.key.Key; + +import java.util.Objects; + public class NamespacedKey { public static final String MINECRAFT_KEY = "minecraft"; - private String namespace; - private String key; + public static NamespacedKey minecraft(String key) { + return new NamespacedKey(MINECRAFT_KEY, key); + } + + public static NamespacedKey fromKey(Key key) { + return new NamespacedKey(key.namespace(), key.value()); + } + + private final String namespace; + private final String key; public NamespacedKey(String namespacedKey) { int index = namespacedKey.indexOf(":"); @@ -37,14 +50,14 @@ public class NamespacedKey { } } + public NamespacedKey(LimboPlugin plugin, String key) { + this(plugin.getName().toLowerCase().replace(" ", "_"), key); + } + public NamespacedKey(String namespace, String key) { this.namespace = namespace; this.key = key; } - - public static NamespacedKey minecraft(String key) { - return new NamespacedKey(MINECRAFT_KEY, key); - } public String getNamespace() { return namespace; @@ -54,40 +67,25 @@ public class NamespacedKey { return key; } + public Key toKey() { + return Key.key(namespace, key); + } + @Override public String toString() { return namespace + ":" + key; } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((key == null) ? 0 : key.hashCode()); - result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NamespacedKey that = (NamespacedKey) o; + return namespace.equals(that.namespace) && key.equals(that.key); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - NamespacedKey other = (NamespacedKey) obj; - if (key == null) { - if (other.key != null) - return false; - } else if (!key.equals(other.key)) - return false; - if (namespace == null) { - if (other.namespace != null) - return false; - } else if (!namespace.equals(other.namespace)) - return false; - return true; + public int hashCode() { + return Objects.hash(namespace, key); } - } diff --git a/src/main/resources/mapping.json b/src/main/resources/mapping.json index 8a90cb0..59d366e 100644 --- a/src/main/resources/mapping.json +++ b/src/main/resources/mapping.json @@ -49,7 +49,11 @@ "ClientboundSetTitlesAnimationPacket": "0x5C", "ClientboundSetTitleTextPacket": "0x5B", "ClientboundSetSubtitleTextPacket": "0x59", - "ClientboundClearTitlesPacket": "0x0C" + "ClientboundSetActionBarTextPacket": "0x42", + "ClientboundClearTitlesPacket": "0x0C", + "PacketPlayOutBoss": "0x0A", + "PacketPlayOutNamedSoundEffect": "0x5E", + "PacketPlayOutStopSound": "0x5F" }, "StatusIn": { "0x01": "PacketStatusInPing",