package de.robotricker.transportpipes.protocol; import com.comphenix.packetwrapper.WrapperPlayServerEntityDestroy; import com.comphenix.packetwrapper.WrapperPlayServerEntityEquipment; import com.comphenix.packetwrapper.WrapperPlayServerEntityMetadata; import com.comphenix.packetwrapper.WrapperPlayServerRelEntityMove; import com.comphenix.packetwrapper.WrapperPlayServerSpawnEntity; import com.comphenix.protocol.wrappers.EnumWrappers; import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.WrappedWatchableObject; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import javax.inject.Inject; import de.robotricker.transportpipes.TransportPipes; import de.robotricker.transportpipes.duct.pipe.items.PipeItem; import de.robotricker.transportpipes.location.BlockLocation; import de.robotricker.transportpipes.location.RelativeLocation; import de.robotricker.transportpipes.utils.NMSUtils; public class ProtocolService { private WrappedDataWatcher.Serializer INT_SERIALIZER; private WrappedDataWatcher.Serializer BYTE_SERIALIZER; private WrappedDataWatcher.Serializer VECTOR_SERIALIZER; private WrappedDataWatcher.Serializer BOOLEAN_SERIALIZER; private TransportPipes plugin; @Inject public ProtocolService(TransportPipes plugin) { INT_SERIALIZER = WrappedDataWatcher.Registry.get(Integer.class); BYTE_SERIALIZER = WrappedDataWatcher.Registry.get(Byte.class); VECTOR_SERIALIZER = WrappedDataWatcher.Registry.get(NMSUtils.getVector3fClass()); BOOLEAN_SERIALIZER = WrappedDataWatcher.Registry.get(Boolean.class); this.plugin = plugin; } private int nextEntityID = 99999; private UUID uuid = UUID.randomUUID(); public void sendPipeItem(Player p, PipeItem item) { sendASD(p, item.getBlockLoc(), item.getRelativeLocation().clone().add(-0.5d, -0.5d, -0.5d), item.getAsd()); } public void updatePipeItem(Player p, PipeItem item) { try { WrapperPlayServerRelEntityMove moveWrapper = new WrapperPlayServerRelEntityMove(); moveWrapper.setEntityID(item.getAsd().getEntityID()); moveWrapper.setDx((int) ((item.getRelativeLocationDifference().getDoubleX() * 32d) * 128)); moveWrapper.setDy((int) ((item.getRelativeLocationDifference().getDoubleY() * 32d) * 128)); moveWrapper.setDz((int) ((item.getRelativeLocationDifference().getDoubleZ() * 32d) * 128)); moveWrapper.setOnGround(true); moveWrapper.sendPacket(p); } catch (Exception e) { e.printStackTrace(); } } public void removePipeItem(final Player p, PipeItem item) { removeASD(p, Collections.singletonList(item.getAsd())); } public void sendASD(Player p, BlockLocation blockLoc, RelativeLocation offset, ArmorStandData asd) { int serverVersion = NMSUtils.gatherProtocolVersion(); try { if (asd.getEntityID() == -1) { asd.setEntityID(++nextEntityID); } // SPAWN ENTITY WrapperPlayServerSpawnEntity spawnWrapper = new WrapperPlayServerSpawnEntity(); spawnWrapper.setEntityID(asd.getEntityID()); spawnWrapper.setUniqueId(uuid); spawnWrapper.setType(78); // object id: ArmorStand (http://wiki.vg/Protocol#Spawn_Object) spawnWrapper.setX(blockLoc.getX() + asd.getRelLoc().getDoubleX() + offset.getDoubleX()); spawnWrapper.setY(blockLoc.getY() + asd.getRelLoc().getDoubleY() + offset.getDoubleY()); spawnWrapper.setZ(blockLoc.getZ() + asd.getRelLoc().getDoubleZ() + offset.getDoubleZ()); spawnWrapper.setOptionalSpeedX(0); spawnWrapper.setOptionalSpeedY(0); spawnWrapper.setOptionalSpeedZ(0); spawnWrapper.setPitch(0); double x = asd.getDirection().getX(); double z = asd.getDirection().getZ(); double theta = Math.atan2(-x, z); double yaw = Math.toDegrees((theta + 2 * Math.PI) % (2 * Math.PI)); spawnWrapper.setYaw((float) yaw); spawnWrapper.setObjectData(0); // without random velocity spawnWrapper.sendPacket(p); // ENTITYMETADATA WrapperPlayServerEntityMetadata metaWrapper = new WrapperPlayServerEntityMetadata(); metaWrapper.setEntityID(asd.getEntityID()); byte bitMask = (byte) ((asd.isSmall() ? 0x01 : 0x00) | 0x04 | 0x08 | 0x10); // (small) + hasArms + noBasePlate + Marker List<WrappedWatchableObject> metaList = new ArrayList<>(); metaList.add(new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, BOOLEAN_SERIALIZER), false));// customname // invisible metaList.add(new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(serverVersion <= 110 ? 10 : 11, BYTE_SERIALIZER), bitMask));// armorstand // specific // data... metaList.add(new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, BYTE_SERIALIZER), (byte) (0x20)));// invisible // (entity // specific // data) metaList.add(new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(serverVersion <= 110 ? 11 : 12, VECTOR_SERIALIZER), NMSUtils.createVector3f((float) asd.getHeadRotation().getX(), (float) asd.getHeadRotation().getY(), (float) asd.getHeadRotation().getZ())));// head rot metaList.add(new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(serverVersion <= 110 ? 14 : 15, VECTOR_SERIALIZER), NMSUtils.createVector3f((float) asd.getArmRotation().getX(), (float) asd.getArmRotation().getY(), (float) asd.getArmRotation().getZ())));// right arm rot metaWrapper.setMetadata(metaList); metaWrapper.sendPacket(p); // ENTITYEQUIPMENT final WrapperPlayServerEntityEquipment equipmentWrapper = new WrapperPlayServerEntityEquipment(); equipmentWrapper.setEntityID(asd.getEntityID()); // HAND ITEM if (asd.getHandItem() != null) { equipmentWrapper.setSlot(EnumWrappers.ItemSlot.MAINHAND); equipmentWrapper.setItem(asd.getHandItem()); } // HEAD ITEM if (asd.getHeadItem() != null) { equipmentWrapper.setSlot(EnumWrappers.ItemSlot.HEAD); equipmentWrapper.setItem(asd.getHeadItem()); } // ENTITYMETADATA 2 (fire) final WrapperPlayServerEntityMetadata meta2Wrapper = new WrapperPlayServerEntityMetadata(); meta2Wrapper.setEntityID(asd.getEntityID()); List<WrappedWatchableObject> meta2List = new ArrayList<>(); meta2List.add(new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, BYTE_SERIALIZER), (byte) (0x01 | 0x20)));// on // fire meta2Wrapper.setMetadata(meta2List); plugin.runTaskAsync(() -> { try { meta2Wrapper.sendPacket(p); equipmentWrapper.sendPacket(p); } catch (Exception e) { e.printStackTrace(); } }, 1); } catch (Exception e) { e.printStackTrace(); } } public void sendASD(Player p, BlockLocation blockLoc, List<ArmorStandData> armorStandData) { for (ArmorStandData asd : armorStandData) { sendASD(p, blockLoc, new RelativeLocation(0d, 0d, 0d), asd); } } public void removeASD(Player p, List<ArmorStandData> armorStandData) { WrapperPlayServerEntityDestroy destroyWrapper = new WrapperPlayServerEntityDestroy(); int[] ids = armorStandData.stream().mapToInt(ArmorStandData::getEntityID).toArray(); destroyWrapper.setEntityIds(ids); destroyWrapper.sendPacket(p); } }