Added new metadata API

This commit is contained in:
themode 2021-01-30 04:44:44 +01:00
parent 59c4cd9382
commit 3026e46220
31 changed files with 521 additions and 1196 deletions

View File

@ -26,7 +26,7 @@ import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.BitmaskUtil;
import net.minestom.server.utils.callback.OptionalCallback;
import net.minestom.server.utils.chunk.ChunkCallback;
import net.minestom.server.utils.chunk.ChunkUtils;
@ -121,21 +121,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
// Events
private final Map<Class<? extends Event>, Collection<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
// Metadata
protected boolean onFire;
protected boolean crouched;
protected boolean UNUSED_METADATA;
protected boolean sprinting;
protected boolean swimming;
protected boolean invisible;
protected boolean glowing;
protected boolean usingElytra;
protected int air = 300;
protected JsonMessage customName;
protected boolean customNameVisible;
protected boolean silent;
protected boolean noGravity;
protected Pose pose = Pose.STANDING;
protected Metadata metadata = new Metadata(this);
private final List<TimedPotion> effects = new CopyOnWriteArrayList<>();
@ -487,7 +473,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
Vector newVelocityOut = new Vector();
// Gravity force
final double gravityY = !noGravity ? Math.min(
final double gravityY = !hasNoGravity() ? Math.min(
gravityDragPerTick + (gravityAcceleration * (double) gravityTickCount),
gravityTerminalVelocity) : 0;
@ -974,7 +960,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @return true if the entity is in fire, false otherwise
*/
public boolean isOnFire() {
return onFire;
return (getStateMeta() & 0x01) != 0;
}
/**
@ -986,8 +972,56 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @param fire should the entity be set in fire
*/
public void setOnFire(boolean fire) {
this.onFire = fire;
sendMetadataIndex(0);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x01, (byte) (fire ? 1 : 0), (byte) 0);
this.metadata.setIndex((byte) 0, Metadata.Byte(state));
}
/**
* Gets if the entity is sneaking.
* <p>
* WARNING: this can be bypassed by hacked client, this is only what the client told the server.
*
* @return true if the player is sneaking
*/
public boolean isSneaking() {
return (getStateMeta() & 0x02) != 0;
}
/**
* Makes the entity sneak.
* <p>
* WARNING: this will not work for the client itself.
*
* @param sneaking true to make the entity sneak
*/
public void setSneaking(boolean sneaking) {
setPose(sneaking ? Pose.SNEAKING : Pose.STANDING);
// update the crouched metadata
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x02, (byte) (sneaking ? 1 : 0), (byte) 1);
this.metadata.setIndex((byte) 0, Metadata.Byte(state));
}
/**
* Gets if the player is sprinting.
* <p>
* WARNING: this can be bypassed by hacked client, this is only what the client told the server.
*
* @return true if the player is sprinting
*/
public boolean isSprinting() {
return (getStateMeta() & 0x08) != 0;
}
/**
* Makes the entity sprint.
* <p>
* WARNING: this will not work on the client itself.
*
* @param sprinting true to make the entity sprint
*/
public void setSprinting(boolean sprinting) {
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x08, (byte) (sprinting ? 1 : 0), (byte) 3);
this.metadata.setIndex((byte) 0, Metadata.Byte(state));
}
/**
@ -996,7 +1030,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @return true if the entity is invisible, false otherwise
*/
public boolean isInvisible() {
return invisible;
return (getStateMeta() & 0x20) != 0;
}
/**
@ -1006,8 +1040,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @param invisible true to set the entity invisible, false otherwise
*/
public void setInvisible(boolean invisible) {
this.invisible = invisible;
sendMetadataIndex(0);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x20, (byte) (invisible ? 1 : 0), (byte) 5);
this.metadata.setIndex((byte) 0, Metadata.Byte(state));
}
/**
@ -1016,7 +1050,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @return true if the entity is glowing, false otherwise
*/
public boolean isGlowing() {
return glowing;
return (getStateMeta() & 0x40) != 0;
}
/**
@ -1025,8 +1059,31 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @param glowing true to make the entity glows, false otherwise
*/
public void setGlowing(boolean glowing) {
this.glowing = glowing;
sendMetadataIndex(0);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x40, (byte) (glowing ? 1 : 0), (byte) 6);
this.metadata.setIndex((byte) 0, Metadata.Byte(state));
}
/**
* Gets the current entity pose.
*
* @return the entity pose
*/
@NotNull
public Pose getPose() {
return metadata.getIndex((byte) 6, Pose.STANDING);
}
/**
* Changes the entity pose.
* <p>
* The internal {@code crouched} and {@code swimming} field will be
* updated accordingly.
*
* @param pose the new entity pose
*/
@NotNull
public void setPose(@NotNull Pose pose) {
this.metadata.setIndex((byte) 6, Metadata.Pose(pose));
}
/**
@ -1034,8 +1091,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
*
* @return the custom name of the entity, null if there is not
*/
@Nullable
public JsonMessage getCustomName() {
return customName;
return metadata.getIndex((byte) 2, null);
}
/**
@ -1043,9 +1101,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
*
* @param customName the custom name of the entity, null to remove it
*/
public void setCustomName(JsonMessage customName) {
this.customName = customName;
sendMetadataIndex(2);
public void setCustomName(@Nullable JsonMessage customName) {
this.metadata.setIndex((byte) 2, Metadata.OptChat(customName));
}
/**
@ -1054,7 +1111,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @return true if the custom name is visible, false otherwise
*/
public boolean isCustomNameVisible() {
return customNameVisible;
return metadata.getIndex((byte) 3, false);
}
/**
@ -1064,27 +1121,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @param customNameVisible true to make the custom name visible, false otherwise
*/
public void setCustomNameVisible(boolean customNameVisible) {
this.customNameVisible = customNameVisible;
sendMetadataIndex(3);
this.metadata.setIndex((byte) 3, Metadata.Boolean(customNameVisible));
}
public boolean isSilent() {
return silent;
return metadata.getIndex((byte) 4, false);
}
public void setSilent(boolean silent) {
this.silent = silent;
sendMetadataIndex(4);
}
/**
* Changes the noGravity metadata field and change the gravity behaviour accordingly.
*
* @param noGravity should the entity ignore gravity
*/
public void setNoGravity(boolean noGravity) {
this.noGravity = noGravity;
sendMetadataIndex(5);
this.metadata.setIndex((byte) 4, Metadata.Boolean(silent));
}
/**
@ -1093,7 +1138,16 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
* @return true if the entity ignore gravity, false otherwise
*/
public boolean hasNoGravity() {
return noGravity;
return metadata.getIndex((byte) 5, false);
}
/**
* Changes the noGravity metadata field and change the gravity behaviour accordingly.
*
* @param noGravity should the entity ignore gravity
*/
public void setNoGravity(boolean noGravity) {
this.metadata.setIndex((byte) 5, Metadata.Boolean(noGravity));
}
/**
@ -1176,56 +1230,6 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
this.cachePitch = pitch;
}
/**
* Makes the entity sneak.
* <p>
* WARNING: this will not work for the client itself.
*
* @param sneaking true to make the entity sneak
*/
public void setSneaking(boolean sneaking) {
setPose(sneaking ? Pose.SNEAKING : Pose.STANDING);
sendMetadataIndex(0); // update the crouched metadata
}
/**
* Gets the current entity pose.
*
* @return the entity pose
*/
@NotNull
public Pose getPose() {
return pose;
}
/**
* Changes the entity pose.
* <p>
* The internal {@code crouched} and {@code swimming} field will be
* updated accordingly.
*
* @param pose the new entity pose
*/
@NotNull
public void setPose(@NotNull Pose pose) {
this.crouched = pose == Pose.SNEAKING;
this.swimming = pose == Pose.SWIMMING;
this.pose = pose;
sendMetadataIndex(6);
}
/**
* Makes the entity sprint.
* <p>
* WARNING: this will not work on the client itself.
*
* @param sprinting true to make the entity sprint
*/
public void setSprinting(boolean sprinting) {
this.sprinting = sprinting;
sendMetadataIndex(0);
}
/**
* Gets the entity position.
*
@ -1355,138 +1359,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
public EntityMetaDataPacket getMetadataPacket() {
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
metaDataPacket.entityId = getEntityId();
metaDataPacket.consumer = getMetadataConsumer();
metaDataPacket.entries = metadata.getEntries();
return metaDataPacket;
}
/**
* Should be override when wanting to add a new metadata index
*
* @return The consumer used to write {@link EntityMetaDataPacket} in {@link #getMetadataPacket()}
*/
@NotNull
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
fillMetadataIndex(packet, 0);
fillMetadataIndex(packet, 1);
fillMetadataIndex(packet, 2);
fillMetadataIndex(packet, 3);
fillMetadataIndex(packet, 4);
fillMetadataIndex(packet, 5);
fillMetadataIndex(packet, 6);
};
}
/**
* Sends a {@link EntityMetaDataPacket} containing only the specified index
* The index is wrote using {@link #fillMetadataIndex(BinaryWriter, int)}.
*
* @param index the metadata index
*/
protected void sendMetadataIndex(int index) {
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
metaDataPacket.entityId = getEntityId();
metaDataPacket.consumer = packet -> fillMetadataIndex(packet, index);
sendPacketToViewersAndSelf(metaDataPacket);
}
/**
* Used to fill/write a specific metadata index.
* The proper use to add a new metadata index is to override this and add your case.
* Then you can also override {@link #getMetadataConsumer()} and fill your newly added index.
*
* @param packet the packet writer
* @param index the index to fill/write
*/
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
switch (index) {
case 0:
fillStateMetadata(packet);
break;
case 1:
fillAirTickMetaData(packet);
break;
case 2:
fillCustomNameMetaData(packet);
break;
case 3:
fillCustomNameVisibleMetaData(packet);
break;
case 4:
fillSilentMetaData(packet);
break;
case 5:
fillNoGravityMetaData(packet);
break;
case 6:
fillPoseMetaData(packet);
break;
}
}
private void fillStateMetadata(@NotNull BinaryWriter packet) {
packet.writeByte((byte) 0);
packet.writeByte(METADATA_BYTE);
byte index0 = 0;
if (onFire)
index0 += 1;
if (crouched)
index0 += 2;
if (UNUSED_METADATA)
index0 += 4;
if (sprinting)
index0 += 8;
if (swimming)
index0 += 16;
if (invisible)
index0 += 32;
if (glowing)
index0 += 64;
if (usingElytra)
index0 += 128;
packet.writeByte(index0);
}
private void fillAirTickMetaData(@NotNull BinaryWriter packet) {
packet.writeByte((byte) 1);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(air);
}
private void fillCustomNameMetaData(@NotNull BinaryWriter packet) {
boolean hasCustomName = customName != null;
packet.writeByte((byte) 2);
packet.writeByte(METADATA_OPTCHAT);
packet.writeBoolean(hasCustomName);
if (hasCustomName) {
packet.writeSizedString(customName.toString());
}
}
private void fillCustomNameVisibleMetaData(@NotNull BinaryWriter packet) {
packet.writeByte((byte) 3);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(customNameVisible);
}
private void fillSilentMetaData(@NotNull BinaryWriter packet) {
packet.writeByte((byte) 4);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(silent);
}
private void fillNoGravityMetaData(@NotNull BinaryWriter packet) {
packet.writeByte((byte) 5);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(noGravity);
}
private void fillPoseMetaData(@NotNull BinaryWriter packet) {
packet.writeByte((byte) 6);
packet.writeByte(METADATA_POSE);
packet.writeVarInt(pose.ordinal());
private byte getStateMeta() {
return metadata.getIndex((byte) 0, (byte) 0);
}
protected void sendSynchronization() {

View File

@ -6,7 +6,6 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
@ -14,7 +13,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.function.Consumer;
/**
* Represents an item on the ground.
@ -42,7 +40,7 @@ public class ItemEntity extends ObjectEntity {
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition) {
super(EntityType.ITEM, spawnPosition);
this.itemStack = itemStack;
setItemStack(itemStack);
setBoundingBox(0.25f, 0.25f, 0.25f);
}
@ -129,26 +127,6 @@ public class ItemEntity extends ObjectEntity {
this.spawnTime = System.currentTimeMillis();
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
packet.writeByte(METADATA_SLOT);
packet.writeItemStack(itemStack);
}
}
@Override
public int getObjectData() {
return 1;
@ -159,6 +137,7 @@ public class ItemEntity extends ObjectEntity {
*
* @return the item stack
*/
@NotNull
public ItemStack getItemStack() {
return itemStack;
}
@ -168,9 +147,9 @@ public class ItemEntity extends ObjectEntity {
*
* @param itemStack the item stack
*/
public void setItemStack(ItemStack itemStack) {
public void setItemStack(@NotNull ItemStack itemStack) {
this.itemStack = itemStack;
sendMetadataIndex(7); // Refresh the ItemStack for viewers
this.metadata.setIndex((byte) 7, Metadata.Slot(itemStack));
}
/**

View File

@ -22,7 +22,6 @@ import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.block.BlockIterator;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit;
@ -32,7 +31,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
//TODO: Default attributes registration (and limitation ?)
public abstract class LivingEntity extends Entity implements EquipmentHandler {
@ -44,7 +42,6 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
protected boolean isDead;
private float health;
protected DamageType lastDamageSource;
// Bounding box used for items' pickup (see LivingEntity#setBoundingBox)
@ -52,12 +49,6 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
private final Map<String, AttributeInstance> attributeModifiers = new ConcurrentHashMap<>(Attribute.values().length);
private boolean isHandActive;
private boolean offHand;
private boolean riptideSpinAttack;
// The number of arrows in entity
private int arrowCount;
// Abilities
protected boolean invulnerable;
@ -138,50 +129,13 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
fillMetadataIndex(packet, 8);
fillMetadataIndex(packet, 11);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
packet.writeByte(METADATA_BYTE);
byte activeHandValue = 0;
if (isHandActive) {
activeHandValue += 1;
if (offHand)
activeHandValue += 2;
if (riptideSpinAttack)
activeHandValue += 4;
}
packet.writeByte(activeHandValue);
} else if (index == 8) {
packet.writeByte((byte) 8);
packet.writeByte(METADATA_FLOAT);
packet.writeFloat(health);
} else if (index == 11) {
packet.writeByte((byte) 11);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(arrowCount);
}
}
/**
* Gets the amount of arrows in the entity.
*
* @return the arrow count
*/
public int getArrowCount() {
return arrowCount;
return metadata.getIndex((byte) 11, 0);
}
/**
@ -190,8 +144,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
* @param arrowCount the arrow count
*/
public void setArrowCount(int arrowCount) {
this.arrowCount = arrowCount;
sendMetadataIndex(11);
this.metadata.setIndex((byte) 11, Metadata.VarInt(arrowCount));
}
/**
@ -345,7 +298,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
* @return the entity health
*/
public float getHealth() {
return health;
return metadata.getIndex((byte) 8, 1f);
}
/**
@ -355,12 +308,11 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
*/
public void setHealth(float health) {
health = Math.min(health, getMaxHealth());
this.health = health;
if (this.health <= 0 && !isDead) {
if (health <= 0 && !isDead) {
kill();
}
sendMetadataIndex(8); // Health metadata index
this.metadata.setIndex((byte) 8, Metadata.Float(health));
}
/**
@ -478,11 +430,15 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
public void refreshActiveHand(boolean isHandActive, boolean offHand, boolean riptideSpinAttack) {
this.isHandActive = isHandActive;
this.offHand = offHand;
this.riptideSpinAttack = riptideSpinAttack;
byte handState = 0;
if (isHandActive)
handState |= 0x01;
if (offHand)
handState |= 0x02;
if (riptideSpinAttack)
handState |= 0x04;
sendPacketToViewers(getMetadataPacket());
this.metadata.setIndex((byte) 7, Metadata.Byte(handState));
}
/**

View File

@ -0,0 +1,214 @@
package net.minestom.server.entity;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.EntityMetaDataPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
public class Metadata {
// METADATA TYPES
public static Value<Byte> Byte(byte value) {
return new Value<>(TYPE_BYTE, value, writer -> writer.writeByte(value));
}
public static Value<Integer> VarInt(int value) {
return new Value<>(TYPE_VARINT, value, writer -> writer.writeVarInt(value));
}
public static Value<Float> Float(float value) {
return new Value<>(TYPE_FLOAT, value, writer -> writer.writeFloat(value));
}
public static Value<String> String(@NotNull String value) {
return new Value<>(TYPE_STRING, value, writer -> writer.writeSizedString(value));
}
public static Value<JsonMessage> Chat(@NotNull JsonMessage value) {
return new Value<>(TYPE_CHAT, value, writer -> writer.writeSizedString(value.toString()));
}
public static Value<JsonMessage> OptChat(@Nullable JsonMessage value) {
return new OptionalValue<>(TYPE_OPTCHAT, value, writer -> {
assert value != null;
writer.writeSizedString(value.toString());
});
}
public static Value<ItemStack> Slot(@NotNull ItemStack value) {
return new Value<>(TYPE_SLOT, value, writer -> writer.writeItemStack(value));
}
public static Value<Boolean> Boolean(boolean value) {
return new Value<>(TYPE_BOOLEAN, value, writer -> writer.writeBoolean(value));
}
public static Value<Vector> Rotation(@NotNull Vector value) {
return new Value<>(TYPE_ROTATION, value, writer -> {
writer.writeFloat((float) value.getX());
writer.writeFloat((float) value.getY());
writer.writeFloat((float) value.getZ());
});
}
public static Value<BlockPosition> Position(@NotNull BlockPosition value) {
return new Value<>(TYPE_POSITION, value, writer -> writer.writeBlockPosition(value));
}
public static Value<BlockPosition> OptPosition(@Nullable BlockPosition value) {
return new OptionalValue<>(TYPE_OPTPOSITION, value, writer -> {
assert value != null;
writer.writeBlockPosition(value);
});
}
public static Value<Direction> Direction(@NotNull Direction value) {
return new Value<>(TYPE_DIRECTION, value, writer -> writer.writeVarInt(value.ordinal()));
}
public static Value<UUID> OptUUID(@Nullable UUID value) {
return new OptionalValue<>(TYPE_OPTUUID, value, writer -> {
assert value != null;
writer.writeUuid(value);
});
}
public static Value<Entity.Pose> Pose(@NotNull Entity.Pose value) {
return new Value<>(TYPE_POSE, value, writer -> writer.writeVarInt(value.ordinal()));
}
public static final byte TYPE_BYTE = 0;
public static final byte TYPE_VARINT = 1;
public static final byte TYPE_FLOAT = 2;
public static final byte TYPE_STRING = 3;
public static final byte TYPE_CHAT = 4;
public static final byte TYPE_OPTCHAT = 5;
public static final byte TYPE_SLOT = 6;
public static final byte TYPE_BOOLEAN = 7;
public static final byte TYPE_ROTATION = 8;
public static final byte TYPE_POSITION = 9;
public static final byte TYPE_OPTPOSITION = 10;
public static final byte TYPE_DIRECTION = 11;
public static final byte TYPE_OPTUUID = 12;
public static final byte TYPE_OPTBLOCKID = 13;
public static final byte TYPE_NBT = 14;
public static final byte TYPE_PARTICLE = 15;
public static final byte TYPE_VILLAGERDATA = 16;
public static final byte TYPE_OPTVARINT = 17;
public static final byte TYPE_POSE = 18;
private final Entity entity;
private Map<Byte, Entry<?>> metadataMap = new ConcurrentHashMap<>();
public Metadata(@Nullable Entity entity) {
this.entity = entity;
}
public <T> T getIndex(byte index, @Nullable T defaultValue) {
Entry<?> value = metadataMap.get(index);
return value != null ? (T) value.getMetaValue().value : defaultValue;
}
public void setIndex(byte index, @NotNull Value<?> value) {
final Entry<?> entry = new Entry<>(index, value);
this.metadataMap.put(index, entry);
// Send metadata packet to update viewers and self
if (entity != null && entity.isActive()) {
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
metaDataPacket.entityId = entity.getEntityId();
metaDataPacket.entries = Collections.singleton(entry);
this.entity.sendPacketToViewersAndSelf(metaDataPacket);
}
}
@NotNull
public Collection<Entry<?>> getEntries() {
return metadataMap.values();
}
public static class Entry<T> implements Writeable {
protected final byte index;
protected final Value<T> value;
private Entry(byte index, @NotNull Value<T> value) {
this.index = index;
this.value = value;
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeByte(index);
this.value.write(writer);
}
public byte getIndex() {
return index;
}
@NotNull
public Value<T> getMetaValue() {
return value;
}
}
public static class Value<T> implements Writeable {
protected final int type;
protected final T value;
protected final Consumer<BinaryWriter> valueWriter;
private Value(int type, T value, @NotNull Consumer<BinaryWriter> valueWriter) {
this.type = type;
this.value = value;
this.valueWriter = valueWriter;
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeVarInt(type);
this.valueWriter.accept(writer);
}
public int getType() {
return type;
}
public T getValue() {
return value;
}
}
private static class OptionalValue<T> extends Value<T> {
private OptionalValue(int type, T value, @NotNull Consumer<BinaryWriter> valueWriter) {
super(type, value, valueWriter);
}
@Override
public void write(@NotNull BinaryWriter writer) {
final boolean present = value != null;
writer.writeBoolean(present);
if (present) {
super.write(writer);
}
}
}
}

View File

@ -50,7 +50,6 @@ import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory;
import net.minestom.server.stat.PlayerStatistic;
import net.minestom.server.utils.*;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.callback.OptionalCallback;
import net.minestom.server.utils.chunk.ChunkCallback;
import net.minestom.server.utils.chunk.ChunkUtils;
@ -68,7 +67,6 @@ import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
* Those are the major actors of the server,
@ -148,7 +146,6 @@ public class Player extends LivingEntity implements CommandSender {
private Position respawnPoint;
private float additionalHearts;
private int food;
private float foodSaturation;
private long startEatingTime;
@ -766,30 +763,6 @@ public class Player extends LivingEntity implements CommandSender {
callEvent(PlayerSpawnEvent.class, spawnEvent);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 14);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 14) {
packet.writeByte((byte) 14);
packet.writeByte(METADATA_FLOAT);
packet.writeFloat(additionalHearts);
} else if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_BYTE);
packet.writeByte(getSettings().getDisplayedSkinParts());
}
}
/**
* Sends a plugin message to the player.
*
@ -1134,17 +1107,16 @@ public class Player extends LivingEntity implements CommandSender {
* @return the player additional hearts
*/
public float getAdditionalHearts() {
return additionalHearts;
return metadata.getIndex((byte) 14, 0f);
}
/**
* Updates the internal field and send the appropriate {@link EntityMetaDataPacket}.
* Changes the amount of additional hearts shown.
*
* @param additionalHearts the count of additional hearts
*/
public void setAdditionalHearts(float additionalHearts) {
this.additionalHearts = additionalHearts;
sendMetadataIndex(14);
this.metadata.setIndex((byte) 14, Metadata.Float(additionalHearts));
}
/**
@ -1844,28 +1816,6 @@ public class Player extends LivingEntity implements CommandSender {
this.belowNameTag = belowNameTag;
}
/**
* Gets if the player is sneaking.
* <p>
* WARNING: this can be bypassed by hacked client, this is only what the client told the server.
*
* @return true if the player is sneaking
*/
public boolean isSneaking() {
return crouched;
}
/**
* Gets if the player is sprinting.
* <p>
* WARNING: this can be bypassed by hacked client, this is only what the client told the server.
*
* @return true if the player is sprinting
*/
public boolean isSprinting() {
return sprinting;
}
/**
* Used to get the {@link CustomBlock} that the player is currently mining.
*
@ -2663,7 +2613,8 @@ public class Player extends LivingEntity implements CommandSender {
this.chatColors = chatColors;
this.displayedSkinParts = displayedSkinParts;
this.mainHand = mainHand;
sendMetadataIndex(16);
metadata.setIndex((byte) 16, Metadata.Byte(displayedSkinParts));
this.firstRefresh = false;

View File

@ -2,48 +2,24 @@ package net.minestom.server.entity.type.ambient;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityBat extends EntityCreature implements Animal {
private boolean hanging;
public EntityBat(Position spawnPosition) {
super(EntityType.BAT, spawnPosition);
setBoundingBox(0.5f, 0.9f, 0.5f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BYTE);
packet.writeByte((byte) (hanging ? 1 : 0));
}
}
/**
* Gets if the bat is hanging.
*
* @return true if the bat is hanging, false otherwise
*/
public boolean isHanging() {
return hanging;
return metadata.getIndex((byte) 15, 0) == 1;
}
/**
@ -52,6 +28,6 @@ public class EntityBat extends EntityCreature implements Animal {
* @param hanging true to make the bat hanging, false otherwise
*/
public void setHanging(boolean hanging) {
this.hanging = hanging;
this.metadata.setIndex((byte) 15, Metadata.Byte((byte) (hanging ? 1 : 0)));
}
}

View File

@ -2,49 +2,25 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityMooshroom extends EntityCreature implements Animal {
private MooshroomType mooshroomType;
public EntityMooshroom(Position spawnPosition) {
super(EntityType.MOOSHROOM, spawnPosition);
setBoundingBox(0.9f, 1.4f, 0.9f);
setMooshroomType(MooshroomType.RED);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_STRING);
packet.writeSizedString(mooshroomType.getIdentifier());
}
}
public MooshroomType getMooshroomType() {
return mooshroomType;
final String identifier = metadata.getIndex((byte) 16, "red");
return MooshroomType.fromIdentifier(identifier);
}
public void setMooshroomType(MooshroomType mooshroomType) {
this.mooshroomType = mooshroomType;
sendMetadataIndex(16);
public void setMooshroomType(@NotNull MooshroomType mooshroomType) {
this.metadata.setIndex((byte) 16, Metadata.String(mooshroomType.getIdentifier()));
}
public enum MooshroomType {
@ -61,5 +37,14 @@ public class EntityMooshroom extends EntityCreature implements Animal {
private String getIdentifier() {
return identifier;
}
public static MooshroomType fromIdentifier(String identifier) {
if (identifier.equals("red")) {
return RED;
} else if (identifier.equals("brown")) {
return BROWN;
}
throw new IllegalArgumentException("Weird thing happened");
}
}
}

View File

@ -2,48 +2,24 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityPig extends EntityCreature implements Animal {
private boolean saddle;
public EntityPig(Position spawnPosition) {
super(EntityType.PIG, spawnPosition);
setBoundingBox(0.9f, 0.9f, 0.9f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(saddle);
}
}
/**
* Gets if the pig has a saddle.
*
* @return true if the pig has a saddle, false otherwise
*/
public boolean hasSaddle() {
return saddle;
return metadata.getIndex((byte) 16, false);
}
/**
@ -52,7 +28,6 @@ public class EntityPig extends EntityCreature implements Animal {
* @param saddle true to add a saddle, false to remove it
*/
public void setSaddle(boolean saddle) {
this.saddle = saddle;
sendMetadataIndex(16);
this.metadata.setIndex((byte) 16, Metadata.Boolean(saddle));
}
}

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityPolarBear extends EntityCreature implements Animal {
private boolean standingUp;
public EntityPolarBear(Position spawnPosition) {
super(EntityType.POLAR_BEAR, spawnPosition);
setBoundingBox(1.3f, 1.4f, 1.3f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(standingUp);
}
}
public boolean isStandingUp() {
return standingUp;
return metadata.getIndex((byte) 16, false);
}
public void setStandingUp(boolean standingUp) {
this.standingUp = standingUp;
sendMetadataIndex(16);
this.metadata.setIndex((byte) 16, Metadata.Boolean(standingUp));
}
}

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityRabbit extends EntityCreature implements Animal {
private int type;
public EntityRabbit(Position spawnPosition) {
super(EntityType.RABBIT, spawnPosition);
setBoundingBox(0.4f, 0.5f, 0.4f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(type);
}
}
public int getType() {
return type;
return metadata.getIndex((byte) 16, 0);
}
public void setType(int type) {
this.type = type;
sendMetadataIndex(16);
this.metadata.setIndex((byte) 16, Metadata.VarInt(type));
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.entity.type.decoration;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent;
@ -9,25 +10,11 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.EntityEquipmentPacket;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.BitmaskUtil;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
private boolean small;
private boolean hasArms;
private boolean noBasePlate;
private boolean setMarker;
private Vector headRotation;
private Vector bodyRotation;
private Vector leftArmRotation;
private Vector rightArmRotation;
private Vector leftLegRotation;
private Vector rightLegRotation;
// Equipments
private ItemStack mainHandItem;
private ItemStack offHandItem;
@ -72,76 +59,6 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
return 0;
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 14);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 16);
fillMetadataIndex(packet, 17);
fillMetadataIndex(packet, 18);
fillMetadataIndex(packet, 19);
fillMetadataIndex(packet, 20);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 14) {
packet.writeByte((byte) 14);
packet.writeByte(METADATA_BYTE);
byte dataValue = 0;
if (isSmall())
dataValue |= 0x01;
if (hasArms)
dataValue |= 0x04;
if (hasNoBasePlate())
dataValue |= 0x08;
if (hasMarker())
dataValue |= 0x10;
packet.writeByte(dataValue);
} else if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_ROTATION);
packet.writeFloat(getRotationX(headRotation));
packet.writeFloat(getRotationY(headRotation));
packet.writeFloat(getRotationZ(headRotation));
} else if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_ROTATION);
packet.writeFloat(getRotationX(bodyRotation));
packet.writeFloat(getRotationY(bodyRotation));
packet.writeFloat(getRotationZ(bodyRotation));
} else if (index == 17) {
packet.writeByte((byte) 17);
packet.writeByte(METADATA_ROTATION);
packet.writeFloat(getRotationX(leftArmRotation));
packet.writeFloat(getRotationY(leftArmRotation));
packet.writeFloat(getRotationZ(leftArmRotation));
} else if (index == 18) {
packet.writeByte((byte) 18);
packet.writeByte(METADATA_ROTATION);
packet.writeFloat(getRotationX(rightArmRotation));
packet.writeFloat(getRotationY(rightArmRotation));
packet.writeFloat(getRotationZ(rightArmRotation));
} else if (index == 19) {
packet.writeByte((byte) 19);
packet.writeByte(METADATA_ROTATION);
packet.writeFloat(getRotationX(leftLegRotation));
packet.writeFloat(getRotationY(leftLegRotation));
packet.writeFloat(getRotationZ(leftLegRotation));
} else if (index == 20) {
packet.writeByte((byte) 20);
packet.writeByte(METADATA_ROTATION);
packet.writeFloat(getRotationX(rightLegRotation));
packet.writeFloat(getRotationY(rightLegRotation));
packet.writeFloat(getRotationZ(rightLegRotation));
}
}
@NotNull
@Override
public ItemStack getItemInMainHand() {
@ -215,12 +132,12 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
}
public boolean isSmall() {
return small;
return (getStateMeta() & 0x01) != 0;
}
public void setSmall(boolean small) {
this.small = small;
sendMetadataIndex(14);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x01, (byte) (small ? 1 : 0), (byte) 0);
this.metadata.setIndex((byte) 14, Metadata.Byte(state));
if (small) {
setBoundingBox(0.25f, 0.9875f, 0.25f);
@ -230,96 +147,88 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
}
public boolean hasArms() {
return hasArms;
return (getStateMeta() & 0x04) != 0;
}
public void setHasArms(boolean hasArms) {
this.hasArms = hasArms;
sendMetadataIndex(14);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x08, (byte) (hasArms ? 1 : 0), (byte) 2);
this.metadata.setIndex((byte) 14, Metadata.Byte(state));
}
public boolean hasNoBasePlate() {
return noBasePlate;
return (getStateMeta() & 0x08) != 0;
}
public void setNoBasePlate(boolean noBasePlate) {
this.noBasePlate = noBasePlate;
sendMetadataIndex(14);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x10, (byte) (noBasePlate ? 1 : 0), (byte) 3);
this.metadata.setIndex((byte) 14, Metadata.Byte(state));
}
public boolean hasMarker() {
return setMarker;
return (getStateMeta() & 0x10) != 0;
}
public void setMarker(boolean setMarker) {
this.setMarker = setMarker;
sendMetadataIndex(14);
final byte state = BitmaskUtil.changeBit(getStateMeta(), (byte) 0x20, (byte) (setMarker ? 1 : 0), (byte) 4);
this.metadata.setIndex((byte) 14, Metadata.Byte(state));
}
@NotNull
public Vector getHeadRotation() {
return headRotation;
return metadata.getIndex((byte) 15, new Vector(0, 0, 0));
}
public void setHeadRotation(Vector headRotation) {
this.headRotation = headRotation;
sendMetadataIndex(15);
public void setHeadRotation(@NotNull Vector headRotation) {
this.metadata.setIndex((byte) 15, Metadata.Rotation(headRotation));
}
@NotNull
public Vector getBodyRotation() {
return bodyRotation;
return metadata.getIndex((byte) 16, new Vector(0, 0, 0));
}
public void setBodyRotation(Vector bodyRotation) {
this.bodyRotation = bodyRotation;
sendMetadataIndex(16);
public void setBodyRotation(@NotNull Vector bodyRotation) {
this.metadata.setIndex((byte) 16, Metadata.Rotation(bodyRotation));
}
@NotNull
public Vector getLeftArmRotation() {
return leftArmRotation;
return metadata.getIndex((byte) 17, new Vector(-10, 0, -10));
}
public void setLeftArmRotation(Vector leftArmRotation) {
this.leftArmRotation = leftArmRotation;
sendMetadataIndex(17);
public void setLeftArmRotation(@NotNull Vector leftArmRotation) {
this.metadata.setIndex((byte) 17, Metadata.Rotation(leftArmRotation));
}
@NotNull
public Vector getRightArmRotation() {
return rightArmRotation;
return metadata.getIndex((byte) 18, new Vector(-15, 0, 10));
}
public void setRightArmRotation(Vector rightArmRotation) {
this.rightArmRotation = rightArmRotation;
sendMetadataIndex(18);
public void setRightArmRotation(@NotNull Vector rightArmRotation) {
this.metadata.setIndex((byte) 18, Metadata.Rotation(rightArmRotation));
}
@NotNull
public Vector getLeftLegRotation() {
return leftLegRotation;
return metadata.getIndex((byte) 19, new Vector(-1, 0, -1));
}
public void setLeftLegRotation(Vector leftLegRotation) {
this.leftLegRotation = leftLegRotation;
sendMetadataIndex(19);
public void setLeftLegRotation(@NotNull Vector leftLegRotation) {
this.metadata.setIndex((byte) 19, Metadata.Rotation(leftLegRotation));
}
@NotNull
public Vector getRightLegRotation() {
return rightLegRotation;
return metadata.getIndex((byte) 20, new Vector(1, 0, 1));
}
public void setRightLegRotation(Vector rightLegRotation) {
this.rightLegRotation = rightLegRotation;
sendMetadataIndex(20);
public void setRightLegRotation(@NotNull Vector rightLegRotation) {
this.metadata.setIndex((byte) 20, Metadata.Rotation(rightLegRotation));
}
private float getRotationX(Vector vector) {
return vector != null ? (float) vector.getX() : 0;
}
private float getRotationY(Vector vector) {
return vector != null ? (float) vector.getY() : 0;
}
private float getRotationZ(Vector vector) {
return vector != null ? (float) vector.getZ() : 0;
private byte getStateMeta() {
return metadata.getIndex((byte) 14, (byte) 0);
}
// Equipments

View File

@ -1,55 +1,26 @@
package net.minestom.server.entity.type.decoration;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Rotation;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
// FIXME: https://wiki.vg/Object_Data#Item_Frame_.28id_71.29
// "You have to set both Orientation and Yaw/Pitch accordingly, otherwise it will not work."
public class EntityItemFrame extends ObjectEntity {
private final ItemFrameOrientation orientation;
private ItemStack itemStack;
private Rotation rotation;
public EntityItemFrame(@NotNull Position spawnPosition, @NotNull ItemFrameOrientation orientation) {
super(EntityType.ITEM_FRAME, spawnPosition);
this.orientation = orientation;
this.rotation = Rotation.NONE;
setNoGravity(true);
setGravity(0f, 0f, 0f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
fillMetadataIndex(packet, 8);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
packet.writeByte(METADATA_SLOT);
packet.writeItemStack(itemStack == null ? ItemStack.getAirItem() : itemStack);
} else if (index == 8) {
packet.writeByte((byte) 8);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(rotation.ordinal());
}
}
@Override
public int getObjectData() {
return orientation.ordinal();
@ -60,8 +31,9 @@ public class EntityItemFrame extends ObjectEntity {
*
* @return the item stack in the frame
*/
@NotNull
public ItemStack getItemStack() {
return itemStack;
return metadata.getIndex((byte) 7, ItemStack.getAirItem());
}
/**
@ -69,9 +41,8 @@ public class EntityItemFrame extends ObjectEntity {
*
* @param itemStack the new item stack in the frame
*/
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack;
sendMetadataIndex(7);
public void setItemStack(@NotNull ItemStack itemStack) {
this.metadata.setIndex((byte) 7, Metadata.Slot(itemStack));
}
/**
@ -81,7 +52,8 @@ public class EntityItemFrame extends ObjectEntity {
*/
@NotNull
public Rotation getRotation() {
return rotation;
final int ordinal = metadata.getIndex((byte) 8, 0);
return Rotation.values()[ordinal];
}
/**
@ -90,8 +62,7 @@ public class EntityItemFrame extends ObjectEntity {
* @param rotation the new item rotation
*/
public void setRotation(@NotNull Rotation rotation) {
this.rotation = rotation;
sendMetadataIndex(8);
this.metadata.setIndex((byte) 8, Metadata.VarInt(rotation.ordinal()));
}
/**

View File

@ -2,12 +2,9 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityBlaze extends EntityCreature implements Monster {
@ -16,22 +13,9 @@ public class EntityBlaze extends EntityCreature implements Monster {
setBoundingBox(0.6f, 1.8f, 0.6f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BYTE);
packet.writeByte((byte) (isOnFire() ? 1 : 0));
}
public void setOnFire(boolean fire) {
super.setOnFire(fire);
this.metadata.setIndex((byte) 15, Metadata.Byte((byte) (fire ? 1 : 0)));
}
}

View File

@ -2,79 +2,42 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityCreeper extends EntityCreature implements Monster {
private CreeperState creeperState = CreeperState.IDLE;
private boolean charged;
private boolean ignited;
public EntityCreeper(Position spawnPosition) {
super(EntityType.CREEPER, spawnPosition);
setBoundingBox(0.6f, 1.7f, 0.6f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 16);
fillMetadataIndex(packet, 17);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(creeperState.getState());
} else if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(charged);
} else if (index == 17) {
packet.writeByte((byte) 17);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(ignited);
}
}
@NotNull
public CreeperState getCreeperState() {
return creeperState;
final int state = metadata.getIndex((byte) 15, -1);
return CreeperState.fromState(state);
}
public void setCreeperState(@NotNull CreeperState creeperState) {
this.creeperState = creeperState;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.VarInt(creeperState.getState()));
}
public boolean isCharged() {
return charged;
return metadata.getIndex((byte) 16, false);
}
public void setCharged(boolean charged) {
this.charged = charged;
sendMetadataIndex(16);
this.metadata.setIndex((byte) 16, Metadata.Boolean(charged));
}
public boolean isIgnited() {
return ignited;
return metadata.getIndex((byte) 17, false);
}
public void setIgnited(boolean ignited) {
this.ignited = ignited;
sendMetadataIndex(17);
this.metadata.setIndex((byte) 17, Metadata.Boolean(ignited));
}
public enum CreeperState {
@ -90,5 +53,14 @@ public class EntityCreeper extends EntityCreature implements Monster {
private int getState() {
return state;
}
private static CreeperState fromState(int state) {
if (state == -1) {
return IDLE;
} else if (state == 1) {
return FUSE;
}
throw new IllegalArgumentException("Weird thing happened");
}
}
}

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityGhast extends EntityCreature implements Monster {
private boolean attacking;
public EntityGhast(Position spawnPosition) {
super(EntityType.GHAST, spawnPosition);
setBoundingBox(4, 4, 4);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(attacking);
}
}
public boolean isAttacking() {
return attacking;
return metadata.getIndex((byte) 15, false);
}
public void setAttacking(boolean attacking) {
this.attacking = attacking;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.Boolean(attacking));
}
}

View File

@ -3,16 +3,13 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityGuardian extends EntityCreature implements Monster {
private boolean retractingSpikes;
private Entity target;
public EntityGuardian(Position spawnPosition) {
@ -20,36 +17,12 @@ public class EntityGuardian extends EntityCreature implements Monster {
setBoundingBox(0.85f, 0.85f, 0.85f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(retractingSpikes);
} else if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(target == null ? 0 : target.getEntityId());
}
}
public boolean isRetractingSpikes() {
return retractingSpikes;
return metadata.getIndex((byte) 15, false);
}
public void setRetractingSpikes(boolean retractingSpikes) {
this.retractingSpikes = retractingSpikes;
this.metadata.setIndex((byte) 15, Metadata.Boolean(retractingSpikes));
}
public Entity getTarget() {
@ -58,5 +31,6 @@ public class EntityGuardian extends EntityCreature implements Monster {
public void setTarget(@NotNull Entity target) {
this.target = target;
this.metadata.setIndex((byte) 16, Metadata.VarInt(target.getEntityId()));
}
}

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityPhantom extends EntityCreature implements Monster {
private int size;
public EntityPhantom(Position spawnPosition) {
super(EntityType.PHANTOM, spawnPosition);
setBoundingBox(0.9f, 0.5f, 0.9f); // TODO change based on size
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(size);
}
}
public int getSize() {
return size;
return metadata.getIndex((byte) 17, 0);
}
public void setSize(int size) {
this.size = size;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.VarInt(size));
}
}

View File

@ -2,49 +2,24 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntitySlime extends EntityCreature implements Monster {
private int size;
public EntitySlime(Position spawnPosition) {
super(EntityType.SLIME, spawnPosition);
setSize(1);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(size);
}
}
public int getSize() {
return size;
return metadata.getIndex((byte) 15, 1);
}
public void setSize(int size) {
this.size = size;
final float boxSize = 0.51000005f * size;
setBoundingBox(boxSize, boxSize, boxSize);
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.VarInt(size));
}
}

View File

@ -2,48 +2,24 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntitySpider extends EntityCreature implements Monster {
private boolean climbing;
public EntitySpider(Position spawnPosition) {
super(EntityType.SPIDER, spawnPosition);
setBoundingBox(1.4f, 0.9f, 1.4f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(climbing);
}
}
/**
* Gets if the spider is climbing.
*
* @return true if the spider is climbing, false otherwise
*/
public boolean isClimbing() {
return climbing;
return metadata.getIndex((byte) 15, false);
}
/**
@ -52,7 +28,6 @@ public class EntitySpider extends EntityCreature implements Monster {
* @param climbing true to make the spider climbs, false otherwise
*/
public void setClimbing(boolean climbing) {
this.climbing = climbing;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.Boolean(climbing));
}
}

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityWitch extends EntityCreature implements Monster {
private boolean drinkingPotion;
public EntityWitch(Position spawnPosition) {
super(EntityType.WITCH, spawnPosition);
setBoundingBox(0.6f, 1.95f, 0.6f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(drinkingPotion);
}
}
public boolean isDrinkingPotion() {
return drinkingPotion;
return metadata.getIndex((byte) 16, false);
}
public void setDrinkingPotion(boolean drinkingPotion) {
this.drinkingPotion = drinkingPotion;
sendMetadataIndex(16);
this.metadata.setIndex((byte) 16, Metadata.Boolean(drinkingPotion));
}
}

View File

@ -2,63 +2,31 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityZombie extends EntityCreature implements Monster {
private boolean baby;
private boolean becomingDrowned;
public EntityZombie(Position spawnPosition) {
super(EntityType.ZOMBIE, spawnPosition);
setBoundingBox(0.6f, 1.95f, 0.6f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 17);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(baby);
} else if (index == 17) {
packet.writeByte((byte) 17);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(becomingDrowned);
}
}
public boolean isBaby() {
return baby;
return metadata.getIndex((byte) 15, false);
}
public void setBaby(boolean baby) {
this.baby = baby;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.Boolean(baby));
}
public boolean isBecomingDrowned() {
return becomingDrowned;
return metadata.getIndex((byte) 17, false);
}
public void setBecomingDrowned(boolean becomingDrowned) {
this.becomingDrowned = becomingDrowned;
sendMetadataIndex(17);
this.metadata.setIndex((byte) 17, Metadata.Boolean(becomingDrowned));
}
@Override

View File

@ -2,54 +2,24 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityZombifiedPiglin extends EntityCreature implements Monster {
private boolean baby;
private boolean becomingDrowned;
public EntityZombifiedPiglin(Position spawnPosition) {
super(EntityType.ZOMBIFIED_PIGLIN, spawnPosition);
setBoundingBox(0.6f, 1.95f, 0.6f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 17);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(baby);
} else if (index == 17) {
packet.writeByte((byte) 17);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(becomingDrowned);
}
}
/**
* Gets if the pig zombie is a baby.
*
* @return true if it is a baby, false otherwise
*/
public boolean isBaby() {
return baby;
return metadata.getIndex((byte) 15, false);
}
/**
@ -58,17 +28,15 @@ public class EntityZombifiedPiglin extends EntityCreature implements Monster {
* @param baby true to make it a baby, false otherwise
*/
public void setBaby(boolean baby) {
this.baby = baby;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.Boolean(baby));
}
public boolean isBecomingDrowned() {
return becomingDrowned;
return metadata.getIndex((byte) 17, false);
}
public void setBecomingDrowned(boolean becomingDrowned) {
this.becomingDrowned = becomingDrowned;
sendMetadataIndex(17);
this.metadata.setIndex((byte) 17, Metadata.Boolean(becomingDrowned));
}
@Override

View File

@ -5,7 +5,6 @@ import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.particle.Particle;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
@ -27,7 +26,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
});
}
@NotNull
/*@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
@ -37,9 +36,9 @@ public class EntityAreaEffectCloud extends ObjectEntity {
fillMetadataIndex(packet, 9);
fillMetadataIndex(packet, 10);
};
}
}*/
@Override
/*@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
@ -60,7 +59,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
packet.writeVarInt(particle.getId());
particleDataConsumer.accept(packet);
}
}
}*/
@Override
public int getObjectData() {
@ -74,7 +73,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
public void setRadius(float radius) {
this.radius = radius;
setBoundingBox(2 * radius, 0.5f, 2 * radius);
sendMetadataIndex(7);
//sendMetadataIndex(7);
}
public int getColor() {
@ -83,7 +82,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
public void setColor(int color) {
this.color = color;
sendMetadataIndex(8);
//sendMetadataIndex(8);
}
public boolean isIgnoreRadius() {
@ -92,7 +91,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
public void setIgnoreRadius(boolean ignoreRadius) {
this.ignoreRadius = ignoreRadius;
sendMetadataIndex(9);
//sendMetadataIndex(9);
}
public Particle getParticle() {
@ -101,7 +100,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
public void setParticle(Particle particle) {
this.particle = particle;
sendMetadataIndex(10);
//sendMetadataIndex(10);
}
public Consumer<BinaryWriter> getParticleDataConsumer() {

View File

@ -1,72 +1,36 @@
package net.minestom.server.entity.type.other;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
public class EntityEndCrystal extends ObjectEntity {
private BlockPosition beamTarget;
private boolean showBottom;
public EntityEndCrystal(@NotNull Position spawnPosition) {
super(EntityType.END_CRYSTAL, spawnPosition);
setBoundingBox(2f, 2f, 2f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
fillMetadataIndex(packet, 8);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
final boolean hasTarget = beamTarget != null;
packet.writeByte((byte) 7);
packet.writeByte(METADATA_OPTPOSITION);
packet.writeBoolean(hasTarget);
if (hasTarget) {
packet.writeBlockPosition(beamTarget);
}
} else if (index == 8) {
packet.writeByte((byte) 8);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(showBottom);
}
}
@Nullable
public BlockPosition getBeamTarget() {
return beamTarget;
return metadata.getIndex((byte) 7, null);
}
public void setBeamTarget(@Nullable BlockPosition beamTarget) {
this.beamTarget = beamTarget;
sendMetadataIndex(7);
this.metadata.setIndex((byte) 7, Metadata.OptPosition(beamTarget));
}
public boolean showBottom() {
return showBottom;
return metadata.getIndex((byte) 8, true);
}
public void setShowBottom(boolean showBottom) {
this.showBottom = showBottom;
sendMetadataIndex(8);
this.metadata.setIndex((byte) 8, Metadata.Boolean(showBottom));
}
@Override

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.other;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Constructable;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityIronGolem extends EntityCreature implements Constructable {
private boolean playerCreated;
public EntityIronGolem(Position spawnPosition) {
super(EntityType.IRON_GOLEM, spawnPosition);
setBoundingBox(1.4f, 2.7f, 1.4f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BYTE);
packet.writeByte((byte) (playerCreated ? 1 : 0));
}
}
public boolean isPlayerCreated() {
return playerCreated;
return metadata.getIndex((byte) 15, 0) == 0x01;
}
public void setPlayerCreated(boolean playerCreated) {
this.playerCreated = playerCreated;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.Byte((byte) (playerCreated ? 0x01 : 0x00)));
}
}

View File

@ -2,47 +2,22 @@ package net.minestom.server.entity.type.other;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.type.Constructable;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntitySnowman extends EntityCreature implements Constructable {
private boolean pumpkinHat;
public EntitySnowman(Position spawnPosition) {
super(EntityType.SNOW_GOLEM, spawnPosition);
setBoundingBox(0.7f, 1.9f, 0.7f);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BYTE);
packet.writeByte((byte) (pumpkinHat ? 0x10 : 0x00));
}
}
public boolean hasPumpkinHat() {
return pumpkinHat;
return metadata.getIndex((byte) 15, (byte) 0x00) == 0x10;
}
public void setPumpkinHat(boolean pumpkinHat) {
this.pumpkinHat = pumpkinHat;
sendMetadataIndex(15);
this.metadata.setIndex((byte) 15, Metadata.Byte((byte) (pumpkinHat ? 0x10 : 0x00)));
}
}

View File

@ -1,43 +1,19 @@
package net.minestom.server.entity.type.projectile;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.type.Projectile;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityEyeOfEnder extends ObjectEntity implements Projectile {
private ItemStack itemStack;
public EntityEyeOfEnder(Position spawnPosition) {
super(EntityType.EYE_OF_ENDER, spawnPosition);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
packet.writeByte(METADATA_SLOT);
packet.writeItemStack(itemStack);
}
}
/**
* Gets the eye of ender item.
@ -45,7 +21,7 @@ public class EntityEyeOfEnder extends ObjectEntity implements Projectile {
* @return the item
*/
public ItemStack getItemStack() {
return itemStack;
return metadata.getIndex((byte) 7, ItemStack.getAirItem());
}
/**
@ -56,8 +32,7 @@ public class EntityEyeOfEnder extends ObjectEntity implements Projectile {
* @param itemStack the new item stack
*/
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack;
sendMetadataIndex(7);
this.metadata.setIndex((byte) 7, Metadata.Slot(itemStack));
}
@Override

View File

@ -1,55 +1,32 @@
package net.minestom.server.entity.type.projectile;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.type.Projectile;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityPotion extends ObjectEntity implements Projectile {
private ItemStack potion;
public EntityPotion(Position spawnPosition, ItemStack potion) {
public EntityPotion(Position spawnPosition, @NotNull ItemStack potion) {
super(EntityType.POTION, spawnPosition);
setBoundingBox(0.25f, 0.25f, 0.25f);
setPotion(potion);
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
packet.writeByte(METADATA_SLOT);
packet.writeItemStack(potion);
}
}
@Override
public int getObjectData() {
return 0;
}
@NotNull
public ItemStack getPotion() {
return potion;
return metadata.getIndex((byte) 7, ItemStack.getAirItem());
}
public void setPotion(ItemStack potion) {
this.potion = potion;
sendMetadataIndex(15);
public void setPotion(@NotNull ItemStack potion) {
this.metadata.setIndex((byte) 7, Metadata.Slot(potion));
}
}

View File

@ -1,25 +1,17 @@
package net.minestom.server.entity.type.vehicle;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Metadata;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.type.Vehicle;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EntityBoat extends ObjectEntity implements Vehicle {
private BoatType boatType;
private boolean leftPaddleTurning;
private boolean rightPaddleTurning;
public EntityBoat(Position spawnPosition) {
super(EntityType.BOAT, spawnPosition);
setBoundingBox(1.375f, 0.5625f, 1.375f);
this.boatType = BoatType.OAK;
}
@Override
@ -27,44 +19,15 @@ public class EntityBoat extends ObjectEntity implements Vehicle {
return 0;
}
@NotNull
@Override
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 10);
fillMetadataIndex(packet, 11);
fillMetadataIndex(packet, 12);
// TODO all remaining metadata
};
}
@Override
protected void fillMetadataIndex(@NotNull BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 10) {
packet.writeByte((byte) 10);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(boatType.ordinal());
} else if (index == 11) {
packet.writeByte((byte) 11);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(leftPaddleTurning);
} else if (index == 12) {
packet.writeByte((byte) 12);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(rightPaddleTurning);
}
}
/**
* Gets the boat type.
*
* @return the boat type
*/
@NotNull
public BoatType getBoatType() {
return boatType;
final int ordinal = metadata.getIndex((byte) 10, 0);
return BoatType.values()[ordinal];
}
/**
@ -72,17 +35,14 @@ public class EntityBoat extends ObjectEntity implements Vehicle {
*
* @param boatType the new boat type
*/
public void setBoatType(BoatType boatType) {
Check.notNull(boatType, "The boat type cannot be null");
this.boatType = boatType;
sendMetadataIndex(10);
public void setBoatType(@NotNull BoatType boatType) {
this.metadata.setIndex((byte) 10, Metadata.VarInt(boatType.ordinal()));
}
public void refreshPaddle(boolean left, boolean right) {
this.leftPaddleTurning = left;
this.rightPaddleTurning = right;
sendMetadataIndex(11);
sendMetadataIndex(12);
this.metadata.setIndex((byte) 11, Metadata.Boolean(left));
this.metadata.setIndex((byte) 12, Metadata.Boolean(right));
}
public enum BoatType {

View File

@ -1,22 +1,28 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.entity.Metadata;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import java.util.Collection;
public class EntityMetaDataPacket implements ServerPacket {
public int entityId;
public Consumer<BinaryWriter> consumer;
public Collection<Metadata.Entry<?>> entries;
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeVarInt(entityId);
writer.write(consumer);
writer.writeByte((byte) 0xFF);
// Write all the fields
for (Metadata.Entry<?> entry : entries) {
entry.write(writer);
}
writer.writeByte((byte) 0xFF); // End
}
@Override

View File

@ -0,0 +1,9 @@
package net.minestom.server.utils.binary;
public final class BitmaskUtil {
public static byte changeBit(byte value, byte mask, byte replacement, byte shift) {
return (byte) (value & ~mask | (replacement << shift));
}
}