mirror of
https://github.com/Minestom/Minestom.git
synced 2024-09-28 14:37:31 +02:00
Add particle data types (#2004)
* Add particle data types * misc * misc * remove spaces * defaults, tests, change what mattw said to * RGBLike * RGBLike * RGBLike * add back changes * tests * refactor * annotations * more fixes * another test * more tests + fix * logging + checks consistency * review changes * review changes
This commit is contained in:
parent
aad7bdab0f
commit
5162a00b1e
@ -8,6 +8,7 @@ import net.minestom.server.entity.metadata.animal.tameable.CatMeta;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.play.EntityMetaDataPacket;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -126,6 +127,10 @@ public final class Metadata {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_QUATERNION, value, NetworkBuffer.QUATERNION);
|
||||
}
|
||||
|
||||
public static Entry<Particle> Particle(@NotNull Particle particle) {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_PARTICLE, particle, NetworkBuffer.PARTICLE);
|
||||
}
|
||||
|
||||
public static final byte TYPE_BYTE = 0;
|
||||
public static final byte TYPE_VARINT = 1;
|
||||
public static final byte TYPE_LONG = 2;
|
||||
|
@ -3,6 +3,7 @@ package net.minestom.server.entity.metadata.other;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import net.minestom.server.entity.metadata.EntityMeta;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AreaEffectCloudMeta extends EntityMeta {
|
||||
@ -37,12 +38,12 @@ public class AreaEffectCloudMeta extends EntityMeta {
|
||||
super.metadata.setIndex(OFFSET + 2, Metadata.Boolean(value));
|
||||
}
|
||||
|
||||
// public ParticleWrapper getParticle() {
|
||||
// return super.metadata.getIndex((byte) 10, new ParticleWrapper(Particle.EFFECT, null));
|
||||
// }
|
||||
//
|
||||
// public void setParticle(ParticleWrapper value) {
|
||||
// super.metadata.setIndex((byte) 11, Metadata.Particle(value));
|
||||
// }
|
||||
public @NotNull Particle getParticle() {
|
||||
return super.metadata.getIndex(OFFSET + 3, Particle.DUST);
|
||||
}
|
||||
|
||||
public void setParticle(@NotNull Particle value) {
|
||||
super.metadata.setIndex(OFFSET + 3, Metadata.Particle(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,13 @@
|
||||
package net.minestom.server.network;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.entity.Entity;
|
||||
@ -8,6 +16,7 @@ import net.minestom.server.entity.metadata.animal.SnifferMeta;
|
||||
import net.minestom.server.entity.metadata.animal.tameable.CatMeta;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.Either;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
@ -20,7 +29,6 @@ import org.jglrxavpok.hephaistos.nbt.NBTWriter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -69,6 +77,7 @@ public final class NetworkBuffer {
|
||||
public static final Type<Point> VECTOR3 = NetworkBufferTypes.VECTOR3;
|
||||
public static final Type<Point> VECTOR3D = NetworkBufferTypes.VECTOR3D;
|
||||
public static final Type<float[]> QUATERNION = NetworkBufferTypes.QUATERNION;
|
||||
public static final Type<Particle> PARTICLE = NetworkBufferTypes.PARTICLE;
|
||||
|
||||
ByteBuffer nioBuffer;
|
||||
final boolean resizable;
|
||||
|
@ -12,6 +12,8 @@ import net.minestom.server.entity.metadata.animal.tameable.CatMeta;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -626,6 +628,17 @@ final class NetworkBufferTypes {
|
||||
final float w = buffer.read(FLOAT);
|
||||
return new float[]{x, y, z, w};
|
||||
});
|
||||
static final TypeImpl<Particle> PARTICLE = new TypeImpl<>(Particle.class,
|
||||
(buffer, value) -> {
|
||||
Check.stateCondition(value.data() != null && !value.data().validate(value.id()), "Particle data {0} is not valid for this particle type {1}", value.data(), value.namespace());
|
||||
Check.stateCondition(value.data() == null && ParticleData.requiresData(value.id()), "Particle data is required for this particle type {0}", value.namespace());
|
||||
|
||||
buffer.write(VAR_INT, value.id());
|
||||
|
||||
if (value.data() != null) value.data().write(buffer);
|
||||
return -1;
|
||||
},
|
||||
buffer -> null);
|
||||
|
||||
record TypeImpl<T>(@NotNull Class<T> type,
|
||||
@NotNull TypeWriter<T> writer,
|
||||
|
@ -4,24 +4,53 @@ import net.minestom.server.network.ConnectionState;
|
||||
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.particle.Particle;
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
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 ParticlePacket(int particleId, boolean longDistance,
|
||||
double x, double y, double z,
|
||||
float offsetX, float offsetY, float offsetZ,
|
||||
float particleData, int particleCount, byte[] data) implements ServerPacket {
|
||||
public record ParticlePacket(int particleId, boolean longDistance, double x, double y, double z, float offsetX, float offsetY, float offsetZ, float maxSpeed, int particleCount, @Nullable ParticleData data) implements ServerPacket {
|
||||
private ParticlePacket(ParticlePacket copy) {
|
||||
this(copy.particleId, copy.longDistance, copy.x, copy.y, copy.z, copy.offsetX, copy.offsetY, copy.offsetZ, copy.maxSpeed, copy.particleCount, copy.data);
|
||||
}
|
||||
|
||||
public ParticlePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.read(BOOLEAN),
|
||||
reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE),
|
||||
reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT),
|
||||
reader.read(FLOAT), reader.read(INT), reader.read(RAW_BYTES));
|
||||
this(readPacket(reader));
|
||||
}
|
||||
|
||||
public ParticlePacket(@NotNull Particle particle, boolean longDistance, double x, double y, double z, int offsetX, int offsetY, int offsetZ, int maxSpeed, int particleCount) {
|
||||
this(particle.id(), longDistance, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount, particle.data());
|
||||
}
|
||||
|
||||
public ParticlePacket(@NotNull Particle particle, double x, double y, double z, int offsetX, int offsetY, int offsetZ, int maxSpeed, int particleCount) {
|
||||
this(particle.id(), false, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount, particle.data());
|
||||
}
|
||||
|
||||
private static ParticlePacket readPacket(NetworkBuffer reader) {
|
||||
int particleId = reader.read(VAR_INT);
|
||||
Boolean longDistance = reader.read(BOOLEAN);
|
||||
Double x = reader.read(DOUBLE);
|
||||
Double y = reader.read(DOUBLE);
|
||||
Double z = reader.read(DOUBLE);
|
||||
Float offsetX = reader.read(FLOAT);
|
||||
Float offsetY = reader.read(FLOAT);
|
||||
Float offsetZ = reader.read(FLOAT);
|
||||
Float maxSpeed = reader.read(FLOAT);
|
||||
Integer particleCount = reader.read(INT);
|
||||
ParticleData data = ParticleData.read(particleId, reader);
|
||||
|
||||
return new ParticlePacket(particleId, longDistance, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
Check.stateCondition(data != null && !data.validate(particleId), "Particle data {0} is not valid for this particle type {1}", data, Particle.fromId(particleId));
|
||||
Check.stateCondition(data == null && ParticleData.requiresData(particleId), "Particle data is required for this particle type {0}", Particle.fromId(particleId));
|
||||
|
||||
writer.write(VAR_INT, particleId);
|
||||
writer.write(BOOLEAN, longDistance);
|
||||
writer.write(DOUBLE, x);
|
||||
@ -30,10 +59,10 @@ public record ParticlePacket(int particleId, boolean longDistance,
|
||||
writer.write(FLOAT, offsetX);
|
||||
writer.write(FLOAT, offsetY);
|
||||
writer.write(FLOAT, offsetZ);
|
||||
writer.write(FLOAT, particleData);
|
||||
writer.write(FLOAT, maxSpeed);
|
||||
writer.write(INT, particleCount);
|
||||
|
||||
writer.write(RAW_BYTES, data);
|
||||
if (data != null) data.write(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.particle;
|
||||
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -24,4 +25,7 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits
|
||||
static @Nullable Particle fromId(int id) {
|
||||
return ParticleImpl.getId(id);
|
||||
}
|
||||
|
||||
@NotNull Particle withData(@Nullable ParticleData data);
|
||||
@Nullable ParticleData data();
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
package net.minestom.server.particle;
|
||||
|
||||
import net.minestom.server.network.packet.server.play.ParticlePacket;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Small utils class to create particle packet
|
||||
*/
|
||||
public class ParticleCreator {
|
||||
|
||||
public static ParticlePacket createParticlePacket(Particle particleType, boolean distance,
|
||||
double x, double y, double z,
|
||||
float offsetX, float offsetY, float offsetZ,
|
||||
float particleData, int count, @Nullable Consumer<BinaryWriter> dataWriter) {
|
||||
byte[] data;
|
||||
if (dataWriter != null) {
|
||||
BinaryWriter writer = new BinaryWriter();
|
||||
dataWriter.accept(writer);
|
||||
data = writer.toByteArray();
|
||||
} else {
|
||||
data = new byte[0];
|
||||
}
|
||||
return new ParticlePacket(particleType.id(), distance, x, y, z, offsetX, offsetY, offsetZ, particleData, count, data);
|
||||
}
|
||||
|
||||
public static ParticlePacket createParticlePacket(Particle particleType,
|
||||
double x, double y, double z,
|
||||
float offsetX, float offsetY, float offsetZ,
|
||||
int count) {
|
||||
return createParticlePacket(particleType, true, x, y, z,
|
||||
offsetX, offsetY, offsetZ, 0, count, null);
|
||||
}
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
package net.minestom.server.particle;
|
||||
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
record ParticleImpl(NamespaceID namespace, int id) implements Particle {
|
||||
record ParticleImpl(NamespaceID namespace, int id, ParticleData data) implements Particle {
|
||||
private static final Registry.Container<Particle> CONTAINER = Registry.createStaticContainer(Registry.Resource.PARTICLES,
|
||||
(namespace, properties) -> new ParticleImpl(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
(namespace, properties) -> new ParticleImpl(NamespaceID.from(namespace), properties.getInt("id"), ParticleData.defaultData(namespace)));
|
||||
|
||||
static Particle get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
@ -26,8 +28,17 @@ record ParticleImpl(NamespaceID namespace, int id) implements Particle {
|
||||
return CONTAINER.values();
|
||||
}
|
||||
|
||||
public @NotNull Particle withData(@Nullable ParticleData object) {
|
||||
return new ParticleImpl(namespace, id, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public @Nullable ParticleData data() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String toString() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record BlockMarkerParticleData(@NotNull Block block) implements ParticleData {
|
||||
BlockMarkerParticleData(NetworkBuffer reader) {
|
||||
this(read(reader));
|
||||
}
|
||||
|
||||
BlockMarkerParticleData() {
|
||||
this(Block.STONE);
|
||||
}
|
||||
|
||||
private static Block read(NetworkBuffer reader) {
|
||||
short blockState = reader.read(NetworkBuffer.VAR_INT).shortValue();
|
||||
Block block = Block.fromStateId(blockState);
|
||||
Check.stateCondition(block == null, "Block state " + blockState + " is invalid");
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.VAR_INT, (int) block.stateId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.BLOCK_MARKER.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record BlockParticleData(Block block) implements ParticleData {
|
||||
BlockParticleData(NetworkBuffer reader) {
|
||||
this(read(reader));
|
||||
}
|
||||
|
||||
BlockParticleData() {
|
||||
this(Block.STONE);
|
||||
}
|
||||
|
||||
private static Block read(NetworkBuffer reader) {
|
||||
short blockState = reader.read(NetworkBuffer.VAR_INT).shortValue();
|
||||
Block block = Block.fromStateId(blockState);
|
||||
Check.stateCondition(block == null, "Block state " + blockState + " is invalid");
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.VAR_INT, (int) block.stateId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.BLOCK.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.kyori.adventure.util.RGBLike;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record DustColorTransitionParticleData(@NotNull RGBLike from, float scale, @NotNull RGBLike to) implements ParticleData {
|
||||
public DustColorTransitionParticleData {
|
||||
Check.argCondition(scale < 0.01 || scale > 4, "scale must be between 0.01 and 4: was {0}", scale);
|
||||
}
|
||||
|
||||
DustColorTransitionParticleData() {
|
||||
this(new Color(255, 255, 255), 1, new Color(255, 255, 255));
|
||||
}
|
||||
|
||||
DustColorTransitionParticleData(NetworkBuffer buffer) {
|
||||
this(new Color(
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255),
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255),
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255)
|
||||
), buffer.read(NetworkBuffer.FLOAT), new Color(
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255),
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255),
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.FLOAT, from.red() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, from.green() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, from.blue() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, scale);
|
||||
writer.write(NetworkBuffer.FLOAT, to.red() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, to.green() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, to.blue() / 255f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.DUST_COLOR_TRANSITION.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.kyori.adventure.util.RGBLike;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record DustParticleData(@NotNull RGBLike color, float scale) implements ParticleData {
|
||||
public DustParticleData {
|
||||
Check.argCondition(scale < 0.01 || scale > 4, "scale must be between 0.01 and 4");
|
||||
}
|
||||
|
||||
DustParticleData(NetworkBuffer buffer) {
|
||||
this(new Color(
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255),
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255),
|
||||
(int) (buffer.read(NetworkBuffer.FLOAT) * 255)
|
||||
), buffer.read(NetworkBuffer.FLOAT));
|
||||
}
|
||||
|
||||
DustParticleData() {
|
||||
this(new Color(255, 255, 255), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.FLOAT, color.red() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, color.green() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, color.blue() / 255f);
|
||||
writer.write(NetworkBuffer.FLOAT, scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.DUST.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record FallingDustParticleData(Block block) implements ParticleData {
|
||||
FallingDustParticleData(NetworkBuffer reader) {
|
||||
this(read(reader));
|
||||
}
|
||||
|
||||
FallingDustParticleData() {
|
||||
this(Block.STONE);
|
||||
}
|
||||
|
||||
private static Block read(NetworkBuffer reader) {
|
||||
short blockState = reader.read(NetworkBuffer.VAR_INT).shortValue();
|
||||
Block block = Block.fromStateId(blockState);
|
||||
Check.stateCondition(block == null, "Block state {0} is invalid", blockState);
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.VAR_INT, (int) block.stateId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.FALLING_DUST.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record ItemParticleData(ItemStack item) implements ParticleData {
|
||||
ItemParticleData(NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.ITEM));
|
||||
}
|
||||
|
||||
ItemParticleData() {
|
||||
this(ItemStack.of(Material.STONE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.ITEM, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.ITEM.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface ParticleData {
|
||||
void write(@NotNull NetworkBuffer writer);
|
||||
|
||||
static ParticleData read(int particleId, NetworkBuffer reader) {
|
||||
if (particleId == Particle.BLOCK.id()) return new BlockParticleData(reader);
|
||||
else if (particleId == Particle.BLOCK_MARKER.id()) return new BlockMarkerParticleData(reader);
|
||||
else if (particleId == Particle.DUST.id()) return new DustParticleData(reader);
|
||||
else if (particleId == Particle.DUST_COLOR_TRANSITION.id()) return new DustColorTransitionParticleData(reader);
|
||||
else if (particleId == Particle.FALLING_DUST.id()) return new FallingDustParticleData(reader);
|
||||
else if (particleId == Particle.SCULK_CHARGE.id()) return new SculkChargeParticleData(reader);
|
||||
else if (particleId == Particle.ITEM.id()) return new ItemParticleData(reader);
|
||||
else if (particleId == Particle.VIBRATION.id()) return new VibrationParticleData(reader);
|
||||
else if (particleId == Particle.SHRIEK.id()) return new ShriekParticleData(reader);
|
||||
else return null;
|
||||
}
|
||||
|
||||
boolean validate(int particleId);
|
||||
|
||||
static boolean requiresData(int particleId) {
|
||||
return particleId == Particle.BLOCK.id()
|
||||
|| particleId == Particle.BLOCK_MARKER.id()
|
||||
|| particleId == Particle.DUST.id()
|
||||
|| particleId == Particle.DUST_COLOR_TRANSITION.id()
|
||||
|| particleId == Particle.FALLING_DUST.id()
|
||||
|| particleId == Particle.SCULK_CHARGE.id()
|
||||
|| particleId == Particle.ITEM.id()
|
||||
|| particleId == Particle.VIBRATION.id()
|
||||
|| particleId == Particle.SHRIEK.id();
|
||||
}
|
||||
|
||||
static ParticleData defaultData(String id) {
|
||||
return switch (id) {
|
||||
case "minecraft:block" -> new BlockParticleData();
|
||||
case "minecraft:block_marker" -> new BlockMarkerParticleData();
|
||||
case "minecraft:dust" -> new DustParticleData();
|
||||
case "minecraft:dust_color_transition" -> new DustColorTransitionParticleData();
|
||||
case "minecraft:falling_dust" -> new FallingDustParticleData();
|
||||
case "minecraft:sculk_charge" -> new SculkChargeParticleData();
|
||||
case "minecraft:item" -> new ItemParticleData();
|
||||
case "minecraft:vibration" -> new VibrationParticleData();
|
||||
case "minecraft:shriek" -> new ShriekParticleData();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record SculkChargeParticleData(float roll) implements ParticleData {
|
||||
SculkChargeParticleData(NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.FLOAT));
|
||||
}
|
||||
|
||||
SculkChargeParticleData() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.FLOAT, roll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.SCULK_CHARGE.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record ShriekParticleData(int delay) implements ParticleData {
|
||||
ShriekParticleData(NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.VAR_INT));
|
||||
}
|
||||
|
||||
ShriekParticleData() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.VAR_INT, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.SHRIEK.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package net.minestom.server.particle.data;
|
||||
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record VibrationParticleData(@NotNull VibrationSource type, @NotNull Point source, int entityId, float entityEyeHeight, int ticks) implements ParticleData {
|
||||
public enum VibrationSource {
|
||||
BLOCK,
|
||||
ENTITY
|
||||
}
|
||||
|
||||
VibrationParticleData(NetworkBuffer buffer) {
|
||||
this(read(buffer));
|
||||
}
|
||||
|
||||
VibrationParticleData() {
|
||||
this(VibrationSource.BLOCK, Vec.ZERO, 0, 0, 0);
|
||||
}
|
||||
|
||||
private VibrationParticleData(VibrationParticleData copy) {
|
||||
this(copy.type, copy.source, copy.entityId, copy.entityEyeHeight, copy.ticks);
|
||||
}
|
||||
|
||||
private static VibrationParticleData read(NetworkBuffer buffer) {
|
||||
VibrationSource type = buffer.readEnum(VibrationSource.class);
|
||||
|
||||
if (type == VibrationSource.BLOCK) {
|
||||
return new VibrationParticleData(type, buffer.read(NetworkBuffer.BLOCK_POSITION), 0, 0, buffer.read(NetworkBuffer.VAR_INT));
|
||||
} else {
|
||||
return new VibrationParticleData(type, Vec.ZERO, buffer.read(NetworkBuffer.VAR_INT), buffer.read(NetworkBuffer.FLOAT), buffer.read(NetworkBuffer.VAR_INT));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.writeEnum(VibrationSource.class, type);
|
||||
|
||||
if (type == VibrationSource.BLOCK) {
|
||||
writer.write(NetworkBuffer.BLOCK_POSITION, source);
|
||||
writer.write(NetworkBuffer.VAR_INT, ticks);
|
||||
} else {
|
||||
writer.write(NetworkBuffer.VAR_INT, entityId);
|
||||
writer.write(NetworkBuffer.FLOAT, entityEyeHeight);
|
||||
writer.write(NetworkBuffer.VAR_INT, ticks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int particleId) {
|
||||
return particleId == Particle.VIBRATION.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package net.minestom.server.entity;
|
||||
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.entity.metadata.other.AreaEffectCloudMeta;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class AreaEffectCloudTest {
|
||||
@Test
|
||||
public void createWithDustParticle() {
|
||||
int colour = 0x5505FF01;
|
||||
|
||||
int b = (colour & 0x000000FF);
|
||||
int g = (colour & 0x0000FF00) >> 8;
|
||||
int r = (colour & 0x00FF0000) >> 16;
|
||||
|
||||
float size = 0.1f;
|
||||
|
||||
Particle particle = Particle.DUST.withData(new DustParticleData(new Color(r, g, b), size));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
DustParticleData gotData = (DustParticleData) gotParticle.data();
|
||||
assertNotNull(gotData);
|
||||
assert gotData.color().red() == r;
|
||||
assert gotData.color().green() == g;
|
||||
assert gotData.color().blue() == b;
|
||||
assert gotData.scale() == size;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithDustTransition() {
|
||||
int colour = 0xFF05FF01;
|
||||
int colourAfter = 0xFF05FF01;
|
||||
|
||||
int b = (colour & 0x000000FF);
|
||||
int g = (colour & 0x0000FF00) >> 8;
|
||||
int r = (colour & 0x00FF0000) >> 16;
|
||||
|
||||
int b2 = (colourAfter & 0x000000FF);
|
||||
int g2 = (colourAfter & 0x0000FF00) >> 8;
|
||||
int r2 = (colourAfter & 0x00FF0000) >> 16;
|
||||
|
||||
float size = 0.1f;
|
||||
|
||||
Particle particle = Particle.DUST_COLOR_TRANSITION.withData(new DustColorTransitionParticleData(new Color(r, g, b), size, new Color(r2, g2, b2)));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
DustColorTransitionParticleData gotData = (DustColorTransitionParticleData) gotParticle.data();
|
||||
assertNotNull(gotData);
|
||||
assert gotData.from().red() == r;
|
||||
assert gotData.from().green() == g;
|
||||
assert gotData.from().blue() == b;
|
||||
assert gotData.scale() == size;
|
||||
assert gotData.to().red() == r2;
|
||||
assert gotData.to().green() == g2;
|
||||
assert gotData.to().blue() == b2;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithBlockParticle() {
|
||||
Block block = Block.GRASS_BLOCK;
|
||||
Particle particle = Particle.BLOCK.withData(new BlockParticleData(block));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
BlockParticleData gotBlock = (BlockParticleData) gotParticle.data();
|
||||
assert gotBlock.block() == block;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithBlockMarkerParticle() {
|
||||
Block block = Block.GRASS_BLOCK;
|
||||
Particle particle = Particle.BLOCK_MARKER.withData(new BlockMarkerParticleData(block));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
BlockMarkerParticleData gotBlock = (BlockMarkerParticleData) gotParticle.data();
|
||||
assert gotBlock.block() == block;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithItemParticle() {
|
||||
Particle particle = Particle.ITEM.withData(new ItemParticleData(ItemStack.of(Material.ACACIA_LOG)));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
ItemParticleData gotBlock = (ItemParticleData) gotParticle.data();
|
||||
assert gotBlock.item().material() == Material.ACACIA_LOG;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithSculkChargeParticle() {
|
||||
Particle particle = Particle.SCULK_CHARGE.withData(new SculkChargeParticleData(3));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
SculkChargeParticleData gotBlock = (SculkChargeParticleData) gotParticle.data();
|
||||
assert gotBlock.roll() == 3;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithDustParticleIncorrectType() {
|
||||
Particle particle = Particle.DUST.withData(new FallingDustParticleData(Block.GLOWSTONE));
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
assertThrows(IllegalStateException.class, () -> entity.getMetadataPacket().write(new NetworkBuffer()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithComposterParticle() {
|
||||
Particle particle = Particle.COMPOSTER;
|
||||
|
||||
Entity entity = new Entity(EntityTypes.AREA_EFFECT_CLOUD);
|
||||
AreaEffectCloudMeta meta = (AreaEffectCloudMeta) entity.getEntityMeta();
|
||||
meta.setParticle(particle);
|
||||
|
||||
var gotParticle = meta.getParticle();
|
||||
assert gotParticle == particle;
|
||||
|
||||
ParticleData gotBlock = gotParticle.data();
|
||||
assertNull(gotBlock);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package net.minestom.server.particle;
|
||||
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.play.ParticlePacket;
|
||||
import net.minestom.server.particle.data.BlockParticleData;
|
||||
import net.minestom.server.particle.data.DustParticleData;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class ParticleDataTest {
|
||||
|
||||
@Test
|
||||
public void testDustParticleDefault() {
|
||||
Particle particle = Particle.DUST;
|
||||
ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
assertDoesNotThrow(() -> packet.write(new NetworkBuffer()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDustParticleInvalid() {
|
||||
var particle = Particle.DUST.withData(null);
|
||||
ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
assertThrows(IllegalStateException.class, () -> packet.write(new NetworkBuffer()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDustParticleWrongData() {
|
||||
var particle = Particle.DUST.withData(new BlockParticleData(Block.STONE));
|
||||
ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
assertThrows(IllegalStateException.class, () -> packet.write(new NetworkBuffer()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDustParticleWrongParameters() {
|
||||
assertThrows(IllegalArgumentException.class, () -> Particle.DUST.withData(new DustParticleData(new Color(255, 255, 255), 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParticleValid() {
|
||||
var particle = Particle.AMBIENT_ENTITY_EFFECT;
|
||||
ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
assertDoesNotThrow(() -> packet.write(new NetworkBuffer()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParticleData() {
|
||||
var particle = Particle.AMBIENT_ENTITY_EFFECT;
|
||||
ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
assertDoesNotThrow(() -> packet.write(new NetworkBuffer()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidBlock() {
|
||||
var particle = Particle.BLOCK.withData(new BlockParticleData(null));
|
||||
ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
assertThrows(NullPointerException.class, () -> packet.write(new NetworkBuffer()));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user