Skip to content

Commit

Permalink
Set entities silent client-side, and more
Browse files Browse the repository at this point in the history
Add warden entity events. Fix up other things.
  • Loading branch information
Camotoy committed May 31, 2022
1 parent bf4e1d5 commit 196742a
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles
.addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName)
.addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible)
.addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.SILENT, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
.addTranslator(MetadataType.BOOLEAN, Entity::setSilent)
.addTranslator(MetadataType.BOOLEAN, Entity::setGravity)
.addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue()))
.addTranslator(MetadataType.INT, Entity::setFreezing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
* @link https://github.com/GeyserMC/Geyser
*/

package org.geysermc.geyser.entity;
package org.geysermc.geyser.entity.type;

import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.type.BoatEntity;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/java/org/geysermc/geyser/entity/type/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ public class Entity {
private float boundingBoxWidth;
@Setter(AccessLevel.NONE)
protected String nametag = "";
@Setter(AccessLevel.NONE)
protected boolean silent = false;
/* Metadata end */

protected List<Entity> passengers = Collections.emptyList();
Expand Down Expand Up @@ -148,6 +150,12 @@ protected void initializeMetadata() {
setFlag(EntityFlag.HAS_COLLISION, true);
setFlag(EntityFlag.CAN_SHOW_NAME, true);
setFlag(EntityFlag.CAN_CLIMB, true);
// Let the Java server (or us) supply all sounds for an entity
setClientSideSilent();
}

protected void setClientSideSilent() {
setFlag(EntityFlag.SILENT, true);
}

public void spawnEntity() {
Expand Down Expand Up @@ -370,6 +378,10 @@ public void setDisplayNameVisible(BooleanEntityMetadata entityMetadata) {
dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0));
}

public final void setSilent(BooleanEntityMetadata entityMetadata) {
silent = entityMetadata.getPrimitiveValue();
}

public void setGravity(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.HAS_GRAVITY, !entityMetadata.getPrimitiveValue());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
Expand Down Expand Up @@ -58,7 +57,7 @@ public void tick() {

public void setAttackStarted() {
this.attackStarted = true;
if (!getFlag(EntityFlag.SILENT)) {
if (!silent) {
// Play the chomp sound
PlaySoundPacket packet = new PlaySoundPacket();
packet.setPosition(this.position);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,16 @@
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.level.block.BlockPositionIterator;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.level.block.BlockPositionIterator;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockUtils;

import java.util.UUID;
Expand Down Expand Up @@ -129,7 +128,7 @@ protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch,
}

private void sendSplashSound(GeyserSession session) {
if (!getFlag(EntityFlag.SILENT)) {
if (!silent) {
float volume = (float) (0.2f * Math.sqrt(0.2 * (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) + motion.getY() * motion.getY()));
if (volume > 1) {
volume = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ private void updateBoundingBoxes() {
*/
private void effectTick() {
Random random = ThreadLocalRandom.current();
if (!getFlag(EntityFlag.SILENT)) {
if (!silent) {
if (Math.cos(wingPosition * 2f * Math.PI) <= -0.3f && Math.cos(lastWingPosition * 2f * Math.PI) >= -0.3f) {
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
playSoundPacket.setSound("mob.enderdragon.flap");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;

import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

public class WardenEntity extends MonsterEntity implements Tickable {
private int heartBeatDelay;
private int tickCount;

public class WardenEntity extends MonsterEntity {
public WardenEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
Expand All @@ -53,6 +59,23 @@ public void setPose(Pose pose) {

public void setAngerLevel(IntEntityMetadata entityMetadata) {
float anger = (float) entityMetadata.getPrimitiveValue() / 80f;
dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F));
heartBeatDelay = 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F);
dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, heartBeatDelay);
}

@Override
public void tick() {
if (++tickCount % heartBeatDelay == 0 && !silent) {
// We have to do these calculations because they're clientside on Java Edition but we mute entities
// to prevent hearing their step sounds
ThreadLocalRandom random = ThreadLocalRandom.current();

PlaySoundPacket packet = new PlaySoundPacket();
packet.setSound("mob.warden.heartbeat");
packet.setPosition(position);
packet.setPitch(1.0f);
packet.setVolume((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f);
session.sendUpstreamPacket(packet);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ public SessionPlayerEntity(GeyserSession session) {
valid = true;
}

@Override
protected void setClientSideSilent() {
// Do nothing, since we want the session player to hear their own footstep sounds for example.
}

@Override
public void spawnEntity() {
// Already logged in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public class SoundMapping {

public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) {
this.java = java;
this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock;
this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound;
this.bedrock = bedrock == null || bedrock.isEmpty() ? null : bedrock;
this.playsound = playsound == null || playsound.isEmpty() ? null : playsound;
this.extraData = extraData;
this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier;
this.identifier = identifier == null || identifier.isEmpty() ? ":" : identifier;
this.levelEvent = levelEvent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
package org.geysermc.geyser.translator.protocol.java.entity;

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket;
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.data.entity.EntityData;
Expand All @@ -42,14 +41,14 @@
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

@Translator(packet = ClientboundEntityEventPacket.class)
public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntityEventPacket> {

@Override
public void translate(GeyserSession session, ClientboundEntityEventPacket packet) {
System.out.println(packet);
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
if (entity == null)
return;
Expand Down Expand Up @@ -180,8 +179,9 @@ public void translate(GeyserSession session, ClientboundEntityEventPacket packet
case IRON_GOLEM_EMPTY_HAND:
entityEventPacket.setType(EntityEventType.GOLEM_FLOWER_WITHDRAW);
break;
case IRON_GOLEM_ATTACK:
if (entity.getDefinition() == EntityDefinitions.IRON_GOLEM || entity.getDefinition() == EntityDefinitions.EVOKER_FANGS) {
case ATTACK:
if (entity.getDefinition() == EntityDefinitions.IRON_GOLEM || entity.getDefinition() == EntityDefinitions.EVOKER_FANGS
|| entity.getDefinition() == EntityDefinitions.WARDEN) {
entityEventPacket.setType(EntityEventType.ATTACK_START);
if (entity.getDefinition() == EntityDefinitions.EVOKER_FANGS) {
((EvokerFangsEntity) entity).setAttackStarted();
Expand Down Expand Up @@ -236,28 +236,14 @@ public void translate(GeyserSession session, ClientboundEntityEventPacket packet
break;
case MAKE_POOF_PARTICLES:
if (entity instanceof LivingEntity) {
// Not ideal, but...
// LevelEventType.PARTICLE_DEATH_SMOKE doesn't work (as of 1.18.2 Bedrock)
// EntityEventType.DEATH_SMOKE_CLOUD also plays the entity death noise
// Bedrock sends the particles through EntityEventType.DEATH, but Java despawns the entity
// prematurely so they don't show up.
Vector3f position = entity.getPosition();
float baseX = position.getX();
float baseY = position.getY();
float baseZ = position.getZ();
float height = entity.getBoundingBoxHeight();
float width = entity.getBoundingBoxWidth();
Random random = ThreadLocalRandom.current();
for (int i = 0; i < 20; i++) {
// Reconstruct the Java Edition (1.18.1) logic, but in floats
float x = baseX + width * (2.0f * random.nextFloat() - 1f);
float y = baseY + height * random.nextFloat();
float z = baseZ + width * (2.0f * random.nextFloat() - 1f);
LevelEventPacket levelEventPacket = new LevelEventPacket();
levelEventPacket.setPosition(Vector3f.from(x, y, z));
levelEventPacket.setType(LevelEventType.PARTICLE_EXPLODE);
session.sendUpstreamPacket(levelEventPacket);
}
// Note that this event usually makes noise, but because we set all entities as silent on the
// client end this isn't an issue.
entityEventPacket.setType(EntityEventType.DEATH_SMOKE_CLOUD);
}
break;
case WARDEN_RECEIVE_SIGNAL:
if (entity.getDefinition() == EntityDefinitions.WARDEN) {
entityEventPacket.setType(EntityEventType.VIBRATION_DETECTED);
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ public void translate(GeyserSession session, ClientboundSoundEntityPacket packet
if (entity == null) {
return;
}
SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getPitch());
SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getVolume(), packet.getPitch());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ public class JavaSoundTranslator extends PacketTranslator<ClientboundSoundPacket
@Override
public void translate(GeyserSession session, ClientboundSoundPacket packet) {
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
SoundUtils.playBuiltinSound(session, packet.getSound(), position, packet.getPitch());
SoundUtils.playBuiltinSound(session, packet.getSound(), position, packet.getVolume(), packet.getPitch());
}
}
21 changes: 16 additions & 5 deletions core/src/main/java/org/geysermc/geyser/util/SoundUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries;
Expand Down Expand Up @@ -74,10 +75,9 @@ public static String translatePlaySound(Sound sound) {
return "";
}

// Drop the namespace
int colonPos = packetSound.indexOf(":");
if (colonPos != -1) {
packetSound = packetSound.substring(colonPos + 1);
// Drop the Minecraft namespace if applicable
if (packetSound.startsWith("minecraft:")) {
packetSound = packetSound.substring("minecraft:".length());
}

SoundMapping soundMapping = Registries.SOUNDS.get(packetSound);
Expand All @@ -97,7 +97,7 @@ public static String translatePlaySound(Sound sound) {
* @param position the position
* @param pitch the pitch
*/
public static void playBuiltinSound(GeyserSession session, BuiltinSound javaSound, Vector3f position, float pitch) {
public static void playBuiltinSound(GeyserSession session, BuiltinSound javaSound, Vector3f position, float volume, float pitch) {
String packetSound = javaSound.getName();

SoundMapping soundMapping = Registries.SOUNDS.get(packetSound);
Expand All @@ -106,6 +106,17 @@ public static void playBuiltinSound(GeyserSession session, BuiltinSound javaSoun
return;
}

if (soundMapping.getPlaysound() != null) {
// We always prefer the PlaySound mapping because we can control volume and pitch
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
playSoundPacket.setSound(soundMapping.getPlaysound());
playSoundPacket.setPosition(position);
playSoundPacket.setVolume(volume);
playSoundPacket.setPitch(pitch);
session.sendUpstreamPacket(playSoundPacket);
return;
}

if (soundMapping.isLevelEvent()) {
LevelEventPacket levelEventPacket = new LevelEventPacket();
levelEventPacket.setPosition(position);
Expand Down

0 comments on commit 196742a

Please sign in to comment.