Added EntityArmorStand & Hologram

This commit is contained in:
Felix Cravic 2020-05-26 00:07:35 +02:00
parent 9df6b19f1d
commit fc751acb75
8 changed files with 525 additions and 33 deletions

View File

@ -7,10 +7,8 @@ import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.entity.*;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.fakeplayer.FakePlayer;
import net.minestom.server.entity.fakeplayer.FakePlayerController;
import net.minestom.server.entity.hologram.Hologram;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.ItemUpdateStateEvent;
import net.minestom.server.event.item.PickupItemEvent;
@ -152,13 +150,15 @@ public class PlayerInit {
//ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
//chickenCreature.setInstance(player.getInstance());
FakePlayer fakePlayer = new FakePlayer(UUID.randomUUID(), "test", true);
/*FakePlayer fakePlayer = new FakePlayer(UUID.randomUUID(), "test", true);
fakePlayer.addEventCallback(EntityDeathEvent.class, e -> {
fakePlayer.getController().respawn();
});
fakePlayer.setArrowCount(25);
FakePlayerController controller = fakePlayer.getController();
controller.sendChatMessage("I am a bot!");
controller.sendChatMessage("I am a bot!");*/
Hologram hologram = new Hologram(player.getInstance(), player.getPosition(), "Hey guy");
});

View File

@ -1,14 +1,7 @@
package fr.themode.demo.commands;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandProcessor;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.fakeplayer.FakePlayer;
import net.minestom.server.entity.fakeplayer.FakePlayerController;
import net.minestom.server.timer.TaskRunnable;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
public class SimpleCommand implements CommandProcessor {
@Override
@ -24,7 +17,7 @@ public class SimpleCommand implements CommandProcessor {
@Override
public boolean process(Player player, String command, String[] args) {
for (Player p : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
/*for (Player p : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
if (!(p instanceof FakePlayer))
continue;
FakePlayer fakePlayer = (FakePlayer) p;
@ -37,11 +30,13 @@ public class SimpleCommand implements CommandProcessor {
public void run() {
controller.stopDigging(blockPosition);
}
}, new UpdateOption(15, TimeUnit.TICK));
}
}, new UpdateOption(7, TimeUnit.TICK));
//System.gc();
//player.sendMessage("Garbage collector called");
break;
}*/
System.gc();
player.sendMessage("Garbage collector called");
return true;
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.entity;
import net.minestom.server.MinecraftServer;
import net.minestom.server.Viewable;
import net.minestom.server.chat.Chat;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.data.Data;
@ -46,6 +47,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected static final byte METADATA_OPTCHAT = 5;
protected static final byte METADATA_SLOT = 6;
protected static final byte METADATA_BOOLEAN = 7;
protected static final byte METADATA_ROTATION = 8;
protected static final byte METADATA_POSITION = 9;
protected static final byte METADATA_POSE = 18;
protected Instance instance;
@ -90,7 +93,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected boolean glowing;
protected boolean usingElytra;
protected int air = 300;
protected String customName = "";
protected String customName;
protected boolean customNameVisible;
protected boolean silent;
protected boolean noGravity;
@ -590,6 +593,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendMetadataIndex(0);
}
public boolean isInvisible() {
return invisible;
}
public void setInvisible(boolean invisible) {
this.invisible = invisible;
sendMetadataIndex(0);
}
public void setGlowing(boolean glowing) {
this.glowing = glowing;
sendMetadataIndex(0);
@ -602,6 +614,33 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return glowing;
}
public String getCustomName() {
return customName;
}
public void setCustomName(String customName) {
this.customName = customName;
sendMetadataIndex(2);
}
public boolean isCustomNameVisible() {
return customNameVisible;
}
public void setCustomNameVisible(boolean customNameVisible) {
this.customNameVisible = customNameVisible;
sendMetadataIndex(3);
}
public boolean isSilent() {
return silent;
}
public void setSilent(boolean silent) {
this.silent = silent;
sendMetadataIndex(4);
}
/**
* @param noGravity should the entity ignore gravity
*/
@ -831,6 +870,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return packet -> {
fillMetadataIndex(packet, 0);
fillMetadataIndex(packet, 1);
fillMetadataIndex(packet, 2);
fillMetadataIndex(packet, 3);
fillMetadataIndex(packet, 4);
fillMetadataIndex(packet, 5);
fillMetadataIndex(packet, 6);
};
@ -871,6 +913,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
case 2:
fillCustomNameMetaData(packet);
break;
case 3:
fillCustomNameVisibleMetaData(packet);
break;
case 4:
fillSilentMetaData(packet);
break;
case 5:
fillNoGravityMetaData(packet);
break;
@ -910,9 +958,26 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}
private void fillCustomNameMetaData(PacketWriter packet) {
boolean hasCustomName = customName != null && !customName.isEmpty();
packet.writeByte((byte) 2);
packet.writeByte(METADATA_CHAT);
packet.writeSizedString(customName);
packet.writeByte(METADATA_OPTCHAT);
packet.writeBoolean(hasCustomName);
if (hasCustomName) {
packet.writeSizedString(Chat.toJsonString(Chat.fromLegacyText(customName)));
}
}
private void fillCustomNameVisibleMetaData(PacketWriter packet) {
packet.writeByte((byte) 3);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(customNameVisible);
}
private void fillSilentMetaData(PacketWriter packet) {
packet.writeByte((byte) 4);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(silent);
}
private void fillNoGravityMetaData(PacketWriter packet) {

View File

@ -39,9 +39,4 @@ public abstract class ObjectEntity extends Entity {
return super.addViewer(player); // Add player to viewers list
}
@Override
public boolean removeViewer(Player player) {
return super.removeViewer(player);
}
}

View File

@ -0,0 +1,74 @@
package net.minestom.server.entity.hologram;
import net.minestom.server.entity.type.EntityArmorStand;
import net.minestom.server.instance.Instance;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.validate.Check;
public class Hologram {
private static final float OFFSET_Y = -0.9875f;
private HologramEntity entity;
private Position position;
private String text;
private boolean removed;
public Hologram(Instance instance, Position spawnPosition, String text, boolean autoViewable) {
this.entity = new HologramEntity(spawnPosition.clone().add(0, OFFSET_Y, 0));
this.entity.setInstance(instance);
this.entity.setAutoViewable(autoViewable);
this.position = spawnPosition;
setText(text);
}
public Hologram(Instance instance, Position spawnPosition, String text) {
this(instance, spawnPosition, text, true);
}
public Position getPosition() {
return position;
}
public void setPosition(Position position) {
position = position.add(0, OFFSET_Y, 0);
this.position = position;
this.entity.teleport(position);
}
public String getText() {
return text;
}
public void setText(String text) {
checkRemoved();
this.text = text;
this.entity.setCustomName(text);
}
public void remove() {
this.removed = true;
this.entity.remove();
}
private void checkRemoved() {
Check.stateCondition(removed, "You cannot interact with a removed Hologram");
}
private class HologramEntity extends EntityArmorStand {
public HologramEntity(Position spawnPosition) {
super(spawnPosition);
setSmall(true);
setNoGravity(true);
setCustomName("");
setCustomNameVisible(true);
setInvisible(true);
}
}
}

View File

@ -0,0 +1,361 @@
package net.minestom.server.entity.type;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter;
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.item.ItemStackUtils;
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;
private ItemStack helmet;
private ItemStack chestplate;
private ItemStack leggings;
private ItemStack boots;
public EntityArmorStand(Position spawnPosition) {
super(EntityType.ARMOR_STAND, spawnPosition);
// Refresh BoundingBox
setSmall(false);
setHeadRotation(new Vector(0, 0, 0));
setBodyRotation(new Vector(0, 0, 0));
setLeftArmRotation(new Vector(-10f, 0, -10f));
setRightArmRotation(new Vector(-15f, 0, -10f));
setLeftLegRotation(new Vector(-1f, 0, -1f));
setRightLegRotation(new Vector(1, 0, 1));
this.mainHandItem = ItemStack.getAirItem();
this.offHandItem = ItemStack.getAirItem();
this.helmet = ItemStack.getAirItem();
this.chestplate = ItemStack.getAirItem();
this.leggings = ItemStack.getAirItem();
this.boots = ItemStack.getAirItem();
}
@Override
public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
syncEquipments();
return result;
}
@Override
public int getObjectData() {
return 0;
}
@Override
public void update() {
}
@Override
public void spawn() {
}
@Override
public Consumer<PacketWriter> 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(PacketWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 14) {
packet.writeByte((byte) 14);
packet.writeByte(METADATA_BYTE);
byte dataValue = 0;
if (isSmall())
dataValue += 1;
if (hasArms)
dataValue += 2;
if (hasNoBasePlate())
dataValue += 4;
if (hasMarker())
dataValue += 8;
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));
}
}
@Override
public ItemStack getItemInMainHand() {
return mainHandItem;
}
@Override
public void setItemInMainHand(ItemStack itemStack) {
this.mainHandItem = ItemStackUtils.notNull(itemStack);
syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND);
}
@Override
public ItemStack getItemInOffHand() {
return offHandItem;
}
@Override
public void setItemInOffHand(ItemStack itemStack) {
this.offHandItem = ItemStackUtils.notNull(itemStack);
syncEquipment(EntityEquipmentPacket.Slot.OFF_HAND);
}
@Override
public ItemStack getHelmet() {
return helmet;
}
@Override
public void setHelmet(ItemStack itemStack) {
this.helmet = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.HELMET);
syncEquipment(EntityEquipmentPacket.Slot.HELMET);
}
@Override
public ItemStack getChestplate() {
return chestplate;
}
@Override
public void setChestplate(ItemStack itemStack) {
this.chestplate = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.CHESTPLATE);
syncEquipment(EntityEquipmentPacket.Slot.CHESTPLATE);
}
@Override
public ItemStack getLeggings() {
return leggings;
}
@Override
public void setLeggings(ItemStack itemStack) {
this.leggings = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.LEGGINGS);
syncEquipment(EntityEquipmentPacket.Slot.LEGGINGS);
}
@Override
public ItemStack getBoots() {
return boots;
}
@Override
public void setBoots(ItemStack itemStack) {
this.boots = getEquipmentItem(itemStack, ArmorEquipEvent.ArmorSlot.BOOTS);
syncEquipment(EntityEquipmentPacket.Slot.BOOTS);
}
public boolean isSmall() {
return small;
}
public void setSmall(boolean small) {
this.small = small;
sendMetadataIndex(14);
if (small) {
setBoundingBox(0.25f, 0.9875f, 0.25f);
} else {
setBoundingBox(0.5f, 1.975f, 0.5f);
}
}
public boolean hasArms() {
return hasArms;
}
public void setHasArms(boolean hasArms) {
this.hasArms = hasArms;
sendMetadataIndex(14);
}
public boolean hasNoBasePlate() {
return noBasePlate;
}
public void setNoBasePlate(boolean noBasePlate) {
this.noBasePlate = noBasePlate;
sendMetadataIndex(14);
}
public boolean hasMarker() {
return setMarker;
}
public void setMarker(boolean setMarker) {
this.setMarker = setMarker;
sendMetadataIndex(14);
}
public Vector getHeadRotation() {
return headRotation;
}
public void setHeadRotation(Vector headRotation) {
this.headRotation = headRotation;
sendMetadataIndex(15);
}
public Vector getBodyRotation() {
return bodyRotation;
}
public void setBodyRotation(Vector bodyRotation) {
this.bodyRotation = bodyRotation;
sendMetadataIndex(16);
}
public Vector getLeftArmRotation() {
return leftArmRotation;
}
public void setLeftArmRotation(Vector leftArmRotation) {
this.leftArmRotation = leftArmRotation;
sendMetadataIndex(17);
}
public Vector getRightArmRotation() {
return rightArmRotation;
}
public void setRightArmRotation(Vector rightArmRotation) {
this.rightArmRotation = rightArmRotation;
sendMetadataIndex(18);
}
public Vector getLeftLegRotation() {
return leftLegRotation;
}
public void setLeftLegRotation(Vector leftLegRotation) {
this.leftLegRotation = leftLegRotation;
sendMetadataIndex(19);
}
public Vector getRightLegRotation() {
return rightLegRotation;
}
public void setRightLegRotation(Vector rightLegRotation) {
this.rightLegRotation = rightLegRotation;
sendMetadataIndex(20);
}
private float getRotationX(Vector vector) {
return vector != null ? vector.getX() : 0;
}
private float getRotationY(Vector vector) {
return vector != null ? vector.getY() : 0;
}
private float getRotationZ(Vector vector) {
return vector != null ? vector.getZ() : 0;
}
// Equipments
public void syncEquipments() {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
syncEquipment(slot);
}
}
protected void syncEquipment(EntityEquipmentPacket.Slot slot) {
EntityEquipmentPacket entityEquipmentPacket = getEquipmentPacket(slot);
if (entityEquipmentPacket == null)
return;
sendPacketToViewers(entityEquipmentPacket);
}
private ItemStack getEquipmentItem(ItemStack itemStack, ArmorEquipEvent.ArmorSlot armorSlot) {
itemStack = ItemStackUtils.notNull(itemStack);
ArmorEquipEvent armorEquipEvent = new ArmorEquipEvent(this, itemStack, armorSlot);
callEvent(ArmorEquipEvent.class, armorEquipEvent);
return armorEquipEvent.getArmorItem();
}
protected EntityEquipmentPacket getEquipmentPacket(EntityEquipmentPacket.Slot slot) {
ItemStack itemStack = getEquipment(slot);
EntityEquipmentPacket equipmentPacket = new EntityEquipmentPacket();
equipmentPacket.entityId = getEntityId();
equipmentPacket.slot = slot;
equipmentPacket.itemStack = itemStack;
return equipmentPacket;
}
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.event.item;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Entity;
import net.minestom.server.event.Event;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.item.ItemStackUtils;
public class ArmorEquipEvent extends Event {
private LivingEntity livingEntity;
private Entity entity;
private ItemStack armorItem;
private ArmorSlot armorSlot;
public ArmorEquipEvent(LivingEntity livingEntity, ItemStack armorItem, ArmorSlot armorSlot) {
this.livingEntity = livingEntity;
public ArmorEquipEvent(Entity entity, ItemStack armorItem, ArmorSlot armorSlot) {
this.entity = entity;
this.armorItem = armorItem;
this.armorSlot = armorSlot;
}
public LivingEntity getEntity() {
return livingEntity;
public Entity getEntity() {
return entity;
}
public ItemStack getArmorItem() {

View File

@ -283,8 +283,10 @@ public class InstanceContainer extends Instance {
unloadChunkPacket.chunkZ = chunkZ;
chunk.sendPacketToViewers(unloadChunkPacket);
for (Player viewer : chunk.getViewers()) {
chunk.removeViewer(viewer);
if (!ChunkUtils.isChunkUnloaded(this, chunk)) {
for (Player viewer : chunk.getViewers()) {
chunk.removeViewer(viewer);
}
}
this.chunks.remove(index);