From 9133008e188da7b4f09c2a308251b9b54701dc3c Mon Sep 17 00:00:00 2001 From: davchoo Date: Mon, 30 May 2022 14:38:03 -0400 Subject: [PATCH] Translate ClientboundSoundEntityPacket Used by allay, frog, and a few other mobs. Move common code to SoundUtils Update mappings --- .../entity/JavaSoundEntityTranslator.java | 45 ++++++++ .../java/level/JavaCustomSoundTranslator.java | 30 +---- .../java/level/JavaSoundTranslator.java | 62 +--------- .../java/level/JavaStopSoundTranslator.java | 34 +----- .../org/geysermc/geyser/util/SoundUtils.java | 109 +++++++++++++++++- core/src/main/resources/mappings | 2 +- 6 files changed, 162 insertions(+), 120 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java new file mode 100644 index 000000000..11a047805 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.java.entity; + +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSoundEntityPacket; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.SoundUtils; + +@Translator(packet = ClientboundSoundEntityPacket.class) +public class JavaSoundEntityTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundSoundEntityPacket packet) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity == null) { + return; + } + SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getPitch()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java index 63da6710c..00894bd8b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java @@ -25,45 +25,21 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; -import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundCustomSoundPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.*; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.util.SoundUtils; @Translator(packet = ClientboundCustomSoundPacket.class) public class JavaCustomSoundTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundCustomSoundPacket packet) { - String packetSound; - if (packet.getSound() instanceof BuiltinSound) { - packetSound = ((BuiltinSound) packet.getSound()).getName(); - } else if (packet.getSound() instanceof CustomSound) { - packetSound = ((CustomSound) packet.getSound()).getName(); - } else { - session.getGeyser().getLogger().debug("Unknown sound packet, we were unable to map this. " + packet.toString()); - return; - } - - SoundMapping soundMapping = Registries.SOUNDS.get(packetSound.replace("minecraft:", "")); - String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { - // no mapping - session.getGeyser().getLogger() - .debug("[PlaySound] Defaulting to sound server gave us for " + packet.toString()); - playsound = packetSound.replace("minecraft:", ""); - } else { - playsound = soundMapping.getPlaysound(); - } - PlaySoundPacket playSoundPacket = new PlaySoundPacket(); - playSoundPacket.setSound(playsound); + playSoundPacket.setSound(SoundUtils.translatePlaySound(packet.getSound())); playSoundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); playSoundPacket.setVolume(packet.getVolume()); playSoundPacket.setPitch(packet.getPitch()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java index 60e7907e2..626c4527c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java @@ -27,75 +27,17 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSoundPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.util.SoundUtils; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; @Translator(packet = ClientboundSoundPacket.class) public class JavaSoundTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundSoundPacket packet) { - String packetSound = packet.getSound().getName(); - - SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); - if (soundMapping == null) { - session.getGeyser().getLogger().debug("[Builtin] Sound mapping " + packetSound + " not found - " + packet.toString()); - return; - } - - if (soundMapping.isLevelEvent()) { - LevelEventPacket levelEventPacket = new LevelEventPacket(); - levelEventPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - levelEventPacket.setData(0); - levelEventPacket.setType(LevelEventType.valueOf(soundMapping.getBedrock())); - session.sendUpstreamPacket(levelEventPacket); - return; - } - LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); - SoundEvent sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); - if (sound == null) { - sound = SoundUtils.toSoundEvent(packetSound); - } - if (sound == null) { - session.getGeyser().getLogger().debug("[Builtin] Sound for original " + packetSound + " to mappings " + soundPacket - + " was not a playable level sound, or has yet to be mapped to an enum in " - + "NukkitX SoundEvent "); - return; - } - - soundPacket.setSound(sound); - soundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - soundPacket.setIdentifier(soundMapping.getIdentifier()); - if (sound == SoundEvent.NOTE) { - // Minecraft Wiki: 2^(x/12) = Java pitch where x is -12 to 12 - // Java sends the note value as above starting with -12 and ending at 12 - // Bedrock has a number for each type of note, then proceeds up the scale by adding to that number - soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(packet.getPitch()) / Math.log10(2)) * 12)) + 12); - } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { - if (!soundMapping.getIdentifier().equals(":")) { - soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId( - BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID))); - } else { - session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + packet.toString()); - } - soundPacket.setIdentifier(":"); - } else { - soundPacket.setExtraData(soundMapping.getExtraData()); - } - - - soundPacket.setBabySound(false); // might need to adjust this in the future - soundPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundPacket); + Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); + SoundUtils.playBuiltinSound(session, packet.getSound(), position, packet.getPitch()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java index d9750ad7e..e5bc7999f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java @@ -25,15 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; -import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundStopSoundPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.util.SoundUtils; @Translator(packet = ClientboundStopSoundPacket.class) public class JavaStopSoundTranslator extends PacketTranslator { @@ -49,36 +46,11 @@ public class JavaStopSoundTranslator extends PacketTranslator " - + soundMapping + (soundMapping == null ? "[not found]" : "") - + " - " + packet.toString()); - String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { - // no mapping - session.getGeyser().getLogger() - .debug("[StopSound] Defaulting to sound server gave us."); - playsound = packetSound; - } else { - playsound = soundMapping.getPlaysound(); - } - StopSoundPacket stopSoundPacket = new StopSoundPacket(); - stopSoundPacket.setSoundName(playsound); - // packet not mapped in the library + stopSoundPacket.setSoundName(SoundUtils.translatePlaySound(packet.getSound())); stopSoundPacket.setStoppingAllSound(false); session.sendUpstreamPacket(stopSoundPacket); - session.getGeyser().getLogger().debug("[StopSound] Packet sent - " + packet.toString() + " --> " + stopSoundPacket); + session.getGeyser().getLogger().debug("[StopSound] Stopped " + packet.getSound() + " -> " + stopSoundPacket.getSoundName()); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java index d2675f13e..44ec06244 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -25,7 +25,20 @@ package org.geysermc.geyser.util; +import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; +import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; +import com.github.steveice10.mc.protocol.data.game.level.sound.Sound; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.session.GeyserSession; public class SoundUtils { @@ -38,9 +51,103 @@ public class SoundUtils { */ public static SoundEvent toSoundEvent(String sound) { try { - return SoundEvent.valueOf(sound.toUpperCase().replaceAll("\\.", "_")); + return SoundEvent.valueOf(sound.toUpperCase().replace(".", "_")); } catch (Exception ex) { return null; } } + + /** + * Translates a Java Custom or Builtin Sound to its Bedrock equivalent + * + * @param sound the sound to translate + * @return a Bedrock sound + */ + public static String translatePlaySound(Sound sound) { + String packetSound; + if (sound instanceof BuiltinSound builtinSound) { + packetSound = builtinSound.getName(); + } else if (sound instanceof CustomSound customSound) { + packetSound = customSound.getName(); + } else { + GeyserImpl.getInstance().getLogger().debug("Unknown sound, we were unable to map this. " + sound); + return ""; + } + + // Drop the namespace + int colonPos = packetSound.indexOf(":"); + if (colonPos != -1) { + packetSound = packetSound.substring(colonPos + 1); + } + + SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); + if (soundMapping == null || soundMapping.getPlaysound() == null) { + // no mapping + GeyserImpl.getInstance().getLogger().debug("[PlaySound] Defaulting to sound server gave us for " + sound); + return packetSound; + } + return soundMapping.getPlaysound(); + } + + /** + * Translates and plays a Java Builtin Sound for a Bedrock client + * + * @param session the Bedrock client session. + * @param javaSound the builtin sound to play + * @param position the position + * @param pitch the pitch + */ + public static void playBuiltinSound(GeyserSession session, BuiltinSound javaSound, Vector3f position, float pitch) { + String packetSound = javaSound.getName(); + + SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); + if (soundMapping == null) { + session.getGeyser().getLogger().debug("[Builtin] Sound mapping for " + packetSound + " not found"); + return; + } + + if (soundMapping.isLevelEvent()) { + LevelEventPacket levelEventPacket = new LevelEventPacket(); + levelEventPacket.setPosition(position); + levelEventPacket.setData(0); + levelEventPacket.setType(LevelEventType.valueOf(soundMapping.getBedrock())); + session.sendUpstreamPacket(levelEventPacket); + return; + } + + LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); + SoundEvent sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); + if (sound == null) { + sound = SoundUtils.toSoundEvent(packetSound); + } + if (sound == null) { + session.getGeyser().getLogger().debug("[Builtin] Sound for original '" + packetSound + "' to mappings '" + soundMapping.getBedrock() + + "' was not a playable level sound, or has yet to be mapped to an enum in SoundEvent."); + return; + } + + soundPacket.setSound(sound); + soundPacket.setPosition(position); + soundPacket.setIdentifier(soundMapping.getIdentifier()); + if (sound == SoundEvent.NOTE) { + // Minecraft Wiki: 2^(x/12) = Java pitch where x is -12 to 12 + // Java sends the note value as above starting with -12 and ending at 12 + // Bedrock has a number for each type of note, then proceeds up the scale by adding to that number + soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12); + } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { + if (!soundMapping.getIdentifier().equals(":")) { + int javaId = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID); + soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId)); + } else { + session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping); + } + soundPacket.setIdentifier(":"); + } else { + soundPacket.setExtraData(soundMapping.getExtraData()); + } + + soundPacket.setBabySound(false); // might need to adjust this in the future + soundPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundPacket); + } } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index f0cee51f5..7fc4ac178 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit f0cee51f5868a78e18f3ac348eab52d5bbb2ac6f +Subproject commit 7fc4ac178901f2ba2989645d0da44dcfb95575db