mirror of https://github.com/Minestom/Minestom.git
feat: simplify sound events, fix update explosion packet
This commit is contained in:
parent
9894425f12
commit
8a829ebe47
|
@ -30,7 +30,7 @@ public class Generators {
|
|||
generator.generate(resource("potion_effects.json"), "net.minestom.server.potion", "PotionEffect", "PotionEffectImpl", "PotionEffects");
|
||||
generator.generate(resource("potions.json"), "net.minestom.server.potion", "PotionType", "PotionTypeImpl", "PotionTypes");
|
||||
generator.generate(resource("particles.json"), "net.minestom.server.particle", "Particle", "ParticleImpl", "Particles");
|
||||
generator.generate(resource("sounds.json"), "net.minestom.server.sound", "SoundEvent", "SoundEventImpl", "SoundEvents");
|
||||
generator.generate(resource("sounds.json"), "net.minestom.server.sound", "SoundEvent", "BuiltinSoundEvent", "SoundEvents");
|
||||
generator.generate(resource("custom_statistics.json"), "net.minestom.server.statistic", "StatisticType", "StatisticTypeImpl", "StatisticTypes");
|
||||
generator.generate(resource("damage_types.json"), "net.minestom.server.entity.damage", "DamageType", "DamageTypeImpl", "DamageTypes");
|
||||
generator.generate(resource("trim_materials.json"), "net.minestom.server.item.armor", "TrimMaterial", "TrimMaterialImpl", "TrimMaterials");
|
||||
|
|
|
@ -49,9 +49,20 @@ public class DyeColorGenerator extends MinestomCodeGenerator {
|
|||
.addSuperinterface(ClassName.get("net.kyori.adventure.util", "RGBLike"))
|
||||
.addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName());
|
||||
|
||||
ClassName networkBufferCN = ClassName.get("net.minestom.server.network", "NetworkBuffer");
|
||||
ParameterizedTypeName networkBufferTypeCN = ParameterizedTypeName.get(networkBufferCN.nestedClass("Type"), dyeColorCN);
|
||||
ClassName binaryTagSerializerCN = ClassName.get("net.minestom.server.utils.nbt", "BinaryTagSerializer");
|
||||
ParameterizedTypeName binaryTagSerializerTypeCN = ParameterizedTypeName.get(binaryTagSerializerCN, dyeColorCN);
|
||||
|
||||
// Fields
|
||||
dyeColorEnum.addFields(
|
||||
List.of(
|
||||
FieldSpec.builder(networkBufferTypeCN, "NETWORK_TYPE", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
|
||||
.initializer("$T.fromEnum($T.class)", networkBufferCN, dyeColorCN)
|
||||
.build(),
|
||||
FieldSpec.builder(binaryTagSerializerTypeCN, "NBT_TYPE", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
|
||||
.initializer("$T.fromEnumStringable($T.class)", binaryTagSerializerCN, dyeColorCN)
|
||||
.build(),
|
||||
FieldSpec.builder(colorCN, "textureDiffuseColor", Modifier.PRIVATE, Modifier.FINAL).build(),
|
||||
FieldSpec.builder(colorCN, "textColor", Modifier.PRIVATE, Modifier.FINAL).build(),
|
||||
FieldSpec.builder(colorCN, "fireworkColor", Modifier.PRIVATE, Modifier.FINAL).build(),
|
||||
|
|
|
@ -7,6 +7,7 @@ import net.minestom.server.advancements.notifications.Notification;
|
|||
import net.minestom.server.advancements.notifications.NotificationCenter;
|
||||
import net.minestom.server.adventure.MinestomAdventure;
|
||||
import net.minestom.server.adventure.audience.Audiences;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Entity;
|
||||
|
@ -37,9 +38,16 @@ import net.minestom.server.item.component.BlockPredicates;
|
|||
import net.minestom.server.item.component.ItemBlockState;
|
||||
import net.minestom.server.monitoring.BenchmarkManager;
|
||||
import net.minestom.server.monitoring.TickMonitor;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.play.ExplosionPacket;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.BlockParticleData;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
@ -87,6 +95,8 @@ public class PlayerInit {
|
|||
itemEntity.setInstance(player.getInstance(), playerPos.withY(y -> y + 1.5));
|
||||
Vec velocity = playerPos.direction().mul(6);
|
||||
itemEntity.setVelocity(velocity);
|
||||
|
||||
player.sendPacket(makeExplosion(playerPos, velocity));
|
||||
})
|
||||
.addListener(PlayerDisconnectEvent.class, event -> System.out.println("DISCONNECTION " + event.getPlayer().getUsername()))
|
||||
.addListener(AsyncPlayerConfigurationEvent.class, event -> {
|
||||
|
@ -164,6 +174,20 @@ public class PlayerInit {
|
|||
event.getInstance().setBlock(event.getBlockPosition(), block);
|
||||
});
|
||||
|
||||
private static final byte[] AIR_BLOCK_PARTICLE = NetworkBuffer.makeArray(new BlockParticleData(Block.AIR)::write);
|
||||
|
||||
private static @NotNull ExplosionPacket makeExplosion(@NotNull Point position, @NotNull Vec motion) {
|
||||
return new ExplosionPacket(
|
||||
position.x(), position.y(), position.z(),
|
||||
0, new byte[0],
|
||||
(float) motion.x(), (float) motion.y(), (float) motion.z(),
|
||||
ExplosionPacket.BlockInteraction.KEEP,
|
||||
Particle.BLOCK.id(), AIR_BLOCK_PARTICLE,
|
||||
Particle.BLOCK.id(), AIR_BLOCK_PARTICLE,
|
||||
SoundEvent.of(NamespaceID.from("not.a.real.sound"), 0f)
|
||||
);
|
||||
}
|
||||
|
||||
static {
|
||||
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ public enum DyeColor implements RGBLike {
|
|||
BLACK(new Color(0x1d1d21), new Color(0x0), new Color(0x1e1b1b), 29);
|
||||
|
||||
public static final NetworkBuffer.Type<DyeColor> NETWORK_TYPE = NetworkBuffer.fromEnum(DyeColor.class);
|
||||
|
||||
public static final BinaryTagSerializer<DyeColor> NBT_TYPE = BinaryTagSerializer.fromEnumStringable(DyeColor.class);
|
||||
|
||||
private final Color textureDiffuseColor;
|
||||
|
|
|
@ -49,7 +49,7 @@ interface PotionEffects {
|
|||
|
||||
PotionEffect ABSORPTION = PotionEffectImpl.get("minecraft:absorption");
|
||||
|
||||
PotionEffect SATURATION = PotionEffectImpl.get("minecraft:saturationModifier");
|
||||
PotionEffect SATURATION = PotionEffectImpl.get("minecraft:saturation");
|
||||
|
||||
PotionEffect GLOWING = PotionEffectImpl.get("minecraft:glowing");
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,11 +10,11 @@ import net.kyori.adventure.text.Component;
|
|||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.kyori.adventure.title.TitlePart;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.play.*;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.TickUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -111,15 +111,12 @@ public class AdventurePacketConvertor {
|
|||
* @return the sound packet
|
||||
*/
|
||||
public static @NotNull ServerPacket createSoundPacket(@NotNull Sound sound, double x, double y, double z) {
|
||||
final SoundEvent minestomSound = SoundEvent.fromNamespaceId(sound.name().asString());
|
||||
final NamespaceID soundName = NamespaceID.from(sound.name().asString());
|
||||
SoundEvent minestomSound = SoundEvent.fromNamespaceId(soundName);
|
||||
if (minestomSound == null) minestomSound = SoundEvent.of(soundName, null);
|
||||
|
||||
final long seed = sound.seed().orElse(ThreadLocalRandom.current().nextLong());
|
||||
if (minestomSound == null) {
|
||||
return new SoundEffectPacket(sound.name().asString(), null, sound.source(),
|
||||
new Vec(x, y, z), sound.volume(), sound.pitch(), seed);
|
||||
} else {
|
||||
return new SoundEffectPacket(minestomSound, null, sound.source(),
|
||||
new Vec(x, y, z), sound.volume(), sound.pitch(), seed);
|
||||
}
|
||||
return new SoundEffectPacket(minestomSound, sound.source(), (int) x, (int) y, (int) z, sound.volume(), sound.pitch(), seed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,14 +133,12 @@ public class AdventurePacketConvertor {
|
|||
if (!(emitter instanceof Entity entity))
|
||||
throw new IllegalArgumentException("you can only call this method with entities");
|
||||
|
||||
final SoundEvent minestomSound = SoundEvent.fromNamespaceId(sound.name().asString());
|
||||
final long seed = sound.seed().orElse(ThreadLocalRandom.current().nextLong());
|
||||
final NamespaceID soundName = NamespaceID.from(sound.name().asString());
|
||||
SoundEvent minestomSound = SoundEvent.fromNamespaceId(soundName);
|
||||
if (minestomSound == null) minestomSound = SoundEvent.of(soundName, null);
|
||||
|
||||
if (minestomSound != null) {
|
||||
return new EntitySoundEffectPacket(minestomSound, null, sound.source(), entity.getEntityId(), sound.volume(), sound.pitch(), seed);
|
||||
} else {
|
||||
return new EntitySoundEffectPacket(sound.name().asString(), null, sound.source(), entity.getEntityId(), sound.volume(), sound.pitch(), seed);
|
||||
}
|
||||
final long seed = sound.seed().orElse(ThreadLocalRandom.current().nextLong());
|
||||
return new EntitySoundEffectPacket(minestomSound, sound.source(), entity.getEntityId(), sound.volume(), sound.pitch(), seed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -366,8 +366,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
|||
// TODO: separate living entity categories
|
||||
soundCategory = Source.HOSTILE;
|
||||
}
|
||||
sendPacketToViewersAndSelf(new SoundEffectPacket(sound, null, soundCategory,
|
||||
getPosition(), 1.0f, 1.0f, 0));
|
||||
sendPacketToViewersAndSelf(new SoundEffectPacket(sound, soundCategory, getPosition(), 1.0f, 1.0f, 0));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import net.minestom.server.entity.Player;
|
|||
import net.minestom.server.entity.pathfinding.PFColumnarSpace;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockHandler;
|
||||
import net.minestom.server.instance.generator.Generator;
|
||||
import net.minestom.server.instance.heightmap.Heightmap;
|
||||
import net.minestom.server.network.packet.server.SendablePacket;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
|
@ -233,11 +234,11 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets if this chunk will or had been loaded with a {@link ChunkGenerator}.
|
||||
* Gets if this chunk will or had been loaded with a {@link Generator}.
|
||||
* <p>
|
||||
* If false, the chunk will be entirely empty when loaded.
|
||||
*
|
||||
* @return true if this chunk is affected by a {@link ChunkGenerator}
|
||||
* @return true if this chunk is affected by a {@link Generator}
|
||||
*/
|
||||
public boolean shouldGenerate() {
|
||||
return shouldGenerate;
|
||||
|
@ -247,7 +248,7 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
|
|||
* Gets if this chunk is read-only.
|
||||
* <p>
|
||||
* Being read-only should prevent block placing/breaking and setting block from an {@link Instance}.
|
||||
* It does not affect {@link IChunkLoader} and {@link ChunkGenerator}.
|
||||
* It does not affect {@link IChunkLoader} and {@link Generator}.
|
||||
*
|
||||
* @return true if the chunk is read-only
|
||||
*/
|
||||
|
@ -259,7 +260,7 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
|
|||
* Changes the read state of the chunk.
|
||||
* <p>
|
||||
* Being read-only should prevent block placing/breaking and setting block from an {@link Instance}.
|
||||
* It does not affect {@link IChunkLoader} and {@link ChunkGenerator}.
|
||||
* It does not affect {@link IChunkLoader} and {@link Generator}.
|
||||
*
|
||||
* @param readOnly true to make the chunk read-only, false otherwise
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@ public interface IChunkLoader {
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads a {@link Chunk}, all blocks should be set since the {@link ChunkGenerator} is not applied.
|
||||
* Loads a {@link Chunk}, all blocks should be set since the {@link net.minestom.server.instance.generator.Generator} is not applied.
|
||||
*
|
||||
* @param instance the {@link Instance} where the {@link Chunk} belong
|
||||
* @param chunkX the chunk X
|
||||
|
|
|
@ -66,7 +66,7 @@ public sealed interface ItemComponent<T> extends StaticProtocolObject permits It
|
|||
ItemComponent<LodestoneTracker> LODESTONE_TRACKER = declare("lodestone_tracker", LodestoneTracker.NETWORK_TYPE, LodestoneTracker.NBT_TYPE);
|
||||
ItemComponent<FireworkExplosion> FIREWORK_EXPLOSION = declare("firework_explosion", FireworkExplosion.NETWORK_TYPE, FireworkExplosion.NBT_TYPE);
|
||||
ItemComponent<FireworkList> FIREWORKS = declare("fireworks", FireworkList.NETWORK_TYPE, FireworkList.NBT_TYPE);
|
||||
ItemComponent<Void> PROFILE = declare("profile", null, null); //todo
|
||||
ItemComponent<HeadProfile> PROFILE = declare("profile", HeadProfile.NETWORK_TYPE, HeadProfile.NBT_TYPE);
|
||||
ItemComponent<String> NOTE_BLOCK_SOUND = declare("note_block_sound", NetworkBuffer.STRING, BinaryTagSerializer.STRING);
|
||||
ItemComponent<Void> BANNER_PATTERNS = declare("banner_patterns", null, null); //todo
|
||||
ItemComponent<DyeColor> BASE_COLOR = declare("base_color", DyeColor.NETWORK_TYPE, DyeColor.NBT_TYPE);
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.IntArrayBinaryTag;
|
||||
import net.kyori.adventure.nbt.StringBinaryTag;
|
||||
import net.minestom.server.entity.PlayerSkin;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record HeadProfile(@Nullable String name, @Nullable UUID uuid, @NotNull List<Property> properties) {
|
||||
public static final HeadProfile EMPTY = new HeadProfile(null, null, List.of());
|
||||
|
||||
public static final NetworkBuffer.Type<HeadProfile> NETWORK_TYPE = new NetworkBuffer.Type<HeadProfile>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, HeadProfile value) {
|
||||
buffer.writeOptional(NetworkBuffer.STRING, value.name);
|
||||
buffer.writeOptional(NetworkBuffer.UUID, value.uuid);
|
||||
buffer.writeCollection(Property.NETWORK_TYPE, value.properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HeadProfile read(@NotNull NetworkBuffer buffer) {
|
||||
return new HeadProfile(buffer.readOptional(NetworkBuffer.STRING), buffer.readOptional(NetworkBuffer.UUID), buffer.readCollection(Property.NETWORK_TYPE, Short.MAX_VALUE));
|
||||
}
|
||||
};
|
||||
public static final BinaryTagSerializer<HeadProfile> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> new HeadProfile(
|
||||
tag.get("name") instanceof StringBinaryTag string ? string.value() : null,
|
||||
tag.get("uuid") instanceof IntArrayBinaryTag intArray ? BinaryTagSerializer.UUID.read(intArray) : null,
|
||||
Property.NBT_LIST_TYPE.read(tag.getList("properties"))
|
||||
),
|
||||
profile -> {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
if (profile.name != null) builder.putString("name", profile.name);
|
||||
if (profile.uuid != null) builder.put("uuid", BinaryTagSerializer.UUID.write(profile.uuid));
|
||||
if (!profile.properties.isEmpty()) builder.put("properties", Property.NBT_LIST_TYPE.write(profile.properties));
|
||||
return builder.build();
|
||||
}
|
||||
);
|
||||
|
||||
public HeadProfile(@NotNull PlayerSkin playerSkin) {
|
||||
this(null, null, List.of(new Property("textures", playerSkin.textures(), playerSkin.signature())));
|
||||
}
|
||||
|
||||
public @Nullable PlayerSkin skin() {
|
||||
for (Property property : properties) {
|
||||
if ("textures".equals(property.name)) {
|
||||
return new PlayerSkin(property.value, property.signature);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public record Property(@NotNull String name, @NotNull String value, @Nullable String signature) {
|
||||
public static final NetworkBuffer.Type<Property> NETWORK_TYPE = new NetworkBuffer.Type<Property>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Property value) {
|
||||
buffer.write(NetworkBuffer.STRING, value.name);
|
||||
buffer.write(NetworkBuffer.STRING, value.value);
|
||||
buffer.writeOptional(NetworkBuffer.STRING, value.signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property read(@NotNull NetworkBuffer buffer) {
|
||||
return new Property(buffer.read(NetworkBuffer.STRING), buffer.read(NetworkBuffer.STRING), buffer.readOptional(NetworkBuffer.STRING));
|
||||
}
|
||||
};
|
||||
public static final BinaryTagSerializer<Property> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> new Property(tag.getString("name"), tag.getString("value"),
|
||||
tag.get("signature") instanceof StringBinaryTag signature ? signature.value() : null),
|
||||
property -> {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
builder.putString("name", property.name);
|
||||
builder.putString("value", property.value);
|
||||
if (property.signature != null) builder.putString("signature", property.signature);
|
||||
return builder.build();
|
||||
}
|
||||
);
|
||||
public static final BinaryTagSerializer<List<Property>> NBT_LIST_TYPE = NBT_TYPE.list();
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import java.util.*;
|
|||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public final class NetworkBuffer {
|
||||
|
@ -84,6 +85,24 @@ public final class NetworkBuffer {
|
|||
return NetworkBufferTypeImpl.fromEnum(enumClass);
|
||||
}
|
||||
|
||||
public static <T> Type<T> lazy(@NotNull Supplier<Type<T>> supplier) {
|
||||
return new NetworkBuffer.Type<>() {
|
||||
private Type<T> type;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, T value) {
|
||||
if (type == null) type = supplier.get();
|
||||
type.write(buffer, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(@NotNull NetworkBuffer buffer) {
|
||||
if (type == null) type = supplier.get();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ByteBuffer nioBuffer;
|
||||
final boolean resizable;
|
||||
int writeIndex;
|
||||
|
|
|
@ -6,17 +6,12 @@ import net.minestom.server.network.NetworkBuffer;
|
|||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record EntitySoundEffectPacket(
|
||||
// only one of soundEvent and soundName may be present
|
||||
@Nullable SoundEvent soundEvent,
|
||||
@Nullable String soundName,
|
||||
@Nullable Float range, // Only allowed with soundName
|
||||
@NotNull SoundEvent soundEvent,
|
||||
@NotNull Sound.Source source,
|
||||
int entityId,
|
||||
float volume,
|
||||
|
@ -24,64 +19,18 @@ public record EntitySoundEffectPacket(
|
|||
long seed
|
||||
) implements ServerPacket.Play {
|
||||
|
||||
public EntitySoundEffectPacket {
|
||||
Check.argCondition(soundEvent == null && soundName == null, "soundEvent and soundName cannot both be null");
|
||||
Check.argCondition(soundEvent != null && soundName != null, "soundEvent and soundName cannot both be present");
|
||||
Check.argCondition(soundName == null && range != null, "range cannot be present if soundName is null");
|
||||
}
|
||||
|
||||
public EntitySoundEffectPacket(@NotNull SoundEvent soundEvent, @Nullable Float range, @NotNull Sound.Source source,
|
||||
int entityId, float volume, float pitch, long seed) {
|
||||
this(soundEvent, null, range, source, entityId, volume, pitch, seed);
|
||||
}
|
||||
|
||||
public EntitySoundEffectPacket(@NotNull String soundName, @Nullable Float range, @NotNull Sound.Source source,
|
||||
int entityId, float volume, float pitch, long seed) {
|
||||
this(null, soundName, range, source, entityId, volume, pitch, seed);
|
||||
}
|
||||
|
||||
public EntitySoundEffectPacket(@NotNull NetworkBuffer reader) {
|
||||
this(fromReader(reader));
|
||||
}
|
||||
|
||||
private EntitySoundEffectPacket(@NotNull EntitySoundEffectPacket packet) {
|
||||
this(packet.soundEvent, packet.soundName, packet.range, packet.source, packet.entityId, packet.volume, packet.pitch, packet.seed);
|
||||
}
|
||||
|
||||
private static @NotNull EntitySoundEffectPacket fromReader(@NotNull NetworkBuffer reader) {
|
||||
int soundId = reader.read(VAR_INT);
|
||||
SoundEvent soundEvent;
|
||||
String soundName;
|
||||
Float range = null;
|
||||
if (soundId == 0) {
|
||||
soundEvent = null;
|
||||
soundName = reader.read(STRING);
|
||||
range = reader.readOptional(FLOAT);
|
||||
} else {
|
||||
soundEvent = SoundEvent.fromId(soundId - 1);
|
||||
soundName = null;
|
||||
}
|
||||
return new EntitySoundEffectPacket(
|
||||
soundEvent,
|
||||
soundName,
|
||||
range,
|
||||
this(reader.read(SoundEvent.NETWORK_TYPE),
|
||||
reader.readEnum(Sound.Source.class),
|
||||
reader.read(VAR_INT),
|
||||
reader.read(FLOAT),
|
||||
reader.read(FLOAT),
|
||||
reader.read(LONG)
|
||||
);
|
||||
reader.read(LONG));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
if (soundEvent != null) {
|
||||
writer.write(VAR_INT, soundEvent.id() + 1);
|
||||
} else {
|
||||
writer.write(VAR_INT, 0);
|
||||
writer.write(STRING, soundName);
|
||||
writer.writeOptional(FLOAT, range);
|
||||
}
|
||||
writer.write(SoundEvent.NETWORK_TYPE, soundEvent);
|
||||
writer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(source));
|
||||
writer.write(VAR_INT, entityId);
|
||||
writer.write(FLOAT, volume);
|
||||
|
|
|
@ -17,23 +17,23 @@ public record ExplosionPacket(double x, double y, double z, float radius,
|
|||
@NotNull BlockInteraction blockInteraction,
|
||||
int smallParticleId, byte @NotNull [] smallParticleData,
|
||||
int largeParticleId, byte @NotNull [] largeParticleData,
|
||||
@NotNull String soundName, boolean hasFixedSoundRange, float soundRange) implements ServerPacket.Play {
|
||||
@NotNull SoundEvent sound) implements ServerPacket.Play {
|
||||
public static final SoundEvent DEFAULT_SOUND = SoundEvent.ENTITY_GENERIC_EXPLODE;
|
||||
|
||||
private static @NotNull ExplosionPacket fromReader(@NotNull NetworkBuffer reader) {
|
||||
double x = reader.read(DOUBLE), y = reader.read(DOUBLE), z = reader.read(DOUBLE);
|
||||
float radius = reader.read(FLOAT);
|
||||
byte[] records = reader.readBytes(reader.read(VAR_INT) * 3);
|
||||
float playerMotionX = reader.read(FLOAT), playerMotionY = reader.read(FLOAT), playerMotionZ = reader.read(FLOAT);
|
||||
BlockInteraction blockInteraction = BlockInteraction.values()[reader.read(VAR_INT)];
|
||||
BlockInteraction blockInteraction = reader.readEnum(BlockInteraction.class);
|
||||
int smallParticleId = reader.read(VAR_INT);
|
||||
byte[] smallParticleData = readParticleData(reader, Particle.fromId(smallParticleId));
|
||||
int largeParticleId = reader.read(VAR_INT);
|
||||
byte[] largeParticleData = readParticleData(reader, Particle.fromId(largeParticleId));
|
||||
String soundName = reader.read(STRING);
|
||||
boolean hasFixedSoundRange = reader.read(BOOLEAN);
|
||||
float soundRange = hasFixedSoundRange ? reader.read(FLOAT) : 0;
|
||||
SoundEvent sound = reader.read(SoundEvent.NETWORK_TYPE);
|
||||
return new ExplosionPacket(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ,
|
||||
blockInteraction, smallParticleId, smallParticleData, largeParticleId, largeParticleData,
|
||||
soundName, hasFixedSoundRange, soundRange);
|
||||
sound);
|
||||
}
|
||||
|
||||
private static byte @NotNull [] readParticleData(@NotNull NetworkBuffer reader, Particle particle) {
|
||||
|
@ -75,13 +75,13 @@ public record ExplosionPacket(double x, double y, double z, float radius,
|
|||
this(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ,
|
||||
BlockInteraction.DESTROY, Particle.EXPLOSION.id(), new byte[] {},
|
||||
Particle.EXPLOSION_EMITTER.id(), new byte[] {},
|
||||
SoundEvent.ENTITY_GENERIC_EXPLODE.name(), false, 0);
|
||||
DEFAULT_SOUND);
|
||||
}
|
||||
|
||||
private ExplosionPacket(@NotNull ExplosionPacket packet) {
|
||||
this(packet.x, packet.y, packet.z, packet.radius, packet.records, packet.playerMotionX, packet.playerMotionY, packet.playerMotionZ,
|
||||
packet.blockInteraction, packet.smallParticleId, packet.smallParticleData, packet.largeParticleId, packet.largeParticleData,
|
||||
packet.soundName, packet.hasFixedSoundRange, packet.soundRange);
|
||||
packet.sound);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,9 +100,7 @@ public record ExplosionPacket(double x, double y, double z, float radius,
|
|||
writer.write(RAW_BYTES, smallParticleData);
|
||||
writer.write(VAR_INT, largeParticleId);
|
||||
writer.write(RAW_BYTES, largeParticleData);
|
||||
writer.write(STRING, soundName);
|
||||
writer.write(BOOLEAN, hasFixedSoundRange);
|
||||
if (hasFixedSoundRange) writer.write(FLOAT, soundRange);
|
||||
writer.write(SoundEvent.NETWORK_TYPE, sound);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,17 +7,12 @@ import net.minestom.server.network.NetworkBuffer;
|
|||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record SoundEffectPacket(
|
||||
// only one of soundEvent and soundName may be present
|
||||
@Nullable SoundEvent soundEvent,
|
||||
@Nullable String soundName,
|
||||
@Nullable Float range, // Only allowed with soundName
|
||||
@NotNull SoundEvent soundEvent,
|
||||
@NotNull Source source,
|
||||
int x,
|
||||
int y,
|
||||
|
@ -27,67 +22,25 @@ public record SoundEffectPacket(
|
|||
long seed
|
||||
) implements ServerPacket.Play {
|
||||
|
||||
public SoundEffectPacket {
|
||||
Check.argCondition(soundEvent == null && soundName == null, "soundEvent and soundName cannot both be null");
|
||||
Check.argCondition(soundEvent != null && soundName != null, "soundEvent and soundName cannot both be present");
|
||||
Check.argCondition(soundName == null && range != null, "range cannot be present if soundName is null");
|
||||
public SoundEffectPacket(@NotNull SoundEvent soundEvent, @NotNull Source source, @NotNull Point position, float volume, float pitch, long seed) {
|
||||
this(soundEvent, source, position.blockX(), position.blockY(), position.blockZ(), volume, pitch, seed);
|
||||
}
|
||||
|
||||
private static @NotNull SoundEffectPacket fromReader(@NotNull NetworkBuffer reader) {
|
||||
int soundId = reader.read(VAR_INT);
|
||||
SoundEvent soundEvent;
|
||||
String soundName;
|
||||
Float range = null;
|
||||
if (soundId == 0) {
|
||||
soundEvent = null;
|
||||
soundName = reader.read(STRING);
|
||||
range = reader.readOptional(FLOAT);
|
||||
} else {
|
||||
soundEvent = SoundEvent.fromId(soundId - 1);
|
||||
soundName = null;
|
||||
}
|
||||
return new SoundEffectPacket(
|
||||
soundEvent,
|
||||
soundName,
|
||||
range,
|
||||
public SoundEffectPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(SoundEvent.NETWORK_TYPE),
|
||||
reader.readEnum(Source.class),
|
||||
reader.read(INT) * 8,
|
||||
reader.read(INT) * 8,
|
||||
reader.read(INT) * 8,
|
||||
reader.read(FLOAT),
|
||||
reader.read(FLOAT),
|
||||
reader.read(LONG)
|
||||
);
|
||||
reader.read(LONG));
|
||||
}
|
||||
|
||||
public SoundEffectPacket(@NotNull SoundEvent soundEvent, @Nullable Float range, @NotNull Source source,
|
||||
@NotNull Point position, float volume, float pitch, long seed) {
|
||||
this(soundEvent, null, range, source, position.blockX(), position.blockY(), position.blockZ(), volume, pitch, seed);
|
||||
}
|
||||
|
||||
public SoundEffectPacket(@NotNull String soundName, @Nullable Float range, @NotNull Source source,
|
||||
@NotNull Point position, float volume, float pitch, long seed) {
|
||||
this(null, soundName, range, source, position.blockX(), position.blockY(), position.blockZ(), volume, pitch, seed);
|
||||
}
|
||||
|
||||
public SoundEffectPacket(@NotNull NetworkBuffer reader) {
|
||||
this(fromReader(reader));
|
||||
}
|
||||
|
||||
private SoundEffectPacket(@NotNull SoundEffectPacket packet) {
|
||||
this(packet.soundEvent, packet.soundName, packet.range, packet.source,
|
||||
packet.x, packet.y, packet.z, packet.volume, packet.pitch, packet.seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
if (soundEvent != null) {
|
||||
writer.write(VAR_INT, soundEvent.id() + 1);
|
||||
} else {
|
||||
writer.write(VAR_INT, 0);
|
||||
writer.write(STRING, soundName);
|
||||
writer.writeOptional(FLOAT, range);
|
||||
}
|
||||
writer.write(SoundEvent.NETWORK_TYPE, soundEvent);
|
||||
writer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(source));
|
||||
writer.write(INT, x * 8);
|
||||
writer.write(INT, y * 8);
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package net.minestom.server.sound;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
record BuiltinSoundEvent(NamespaceID namespace, int id) implements StaticProtocolObject, SoundEvent {
|
||||
private static final Registry.Container<BuiltinSoundEvent> CONTAINER = Registry.createStaticContainer(Registry.Resource.SOUNDS,
|
||||
(namespace, properties) -> new BuiltinSoundEvent(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
|
||||
public static final NetworkBuffer.Type<SoundEvent> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, SoundEvent value) {
|
||||
switch (value) {
|
||||
case BuiltinSoundEvent soundEvent -> buffer.write(NetworkBuffer.VAR_INT, soundEvent.id + 1);
|
||||
case CustomSoundEvent soundEvent -> {
|
||||
buffer.write(NetworkBuffer.VAR_INT, 0); // Custom sound
|
||||
buffer.write(NetworkBuffer.STRING, soundEvent.name());
|
||||
buffer.writeOptional(NetworkBuffer.FLOAT, soundEvent.range());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundEvent read(@NotNull NetworkBuffer buffer) {
|
||||
int id = buffer.read(NetworkBuffer.VAR_INT) - 1;
|
||||
if (id != -1) return getId(id);
|
||||
|
||||
NamespaceID namespace = NamespaceID.from(buffer.read(NetworkBuffer.STRING));
|
||||
return new CustomSoundEvent(namespace, buffer.readOptional(NetworkBuffer.FLOAT));
|
||||
}
|
||||
};
|
||||
|
||||
static SoundEvent get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
}
|
||||
|
||||
static SoundEvent getSafe(@NotNull String namespace) {
|
||||
return CONTAINER.getSafe(namespace);
|
||||
}
|
||||
|
||||
static SoundEvent getId(int id) {
|
||||
return CONTAINER.getId(id);
|
||||
}
|
||||
|
||||
static Collection<? extends SoundEvent> values() {
|
||||
return CONTAINER.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package net.minestom.server.sound;
|
||||
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
record CustomSoundEvent(@NotNull NamespaceID namespace, @Nullable Float range) implements SoundEvent {
|
||||
}
|
|
@ -2,33 +2,67 @@ package net.minestom.server.sound;
|
|||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.registry.ProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public sealed interface SoundEvent extends StaticProtocolObject, Sound.Type, SoundEvents permits SoundEventImpl {
|
||||
/**
|
||||
* Can represent a builtin/vanilla sound or a custom sound.
|
||||
*/
|
||||
public sealed interface SoundEvent extends ProtocolObject, Sound.Type, SoundEvents permits BuiltinSoundEvent, CustomSoundEvent {
|
||||
|
||||
static @NotNull Collection<@NotNull SoundEvent> values() {
|
||||
return SoundEventImpl.values();
|
||||
@NotNull NetworkBuffer.Type<SoundEvent> NETWORK_TYPE = NetworkBuffer.lazy(() -> BuiltinSoundEvent.NETWORK_TYPE); //todo what is the init issue here??
|
||||
|
||||
static @NotNull Collection<? extends SoundEvent> values() {
|
||||
return BuiltinSoundEvent.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builtin sound event by its namespace ID. Will never return a custom/resource pack sound.
|
||||
*
|
||||
* @param namespaceID the namespace ID of the sound event
|
||||
* @return the sound event, or null if not found
|
||||
*/
|
||||
static @Nullable SoundEvent fromNamespaceId(@NotNull String namespaceID) {
|
||||
return SoundEventImpl.getSafe(namespaceID);
|
||||
return BuiltinSoundEvent.getSafe(namespaceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builtin sound event by its namespace ID. Will never return a custom/resource pack sound.
|
||||
*
|
||||
* @param namespaceID the namespace ID of the sound event
|
||||
* @return the sound event, or null if not found
|
||||
*/
|
||||
static @Nullable SoundEvent fromNamespaceId(@NotNull NamespaceID namespaceID) {
|
||||
return fromNamespaceId(namespaceID.asString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builtin sound event by its protocol ID. Will never return a custom/resource pack sound.
|
||||
*
|
||||
* @param id the ID of the sound event
|
||||
* @return the sound event, or null if not found
|
||||
*/
|
||||
static @Nullable SoundEvent fromId(int id) {
|
||||
return SoundEventImpl.getId(id);
|
||||
return BuiltinSoundEvent.getId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom sound event. The {@link NamespaceID} should match a sound provided in the resource pack.
|
||||
* @param namespaceID the namespace ID of the custom sound event
|
||||
* @param range the range of the sound event, or null for (legacy) dynamic range
|
||||
* @return the custom sound event
|
||||
*/
|
||||
static @NotNull SoundEvent of(@NotNull NamespaceID namespaceID, @Nullable Float range) {
|
||||
return new CustomSoundEvent(namespaceID, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
default @NotNull Key key() {
|
||||
return StaticProtocolObject.super.key();
|
||||
return ProtocolObject.super.key();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
package net.minestom.server.sound;
|
||||
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
record SoundEventImpl(NamespaceID namespace, int id) implements SoundEvent {
|
||||
private static final Registry.Container<SoundEvent> CONTAINER = Registry.createStaticContainer(Registry.Resource.SOUNDS,
|
||||
(namespace, properties) -> new SoundEventImpl(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
|
||||
static SoundEvent get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
}
|
||||
|
||||
static SoundEvent getSafe(@NotNull String namespace) {
|
||||
return CONTAINER.getSafe(namespace);
|
||||
}
|
||||
|
||||
static SoundEvent getId(int id) {
|
||||
return CONTAINER.getId(id);
|
||||
}
|
||||
|
||||
static Collection<SoundEvent> values() {
|
||||
return CONTAINER.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.*;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.utils.UniqueIdUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -154,6 +155,21 @@ public interface BinaryTagSerializer<T> {
|
|||
);
|
||||
BinaryTagSerializer<ItemStack> ITEM = COMPOUND.map(ItemStack::fromItemNBT, ItemStack::toItemNBT);
|
||||
|
||||
BinaryTagSerializer<UUID> UUID = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(java.util.@NotNull UUID value) {
|
||||
return UniqueIdUtils.toNbt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.@NotNull UUID read(@NotNull BinaryTag tag) {
|
||||
if (!(tag instanceof IntArrayBinaryTag intArrayTag)) {
|
||||
throw new IllegalArgumentException("unexpected uuid type: " + tag.type());
|
||||
}
|
||||
return UniqueIdUtils.fromNbt(intArrayTag);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull BinaryTag write(@NotNull T value);
|
||||
@NotNull T read(@NotNull BinaryTag tag);
|
||||
|
||||
|
|
Loading…
Reference in New Issue