Implement playSound and openBook methods

This commit is contained in:
Kieran Wallbanks 2021-03-02 15:56:20 +00:00
parent 52831e7091
commit 2c2f1b6cee
6 changed files with 165 additions and 25 deletions

View File

@ -0,0 +1,29 @@
package net.minestom.server.adventure;
import net.kyori.adventure.key.Key;
import net.minestom.server.sound.Sound;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Adventure related utilities.
*/
public class AdventureUtils {
private static final Map<String, Sound> SOUND_MAP =
Arrays.stream(Sound.values()).collect(Collectors.toMap(Sound::getNamespaceID, sound -> sound));
/**
* Attempts to get an NMS sound from an Adventure key.
*
* @param name the key
*
* @return the sound, if found
*/
public static @Nullable Sound asSound(@NotNull Key name) {
return SOUND_MAP.get(name.asString());
}
}

View File

@ -5,14 +5,13 @@ 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.sound.SoundStop;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.advancements.AdvancementTab;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.adventure.AdventureUtils;
import net.minestom.server.attribute.AttributeInstance;
import net.minestom.server.bossbar.BossBar;
import net.minestom.server.chat.ChatParser;
@ -845,12 +844,13 @@ public class Player extends LivingEntity implements CommandSender {
* @param z the effect Z
* @param volume the volume of the sound (1 is 100%)
* @param pitch the pitch of the sound, between 0.5 and 2.0
* @deprecated Use {@link #playSound(net.kyori.adventure.sound.Sound, double, double, double)}
*/
public void playSound(@NotNull Sound sound, @NotNull SoundCategory soundCategory,
int x, int y, int z, float volume, float pitch) {
@Deprecated
public void playSound(@NotNull Sound sound, @NotNull SoundCategory soundCategory, int x, int y, int z, float volume, float pitch) {
SoundEffectPacket soundEffectPacket = new SoundEffectPacket();
soundEffectPacket.soundId = sound.getId();
soundEffectPacket.soundCategory = soundCategory;
soundEffectPacket.soundCategory = soundCategory.ordinal();
soundEffectPacket.x = x;
soundEffectPacket.y = y;
soundEffectPacket.z = z;
@ -863,9 +863,10 @@ public class Player extends LivingEntity implements CommandSender {
* Plays a sound from the {@link Sound} enum.
*
* @see #playSound(Sound, SoundCategory, int, int, int, float, float)
* @deprecated Use {@link #playSound(net.kyori.adventure.sound.Sound, double, double, double)}
*/
public void playSound(@NotNull Sound sound, @NotNull SoundCategory soundCategory,
BlockPosition position, float volume, float pitch) {
@Deprecated
public void playSound(@NotNull Sound sound, @NotNull SoundCategory soundCategory, BlockPosition position, float volume, float pitch) {
playSound(sound, soundCategory, position.getX(), position.getY(), position.getZ(), volume, pitch);
}
@ -879,12 +880,13 @@ public class Player extends LivingEntity implements CommandSender {
* @param z the effect Z
* @param volume the volume of the sound (1 is 100%)
* @param pitch the pitch of the sound, between 0.5 and 2.0
* @deprecated Use {@link #playSound(net.kyori.adventure.sound.Sound, double, double, double)}
*/
public void playSound(@NotNull String identifier, @NotNull SoundCategory soundCategory,
int x, int y, int z, float volume, float pitch) {
@Deprecated
public void playSound(@NotNull String identifier, @NotNull SoundCategory soundCategory, int x, int y, int z, float volume, float pitch) {
NamedSoundEffectPacket namedSoundEffectPacket = new NamedSoundEffectPacket();
namedSoundEffectPacket.soundName = identifier;
namedSoundEffectPacket.soundCategory = soundCategory;
namedSoundEffectPacket.soundCategory = soundCategory.ordinal();
namedSoundEffectPacket.x = x;
namedSoundEffectPacket.y = y;
namedSoundEffectPacket.z = z;
@ -897,7 +899,9 @@ public class Player extends LivingEntity implements CommandSender {
* Plays a sound from an identifier (represents a custom sound in a resource pack).
*
* @see #playSound(String, SoundCategory, int, int, int, float, float)
* @deprecated Use {@link #playSound(net.kyori.adventure.sound.Sound, double, double, double)}
*/
@Deprecated
public void playSound(@NotNull String identifier, @NotNull SoundCategory soundCategory, BlockPosition position, float volume, float pitch) {
playSound(identifier, soundCategory, position.getX(), position.getY(), position.getZ(), volume, pitch);
}
@ -909,7 +913,9 @@ public class Player extends LivingEntity implements CommandSender {
* @param soundCategory the sound category
* @param volume the volume of the sound (1 is 100%)
* @param pitch the pitch of the sound, between 0.5 and 2.0
* @deprecated Use {@link #playSound(net.kyori.adventure.sound.Sound)}
*/
@Deprecated
public void playSound(@NotNull Sound sound, @NotNull SoundCategory soundCategory, float volume, float pitch) {
EntitySoundEffectPacket entitySoundEffectPacket = new EntitySoundEffectPacket();
entitySoundEffectPacket.entityId = getEntityId();
@ -920,6 +926,56 @@ public class Player extends LivingEntity implements CommandSender {
playerConnection.sendPacket(entitySoundEffectPacket);
}
@Override
public void playSound(net.kyori.adventure.sound.@NonNull Sound sound) {
this.playSound(sound, this.position.getX(), this.position.getY(), this.position.getZ());
}
@Override
public void playSound(net.kyori.adventure.sound.@NonNull Sound sound, double x, double y, double z) {
Sound minestomSound = AdventureUtils.asSound(sound.name());
if (minestomSound == null) {
NamedSoundEffectPacket packet = new NamedSoundEffectPacket();
packet.soundName = sound.name().asString();
packet.soundCategory = sound.source().ordinal();
packet.x = (int) x;
packet.y = (int) y;
packet.z = (int) z;
packet.volume = sound.volume();
packet.pitch = sound.pitch();
playerConnection.sendPacket(packet);
} else {
SoundEffectPacket packet = new SoundEffectPacket();
packet.soundId = minestomSound.getId();
packet.soundCategory = sound.source().ordinal();
packet.x = (int) x;
packet.y = (int) y;
packet.z = (int) z;
packet.volume = sound.volume();
packet.pitch = sound.pitch();
playerConnection.sendPacket(packet);
}
}
@Override
public void stopSound(@NonNull SoundStop stop) {
StopSoundPacket packet = new StopSoundPacket();
packet.flags = 0x0;
if (stop.source() != null) {
packet.flags |= 0x1;
packet.source = stop.source().ordinal();
}
if (stop.sound() != null) {
packet.flags |= 0x2;
packet.sound = stop.sound().asString();
}
this.playerConnection.sendPacket(packet);
}
/**
* Plays a given effect at the given position for this player.
*
@ -941,7 +997,9 @@ public class Player extends LivingEntity implements CommandSender {
/**
* Sends a {@link StopSoundPacket} packet.
* @deprecated Use {@link #stopSound(SoundStop)} with {@link SoundStop#all()}
*/
@Deprecated
public void stopSound() {
StopSoundPacket stopSoundPacket = new StopSoundPacket();
stopSoundPacket.flags = 0x00;
@ -1129,7 +1187,28 @@ public class Player extends LivingEntity implements CommandSender {
@Override
public void openBook(@NonNull Book book) {
// TODO write the book
// make the book
ItemStack writtenBook = new ItemStack(Material.WRITTEN_BOOK, (byte) 1);
writtenBook.setItemMeta(WrittenBookMeta.fromAdventure(book));
// Set book in offhand
SetSlotPacket setBookPacket = new SetSlotPacket();
setBookPacket.windowId = 0;
setBookPacket.slot = 45;
setBookPacket.itemStack = writtenBook;
playerConnection.sendPacket(setBookPacket);
// Open the book
OpenBookPacket openBookPacket = new OpenBookPacket();
openBookPacket.hand = Hand.OFF;
playerConnection.sendPacket(openBookPacket);
// Restore the item in offhand
SetSlotPacket restoreItemPacket = new SetSlotPacket();
restoreItemPacket.windowId = 0;
restoreItemPacket.slot = 45;
restoreItemPacket.itemStack = getItemInOffHand();
playerConnection.sendPacket(restoreItemPacket);
}
@Override

View File

@ -1,5 +1,8 @@
package net.minestom.server.item.metadata;
import net.kyori.adventure.inventory.Book;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatParser;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;
@ -18,7 +21,7 @@ public class WrittenBookMeta extends ItemMeta {
private WrittenBookGeneration generation;
private String author;
private String title;
private List<JsonMessage> pages = new ArrayList<>();
private List<String> pages = new ArrayList<>();
/**
* Gets if the book is resolved.
@ -100,7 +103,7 @@ public class WrittenBookMeta extends ItemMeta {
*
* @return a modifiable {@link ArrayList} with the pages of the book
*/
public List<JsonMessage> getPages() {
public List<String> getPages() {
return pages;
}
@ -109,7 +112,7 @@ public class WrittenBookMeta extends ItemMeta {
*
* @param pages the array list containing the book pages
*/
public void setPages(List<JsonMessage> pages) {
public void setPages(List<String> pages) {
this.pages = pages;
}
@ -149,9 +152,7 @@ public class WrittenBookMeta extends ItemMeta {
if (compound.containsKey("pages")) {
final NBTList<NBTString> list = compound.getList("pages");
for (NBTString page : list) {
final String jsonPage = page.getValue();
final ColoredText coloredText = ChatParser.toColoredText(jsonPage);
this.pages.add(coloredText);
this.pages.add(page.getValue());
}
}
}
@ -172,8 +173,8 @@ public class WrittenBookMeta extends ItemMeta {
}
if (!pages.isEmpty()) {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (JsonMessage page : pages) {
list.add(new NBTString(page.toString()));
for (String page : pages) {
list.add(new NBTString(page));
}
compound.set("pages", list);
}
@ -196,4 +197,26 @@ public class WrittenBookMeta extends ItemMeta {
ORIGINAL, COPY_OF_ORIGINAL, COPY_OF_COPY, TATTERED
}
/**
* Creates a written book meta from an Adventure book. This meta will not be
* resolved and the generation will default to {@link WrittenBookGeneration#ORIGINAL}.
*
* @param book the book
*
* @return the meta
*/
public static @NotNull WrittenBookMeta fromAdventure(@NotNull Book book) {
WrittenBookMeta meta = new WrittenBookMeta();
meta.resolved = false;
meta.generation = WrittenBookGeneration.ORIGINAL;
meta.author = MinecraftServer.getSerializationManager().serialize(book.author());
meta.title = MinecraftServer.getSerializationManager().serialize(book.title());
meta.pages = new ArrayList<>();
for (Component page : book.pages()) {
meta.pages.add(MinecraftServer.getSerializationManager().serialize(page));
}
return meta;
}
}

View File

@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
public class NamedSoundEffectPacket implements ServerPacket {
public String soundName;
public SoundCategory soundCategory;
public int soundCategory;
public int x, y, z;
public float volume;
public float pitch;
@ -17,7 +17,7 @@ public class NamedSoundEffectPacket implements ServerPacket {
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeSizedString(soundName);
writer.writeVarInt(soundCategory.ordinal());
writer.writeVarInt(soundCategory);
writer.writeInt(x * 8);
writer.writeInt(y * 8);
writer.writeInt(z * 8);

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.sound.Sound.Source;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.sound.Sound;
@ -11,15 +12,19 @@ import org.jetbrains.annotations.NotNull;
public class SoundEffectPacket implements ServerPacket {
public int soundId;
public SoundCategory soundCategory;
public int soundCategory;
public int x, y, z;
public float volume;
public float pitch;
/**
* @deprecated Use variables
*/
@Deprecated
public static SoundEffectPacket create(SoundCategory category, Sound sound, Position position, float volume, float pitch) {
SoundEffectPacket packet = new SoundEffectPacket();
packet.soundId = sound.getId();
packet.soundCategory = category;
packet.soundCategory = category.ordinal();
// *8 converts to fixed-point representation with 3 bits for fractional part
packet.x = (int) position.getX();
packet.y = (int) position.getY();
@ -32,7 +37,7 @@ public class SoundEffectPacket implements ServerPacket {
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeVarInt(soundId);
writer.writeVarInt(soundCategory.ordinal());
writer.writeVarInt(soundCategory);
writer.writeInt(x * 8);
writer.writeInt(y * 8);
writer.writeInt(z * 8);

View File

@ -1,5 +1,9 @@
package net.minestom.server.sound;
/**
* @deprecated Use {@link net.kyori.adventure.sound.Sound.Source}
*/
@Deprecated
public enum SoundCategory {
MASTER,
MUSIC,