diff --git a/NMS/pom.xml b/NMS/pom.xml index adf015d8..922108f0 100644 --- a/NMS/pom.xml +++ b/NMS/pom.xml @@ -28,6 +28,7 @@ <module>v1_15_R1</module> <module>v1_16_R1</module> <module>v1_16_R2</module> + <module>v1_16_R3</module> </modules> -</project> \ No newline at end of file +</project> diff --git a/NMS/v1_16_R3/pom.xml b/NMS/v1_16_R3/pom.xml new file mode 100644 index 00000000..23afc8d4 --- /dev/null +++ b/NMS/v1_16_R3/pom.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.gmail.filoghost.holographicdisplays</groupId> + <artifactId>holographicdisplays-nms</artifactId> + <version>2.4.5-SNAPSHOT</version> + </parent> + + <artifactId>holographicdisplays-nms-v1_16_r3</artifactId> + <name>HolographicDisplays NMS v1_16_R3</name> + + <repositories> + <repository> + <id>nms-repo</id> + <url>https://repo.codemc.io/repository/nms/</url> + </repository> + </repositories> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>holographicdisplays-nms-interfaces</artifactId> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>holographicdisplays-utils</artifactId> + </dependency> + + <dependency> + <groupId>org.spigotmc</groupId> + <artifactId>spigot</artifactId> + <version>1.16.4-R0.1-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + </dependencies> + +</project> diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSArmorStand.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSArmorStand.java new file mode 100644 index 00000000..ffd6c879 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSArmorStand.java @@ -0,0 +1,96 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import java.util.Collection; + +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R3.CraftServer; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.util.EulerAngle; +import org.bukkit.util.Vector; + +public class CraftNMSArmorStand extends CraftArmorStand { + + public CraftNMSArmorStand(CraftServer server, EntityNMSArmorStand entity) { + super(server, entity); + } + + // Disallow all the bukkit methods. + + @Override + public void remove() { + // Cannot be removed, this is the most important to override. + } + + // Methods from ArmorStand class + @Override public void setArms(boolean arms) { } + @Override public void setBasePlate(boolean basePlate) { } + @Override public void setBodyPose(EulerAngle pose) { } + @Override public void setBoots(ItemStack item) { } + @Override public void setChestplate(ItemStack item) { } + @Override public void setHeadPose(EulerAngle pose) { } + @Override public void setHelmet(ItemStack item) { } + @Override public void setItemInHand(ItemStack item) { } + @Override public void setLeftArmPose(EulerAngle pose) { } + @Override public void setLeftLegPose(EulerAngle pose) { } + @Override public void setLeggings(ItemStack item) { } + @Override public void setRightArmPose(EulerAngle pose) { } + @Override public void setRightLegPose(EulerAngle pose) { } + @Override public void setSmall(boolean small) { } + @Override public void setVisible(boolean visible) { } + @Override public void setMarker(boolean marker) { } + + // Methods from LivingEntity class + @Override public boolean addPotionEffect(PotionEffect effect) { return false; } + @Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; } + @Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; } + @Override public void setRemoveWhenFarAway(boolean remove) { } + @Override public void setAI(boolean ai) { } + @Override public void setCanPickupItems(boolean pickup) { } + @Override public void setCollidable(boolean collidable) { } + @Override public void setGliding(boolean gliding) { } + @Override public boolean setLeashHolder(Entity holder) { return false; } + @Override public void setSwimming(boolean swimming) { } + + // Methods from Entity class + @Override public void setVelocity(Vector vel) { } + @Override public boolean teleport(Location loc) { return false; } + @Override public boolean teleport(Entity entity) { return false; } + @Override public boolean teleport(Location loc, TeleportCause cause) { return false; } + @Override public boolean teleport(Entity entity, TeleportCause cause) { return false; } + @Override public void setFireTicks(int ticks) { } + @Override public boolean setPassenger(Entity entity) { return false; } + @Override public boolean eject() { return false; } + @Override public boolean leaveVehicle() { return false; } + @Override public void playEffect(EntityEffect effect) { } + @Override public void setCustomName(String name) { } + @Override public void setCustomNameVisible(boolean flag) { } + @Override public void setGlowing(boolean flag) { } + @Override public void setGravity(boolean gravity) { } + @Override public void setInvulnerable(boolean flag) { } + @Override public void setMomentum(Vector value) { } + @Override public void setSilent(boolean flag) { } + @Override public void setTicksLived(int value) { } + @Override public void setPersistent(boolean flag) { } + @Override public void setRotation(float yaw, float pitch) { } + + +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSItem.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSItem.java new file mode 100644 index 00000000..6b252b15 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSItem.java @@ -0,0 +1,65 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R3.CraftServer; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftItem; +import org.bukkit.entity.Entity; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +public class CraftNMSItem extends CraftItem { + + public CraftNMSItem(CraftServer server, EntityNMSItem entity) { + super(server, entity); + } + + // Disallow all the bukkit methods. + + @Override + public void remove() { + // Cannot be removed, this is the most important to override. + } + + // Methods from Item class + @Override public void setItemStack(ItemStack stack) { } + @Override public void setPickupDelay(int delay) { } + + // Methods from Entity class + @Override public void setVelocity(Vector vel) { } + @Override public boolean teleport(Location loc) { return false; } + @Override public boolean teleport(Entity entity) { return false; } + @Override public boolean teleport(Location loc, TeleportCause cause) { return false; } + @Override public boolean teleport(Entity entity, TeleportCause cause) { return false; } + @Override public void setFireTicks(int ticks) { } + @Override public boolean setPassenger(Entity entity) { return false; } + @Override public boolean eject() { return false; } + @Override public boolean leaveVehicle() { return false; } + @Override public void playEffect(EntityEffect effect) { } + @Override public void setCustomName(String name) { } + @Override public void setCustomNameVisible(boolean flag) { } + @Override public void setGlowing(boolean flag) { } + @Override public void setGravity(boolean gravity) { } + @Override public void setInvulnerable(boolean flag) { } + @Override public void setMomentum(Vector value) { } + @Override public void setSilent(boolean flag) { } + @Override public void setTicksLived(int value) { } + @Override public void setPersistent(boolean flag) { } + @Override public void setRotation(float yaw, float pitch) { } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSSlime.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSSlime.java new file mode 100644 index 00000000..38e57629 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/CraftNMSSlime.java @@ -0,0 +1,85 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import java.util.Collection; + +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R3.CraftServer; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftSlime; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.loot.LootTable; +import org.bukkit.potion.PotionEffect; +import org.bukkit.util.Vector; + +public class CraftNMSSlime extends CraftSlime { + + public CraftNMSSlime(CraftServer server, EntityNMSSlime entity) { + super(server, entity); + } + + // Disallow all the bukkit methods. + + @Override + public void remove() { + // Cannot be removed, this is the most important to override. + } + + // Methods from Slime class + @Override public void setSize(int size) { } + @Override public void setTarget(LivingEntity target) { } + + // Methods from Mob class + @Override public void setLootTable(LootTable table) { } + @Override public void setSeed(long seed) { } + + // Methods from LivingEntity class + @Override public boolean addPotionEffect(PotionEffect effect) { return false; } + @Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; } + @Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; } + @Override public void setRemoveWhenFarAway(boolean remove) { } + @Override public void setAI(boolean ai) { } + @Override public void setCanPickupItems(boolean pickup) { } + @Override public void setCollidable(boolean collidable) { } + @Override public void setGliding(boolean gliding) { } + @Override public boolean setLeashHolder(Entity holder) { return false; } + @Override public void setSwimming(boolean swimming) { } + + // Methods from Entity class + @Override public void setVelocity(Vector vel) { } + @Override public boolean teleport(Location loc) { return false; } + @Override public boolean teleport(Entity entity) { return false; } + @Override public boolean teleport(Location loc, TeleportCause cause) { return false; } + @Override public boolean teleport(Entity entity, TeleportCause cause) { return false; } + @Override public void setFireTicks(int ticks) { } + @Override public boolean setPassenger(Entity entity) { return false; } + @Override public boolean eject() { return false; } + @Override public boolean leaveVehicle() { return false; } + @Override public void playEffect(EntityEffect effect) { } + @Override public void setCustomName(String name) { } + @Override public void setCustomNameVisible(boolean flag) { } + @Override public void setGlowing(boolean flag) { } + @Override public void setGravity(boolean gravity) { } + @Override public void setInvulnerable(boolean flag) { } + @Override public void setMomentum(Vector value) { } + @Override public void setSilent(boolean flag) { } + @Override public void setTicksLived(int value) { } + @Override public void setPersistent(boolean flag) { } + @Override public void setRotation(float yaw, float pitch) { } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSArmorStand.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSArmorStand.java new file mode 100644 index 00000000..231a6ad6 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSArmorStand.java @@ -0,0 +1,231 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import com.gmail.filoghost.holographicdisplays.api.line.HologramLine; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand; +import com.gmail.filoghost.holographicdisplays.util.Utils; +import net.minecraft.server.v1_16_R3.*; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage; + +public class EntityNMSArmorStand extends EntityArmorStand implements NMSArmorStand { + + private HologramLine parentPiece; + private CraftEntity customBukkitEntity; + private String customName; + + public EntityNMSArmorStand(World world, HologramLine parentPiece) { + super(EntityTypes.ARMOR_STAND, world); + super.setInvisible(true); + super.setSmall(true); + super.setArms(false); + super.setNoGravity(true); + super.setBasePlate(true); + super.setMarker(true); + super.collides = false; + this.parentPiece = parentPiece; + forceSetBoundingBox(new NullBoundingBox()); + + this.onGround = true; // Workaround to force EntityTrackerEntry to send a teleport packet. + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public void saveData(NBTTagCompound nbttagcompound) { + // Do not save NBT. + } + + @Override + public boolean a_(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return false; + } + + @Override + public boolean d(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return false; + } + + @Override + public NBTTagCompound save(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return nbttagcompound; + } + + @Override + public void load(NBTTagCompound nbttagcompound) { + // Do not load NBT. + } + + @Override + public void loadData(NBTTagCompound nbttagcompound) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerable(DamageSource source) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public boolean isCollidable() { + return false; + } + + @Override + public void setCustomName(IChatBaseComponent ichatbasecomponent) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean visible) { + // Locks the custom name. + } + + @Override + public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, EnumHand enumhand) { + // Prevent stand being equipped + return EnumInteractionResult.PASS; + } + + @Override + public boolean a_(int i, ItemStack item) { + // Prevent stand being equipped + return false; + } + + @Override + public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { + // Prevent stand being equipped + } + + @Override + public void a(AxisAlignedBB boundingBox) { + // Do not change it! + } + + public void forceSetBoundingBox(AxisAlignedBB boundingBox) { + super.a(boundingBox); + } + + @Override + public void playSound(SoundEffect soundeffect, float f, float f1) { + // Remove sounds. + } + + @Override + public void setCustomNameNMS(String name) { + this.customName = Utils.limitLength(name, 300); + super.setCustomName(CraftChatMessage.fromStringOrNull(customName)); + super.setCustomNameVisible(customName != null && !customName.isEmpty()); + } + + @Override + public String getCustomNameStringNMS() { + return this.customName; + } + + @Override + public Object getCustomNameObjectNMS() { + return super.getCustomName(); + } + + @Override + public void die() { + // Prevent being killed. + } + + @Override + public CraftEntity getBukkitEntity() { + if (customBukkitEntity == null) { + customBukkitEntity = new CraftNMSArmorStand(super.world.getServer(), this); + } + return customBukkitEntity; + } + + @Override + public void killEntityNMS() { + super.dead = true; + } + + @Override + public void setLocationNMS(double x, double y, double z, boolean broadcastLocationPacket) { + super.setPosition(x, y, z); + if (broadcastLocationPacket) { + broadcastLocationPacketNMS(); + } + } + + private void broadcastLocationPacketNMS() { + PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(this); + + for (Object obj : super.world.getPlayers()) { + if (obj instanceof EntityPlayer) { + EntityPlayer nmsPlayer = (EntityPlayer) obj; + + double distanceSquared = Utils.square(nmsPlayer.locX() - super.locX()) + Utils.square(nmsPlayer.locZ() - super.locZ()); + if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) { + nmsPlayer.playerConnection.sendPacket(teleportPacket); + } + } + } + } + + @Override + public boolean isDeadNMS() { + return super.dead; + } + + @Override + public int getIdNMS() { + return super.getId(); + } + + @Override + public HologramLine getHologramLine() { + return parentPiece; + } + + @Override + public org.bukkit.entity.Entity getBukkitEntityNMS() { + return getBukkitEntity(); + } +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSItem.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSItem.java new file mode 100644 index 00000000..834479fd --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSItem.java @@ -0,0 +1,249 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import java.util.logging.Level; + +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; +import org.bukkit.entity.Player; + +import com.gmail.filoghost.holographicdisplays.api.line.ItemLine; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.ItemPickupManager; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem; +import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger; +import com.gmail.filoghost.holographicdisplays.util.ItemUtils; +import com.gmail.filoghost.holographicdisplays.util.reflection.ReflectField; + +import net.minecraft.server.v1_16_R3.Blocks; +import net.minecraft.server.v1_16_R3.DamageSource; +import net.minecraft.server.v1_16_R3.Entity; +import net.minecraft.server.v1_16_R3.EntityHuman; +import net.minecraft.server.v1_16_R3.EntityItem; +import net.minecraft.server.v1_16_R3.EntityPlayer; +import net.minecraft.server.v1_16_R3.EntityTypes; +import net.minecraft.server.v1_16_R3.ItemStack; +import net.minecraft.server.v1_16_R3.NBTTagCompound; +import net.minecraft.server.v1_16_R3.NBTTagList; +import net.minecraft.server.v1_16_R3.NBTTagString; +import net.minecraft.server.v1_16_R3.World; + +public class EntityNMSItem extends EntityItem implements NMSItem { + + private static final ReflectField<Entity> VEHICLE_FIELD = new ReflectField<>(Entity.class, "vehicle"); + + private ItemLine parentPiece; + private ItemPickupManager itemPickupManager; + private CraftEntity customBukkitEntity; + + public EntityNMSItem(World world, ItemLine piece, ItemPickupManager itemPickupManager) { + super(EntityTypes.ITEM, world); + super.pickupDelay = 32767; // Lock the item pickup delay, also prevents entities from picking up the item + this.parentPiece = piece; + this.itemPickupManager = itemPickupManager; + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // So it won't get removed. + ticksLived = 0; + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // So it won't get removed. + ticksLived = 0; + } + + // Method called when a player is near. + @Override + public void pickup(EntityHuman human) { + + if (human.locY() < super.locY() - 1.5 || human.locY() > super.locY() + 1.0) { + // Too low or too high, it's a bit weird./ + return; + } + + if (parentPiece.getPickupHandler() != null && human instanceof EntityPlayer) { + itemPickupManager.handleItemLinePickup((Player) human.getBukkitEntity(), parentPiece.getPickupHandler(), parentPiece.getParent()); + // It is never added to the inventory. + } + } + + @Override + public void saveData(NBTTagCompound nbttagcompound) { + // Do not save NBT. + } + + @Override + public boolean a_(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return false; + } + + @Override + public boolean d(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return false; + } + + @Override + public NBTTagCompound save(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return nbttagcompound; + } + + @Override + public void load(NBTTagCompound nbttagcompound) { + // Do not load NBT. + } + + @Override + public void loadData(NBTTagCompound nbttagcompound) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerable(DamageSource source) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public boolean isCollidable() { + return false; + } + + @Override + public void die() { + // Prevent being killed. + } + + @Override + public boolean isAlive() { + // This override prevents items from being picked up by hoppers. + // Should have no side effects. + return false; + } + + @Override + public CraftEntity getBukkitEntity() { + if (customBukkitEntity == null) { + customBukkitEntity = new CraftNMSItem(super.world.getServer(), this); + } + return customBukkitEntity; + } + + @Override + public boolean isDeadNMS() { + return super.dead; + } + + @Override + public void killEntityNMS() { + super.dead = true; + } + + @Override + public void setLocationNMS(double x, double y, double z) { + super.setPosition(x, y, z); + } + + @Override + public void setItemStackNMS(org.bukkit.inventory.ItemStack stack) { + ItemStack newItem = CraftItemStack.asNMSCopy(stack); // ItemStack.a is returned if the stack is null, invalid or the material is not an Item + + if (newItem == null || newItem == ItemStack.b) { + newItem = new ItemStack(Blocks.BEDROCK); + } + + if (newItem.getTag() == null) { + newItem.setTag(new NBTTagCompound()); + } + NBTTagCompound display = newItem.getTag().getCompound("display"); // Returns a new NBTTagCompound if not existing + if (!newItem.getTag().hasKey("display")) { + newItem.getTag().set("display", display); + } + + NBTTagList tagList = new NBTTagList(); + tagList.add(NBTTagString.a(ItemUtils.ANTISTACK_LORE)); // Antistack lore + display.set("Lore", tagList); + + setItemStack(newItem); + } + + @Override + public int getIdNMS() { + return super.getId(); + } + + @Override + public ItemLine getHologramLine() { + return parentPiece; + } + + @Override + public void allowPickup(boolean pickup) { + if (pickup) { + super.pickupDelay = 0; + } else { + super.pickupDelay = 32767; + } + } + + @Override + public org.bukkit.entity.Entity getBukkitEntityNMS() { + return getBukkitEntity(); + } + + @Override + public void setPassengerOfNMS(NMSEntityBase vehicleBase) { + if (vehicleBase == null || !(vehicleBase instanceof Entity)) { + // It should never dismount + return; + } + + Entity entity = (Entity) vehicleBase; + + try { + if (super.getVehicle() != null) { + Entity oldVehicle = super.getVehicle(); + VEHICLE_FIELD.set(this, null); + oldVehicle.passengers.remove(this); + } + + VEHICLE_FIELD.set(this, entity); + entity.passengers.clear(); + entity.passengers.add(this); + + } catch (Throwable t) { + ConsoleLogger.logDebug(Level.SEVERE, "Couldn't set passenger", t); + } + } + + @Override + public Object getRawItemStack() { + return super.getItemStack(); + } +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSSlime.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSSlime.java new file mode 100644 index 00000000..2c734b00 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/EntityNMSSlime.java @@ -0,0 +1,225 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import java.util.logging.Level; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; +import org.bukkit.event.player.PlayerInteractEntityEvent; + +import com.gmail.filoghost.holographicdisplays.api.line.HologramLine; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime; +import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger; +import com.gmail.filoghost.holographicdisplays.util.reflection.ReflectField; + +import net.minecraft.server.v1_16_R3.AxisAlignedBB; +import net.minecraft.server.v1_16_R3.DamageSource; +import net.minecraft.server.v1_16_R3.Entity; +import net.minecraft.server.v1_16_R3.EntityDamageSource; +import net.minecraft.server.v1_16_R3.EntityPlayer; +import net.minecraft.server.v1_16_R3.EntitySlime; +import net.minecraft.server.v1_16_R3.EntityTypes; +import net.minecraft.server.v1_16_R3.IChatBaseComponent; +import net.minecraft.server.v1_16_R3.NBTTagCompound; +import net.minecraft.server.v1_16_R3.SoundEffect; +import net.minecraft.server.v1_16_R3.World; + +public class EntityNMSSlime extends EntitySlime implements NMSSlime { + + private static final ReflectField<Entity> VEHICLE_FIELD = new ReflectField<>(Entity.class, "vehicle"); + + private HologramLine parentPiece; + private CraftEntity customBukkitEntity; + + public EntityNMSSlime(World world, HologramLine parentPiece) { + super(EntityTypes.SLIME, world); + super.persistent = true; + super.collides = false; + a(0.0F, 0.0F); + setSize(1, false); + setInvisible(true); + this.parentPiece = parentPiece; + forceSetBoundingBox(new NullBoundingBox()); + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // So it won't get removed. + ticksLived = 0; + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // So it won't get removed. + ticksLived = 0; + } + + @Override + public void a(AxisAlignedBB boundingBox) { + // Do not change it! + } + + public void forceSetBoundingBox(AxisAlignedBB boundingBox) { + super.a(boundingBox); + } + + @Override + public void saveData(NBTTagCompound nbttagcompound) { + // Do not save NBT. + } + + @Override + public boolean a_(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return false; + } + + @Override + public boolean d(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return false; + } + + @Override + public NBTTagCompound save(NBTTagCompound nbttagcompound) { + // Do not save NBT. + return nbttagcompound; + } + + @Override + public void load(NBTTagCompound nbttagcompound) { + // Do not load NBT. + } + + @Override + public void loadData(NBTTagCompound nbttagcompound) { + // Do not load NBT. + } + + @Override + public boolean damageEntity(DamageSource damageSource, float amount) { + if (damageSource instanceof EntityDamageSource) { + EntityDamageSource entityDamageSource = (EntityDamageSource) damageSource; + if (entityDamageSource.getEntity() instanceof EntityPlayer) { + Bukkit.getPluginManager().callEvent(new PlayerInteractEntityEvent(((EntityPlayer) entityDamageSource.getEntity()).getBukkitEntity(), getBukkitEntity())); // Bukkit takes care of the exceptions + } + } + return false; + } + + @Override + public boolean isInvulnerable(DamageSource source) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public boolean isCollidable() { + return false; + } + + @Override + public void setCustomName(IChatBaseComponent ichatbasecomponent) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean visible) { + // Locks the custom name. + } + + @Override + public void playSound(SoundEffect soundeffect, float f, float f1) { + // Remove sounds. + } + + @Override + public void die() { + // Prevent being killed. + } + + @Override + public CraftEntity getBukkitEntity() { + if (customBukkitEntity == null) { + customBukkitEntity = new CraftNMSSlime(super.world.getServer(), this); + } + return customBukkitEntity; + } + + @Override + public boolean isDeadNMS() { + return super.dead; + } + + @Override + public void killEntityNMS() { + super.dead = true; + } + + @Override + public void setLocationNMS(double x, double y, double z) { + super.setPosition(x, y, z); + } + + @Override + public int getIdNMS() { + return super.getId(); + } + + @Override + public HologramLine getHologramLine() { + return parentPiece; + } + + @Override + public org.bukkit.entity.Entity getBukkitEntityNMS() { + return getBukkitEntity(); + } + + @Override + public void setPassengerOfNMS(NMSEntityBase vehicleBase) { + if (vehicleBase == null || !(vehicleBase instanceof Entity)) { + // It should never dismount + return; + } + + Entity entity = (Entity) vehicleBase; + + try { + if (super.getVehicle() != null) { + Entity oldVehicle = super.getVehicle(); + VEHICLE_FIELD.set(this, null); + oldVehicle.passengers.remove(this); + } + + VEHICLE_FIELD.set(this, entity); + entity.passengers.clear(); + entity.passengers.add(this); + + } catch (Throwable t) { + ConsoleLogger.logDebug(Level.SEVERE, "Couldn't set passenger", t); + } + } +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/NmsManagerImpl.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/NmsManagerImpl.java new file mode 100644 index 00000000..80730ed6 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/NmsManagerImpl.java @@ -0,0 +1,190 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import java.util.List; + +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; +import org.bukkit.inventory.ItemStack; + +import com.gmail.filoghost.holographicdisplays.api.line.HologramLine; +import com.gmail.filoghost.holographicdisplays.api.line.ItemLine; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.ChatComponentAdapter; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.ItemPickupManager; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.CustomNameHelper; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase; +import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem; +import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger; +import com.gmail.filoghost.holographicdisplays.util.Validator; +import com.gmail.filoghost.holographicdisplays.util.reflection.ReflectField; +import com.gmail.filoghost.holographicdisplays.util.reflection.ReflectMethod; + +import net.minecraft.server.v1_16_R3.ChatComponentText; +import net.minecraft.server.v1_16_R3.Entity; +import net.minecraft.server.v1_16_R3.EntityTypes; +import net.minecraft.server.v1_16_R3.EnumCreatureType; +import net.minecraft.server.v1_16_R3.IChatBaseComponent; +import net.minecraft.server.v1_16_R3.IRegistry; +import net.minecraft.server.v1_16_R3.MathHelper; +import net.minecraft.server.v1_16_R3.RegistryMaterials; +import net.minecraft.server.v1_16_R3.WorldServer; + +public class NmsManagerImpl implements NMSManager { + + private static final ReflectField<Map<EntityTypes<?>, Integer>> REGISTRY_TO_ID_FIELD = new ReflectField<>(RegistryMaterials.class, "bg"); + private static final ReflectMethod<Void> REGISTER_ENTITY_METHOD = new ReflectMethod<>(WorldServer.class, "registerEntity", Entity.class); + + @Override + public void setup() throws Exception { + registerCustomEntity(EntityNMSSlime.class, 55, 2.04f, 2.04f); + } + + public void registerCustomEntity(Class<? extends Entity> entityClass, int id, float sizeWidth, float sizeHeight) throws Exception { + // Use reflection to map the custom entity to the correct ID + Map<EntityTypes<?>, Integer> entityTypesToId = REGISTRY_TO_ID_FIELD.get(IRegistry.ENTITY_TYPE); + EntityTypes<?> customEntityTypes = EntityTypes.Builder.a(EnumCreatureType.MONSTER).a(sizeWidth, sizeHeight).b().a((String) null); + entityTypesToId.put(customEntityTypes, id); + } + + @Override + public NMSItem spawnNMSItem(org.bukkit.World bukkitWorld, double x, double y, double z, ItemLine parentPiece, ItemStack stack, ItemPickupManager itemPickupManager) { + WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle(); + EntityNMSItem customItem = new EntityNMSItem(nmsWorld, parentPiece, itemPickupManager); + customItem.setLocationNMS(x, y, z); + customItem.setItemStackNMS(stack); + if (!addEntityToWorld(nmsWorld, customItem)) { + ConsoleLogger.handleSpawnFail(parentPiece); + } + return customItem; + } + + @Override + public EntityNMSSlime spawnNMSSlime(org.bukkit.World bukkitWorld, double x, double y, double z, HologramLine parentPiece) { + WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle(); + EntityNMSSlime touchSlime = new EntityNMSSlime(nmsWorld, parentPiece); + touchSlime.setLocationNMS(x, y, z); + if (!addEntityToWorld(nmsWorld, touchSlime)) { + ConsoleLogger.handleSpawnFail(parentPiece); + } + return touchSlime; + } + + @Override + public NMSArmorStand spawnNMSArmorStand(org.bukkit.World world, double x, double y, double z, HologramLine parentPiece, boolean broadcastLocationPacket) { + WorldServer nmsWorld = ((CraftWorld) world).getHandle(); + EntityNMSArmorStand invisibleArmorStand = new EntityNMSArmorStand(nmsWorld, parentPiece); + invisibleArmorStand.setLocationNMS(x, y, z, broadcastLocationPacket); + if (!addEntityToWorld(nmsWorld, invisibleArmorStand)) { + ConsoleLogger.handleSpawnFail(parentPiece); + } + return invisibleArmorStand; + } + + private boolean addEntityToWorld(WorldServer nmsWorld, Entity nmsEntity) { + Validator.isTrue(Bukkit.isPrimaryThread(), "Async entity add"); + + final int chunkX = MathHelper.floor(nmsEntity.locX() / 16.0); + final int chunkZ = MathHelper.floor(nmsEntity.locZ() / 16.0); + + if (!nmsWorld.isChunkLoaded(chunkX, chunkZ)) { + // This should never happen + nmsEntity.dead = true; + return false; + } + + nmsWorld.getChunkAt(chunkX, chunkZ).a(nmsEntity); + try { + REGISTER_ENTITY_METHOD.invoke(nmsWorld, nmsEntity); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean isNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) { + return ((CraftEntity) bukkitEntity).getHandle() instanceof NMSEntityBase; + } + + @Override + public NMSEntityBase getNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) { + Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle(); + + if (nmsEntity instanceof NMSEntityBase) { + return ((NMSEntityBase) nmsEntity); + } else { + return null; + } + } + + @Override + public NMSEntityBase getNMSEntityBaseFromID(org.bukkit.World bukkitWorld, int entityID) { + WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle(); + Entity nmsEntity = nmsWorld.getEntity(entityID); + + if (nmsEntity instanceof NMSEntityBase) { + return ((NMSEntityBase) nmsEntity); + } else { + return null; + } + } + + @Override + public Object replaceCustomNameText(Object customNameObject, String target, String replacement) { + return CustomNameHelper.replaceCustomNameChatComponent(NMSChatComponentAdapter.INSTANCE, customNameObject, target, replacement); + } + + private static enum NMSChatComponentAdapter implements ChatComponentAdapter<IChatBaseComponent> { + + INSTANCE { + + public ChatComponentText cast(Object chatComponentObject) { + return (ChatComponentText) chatComponentObject; + } + + @Override + public String getText(IChatBaseComponent chatComponent) { + return chatComponent.getText(); + } + + @Override + public List<IChatBaseComponent> getSiblings(IChatBaseComponent chatComponent) { + return chatComponent.getSiblings(); + } + + @Override + public void addSibling(IChatBaseComponent chatComponent, IChatBaseComponent newSibling) { + newSibling.getChatModifier().setChatModifier(chatComponent.getChatModifier()); + chatComponent.getSiblings().add(newSibling); + } + + @Override + public ChatComponentText cloneComponent(IChatBaseComponent chatComponent, String newText) { + ChatComponentText clonedChatComponent = new ChatComponentText(newText); + clonedChatComponent.setChatModifier(chatComponent.getChatModifier().a()); + return clonedChatComponent; + } + + } + + } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/NullBoundingBox.java b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/NullBoundingBox.java new file mode 100644 index 00000000..408bff2c --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/gmail/filoghost/holographicdisplays/nms/v1_16_R3/NullBoundingBox.java @@ -0,0 +1,134 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package com.gmail.filoghost.holographicdisplays.nms.v1_16_R3; + +import net.minecraft.server.v1_16_R3.AxisAlignedBB; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.EnumDirection.EnumAxis; +import net.minecraft.server.v1_16_R3.Vec3D; + +public class NullBoundingBox extends AxisAlignedBB { + + public NullBoundingBox() { + super(0, 0, 0, 0, 0, 0); + } + + @Override + public double a() { + return 0.0; + } + + @Override + public AxisAlignedBB a(AxisAlignedBB arg0) { + return this; + } + + @Override + public AxisAlignedBB a(double arg0, double arg1, double arg2) { + return this; + } + + @Override + public AxisAlignedBB grow(double arg0, double arg1, double arg2) { + return this; + } + + @Override + public AxisAlignedBB shrink(double arg0) { + return this; + } + + @Override + public AxisAlignedBB a(BlockPosition arg0) { + return this; + } + + @Override + public boolean a(double arg0, double arg1, double arg2, double arg3, double arg4, double arg5) { + return false; + } + + @Override + public AxisAlignedBB g(double arg0) { + return this; + } + + @Override + public AxisAlignedBB b(Vec3D arg0) { + return this; + } + + @Override + public AxisAlignedBB b(AxisAlignedBB arg0) { + return this; + } + + @Override + public AxisAlignedBB b(double arg0, double arg1, double arg2) { + return this; + } + + @Override + public boolean c(AxisAlignedBB arg0) { + return false; + } + + @Override + public AxisAlignedBB d(double arg0, double arg1, double arg2) { + return this; + } + + @Override + public double a(EnumAxis arg0) { + return 0.0; + } + + @Override + public double b(EnumAxis arg0) { + return 0.0; + } + + @Override + public boolean e(double arg0, double arg1, double arg2) { + return false; + } + + @Override + public double b() { + return 0.0; + } + + @Override + public double c() { + return 0.0; + } + + @Override + public double d() { + return 0.0; + } + + @Override + public boolean d(Vec3D var0) { + return false; + } + + @Override + public Vec3D f() { + return Vec3D.ORIGIN; + } + + +} diff --git a/Plugin/pom.xml b/Plugin/pom.xml index c8a8577c..5c3bd86b 100644 --- a/Plugin/pom.xml +++ b/Plugin/pom.xml @@ -120,6 +120,11 @@ <artifactId>holographicdisplays-nms-v1_16_r2</artifactId> </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>holographicdisplays-nms-v1_16_r3</artifactId> + </dependency> + <dependency> <groupId>org.spigotmc</groupId> <artifactId>spigot-api</artifactId> diff --git a/Plugin/src/main/java/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java b/Plugin/src/main/java/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java index de842ba2..ae098b25 100644 --- a/Plugin/src/main/java/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java +++ b/Plugin/src/main/java/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java @@ -109,7 +109,7 @@ public class HolographicDisplays extends JavaPlugin { if (!NMSVersion.isValid()) { criticalShutdown( "Holographic Displays does not support this server version.", - "Supported Spigot versions: from 1.8.3 to 1.16."); + "Supported Spigot versions: from 1.8.3 to 1.16.4."); return; } diff --git a/Utils/src/main/java/com/gmail/filoghost/holographicdisplays/util/NMSVersion.java b/Utils/src/main/java/com/gmail/filoghost/holographicdisplays/util/NMSVersion.java index 2d45530c..7c2787fa 100644 --- a/Utils/src/main/java/com/gmail/filoghost/holographicdisplays/util/NMSVersion.java +++ b/Utils/src/main/java/com/gmail/filoghost/holographicdisplays/util/NMSVersion.java @@ -31,7 +31,8 @@ public enum NMSVersion { v1_14_R1, v1_15_R1, v1_16_R1, - v1_16_R2; + v1_16_R2, + v1_16_R3; private static final NMSVersion CURRENT_VERSION = extractCurrentVersion(); diff --git a/pom.xml b/pom.xml index f2e433c8..bf89e0bf 100644 --- a/pom.xml +++ b/pom.xml @@ -147,6 +147,12 @@ <artifactId>holographicdisplays-nms-v1_16_r2</artifactId> <version>${project.version}</version> </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>holographicdisplays-nms-v1_16_r3</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.spigotmc</groupId>