package com.bgsoftware.wildloaders.nms.v1_8_R3; import com.bgsoftware.wildloaders.handlers.NPCHandler; import com.bgsoftware.wildloaders.npc.DummyChannel; import com.mojang.authlib.GameProfile; import net.minecraft.server.v1_8_R3.AxisAlignedBB; import net.minecraft.server.v1_8_R3.DamageSource; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.EnumProtocolDirection; import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.NetworkManager; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig; import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace; import net.minecraft.server.v1_8_R3.PacketPlayInChat; import net.minecraft.server.v1_8_R3.PacketPlayInFlying; import net.minecraft.server.v1_8_R3.PacketPlayInHeldItemSlot; import net.minecraft.server.v1_8_R3.PacketPlayInTransaction; import net.minecraft.server.v1_8_R3.PacketPlayInUpdateSign; import net.minecraft.server.v1_8_R3.PacketPlayInWindowClick; import net.minecraft.server.v1_8_R3.PlayerConnection; import net.minecraft.server.v1_8_R3.PlayerInteractManager; import net.minecraft.server.v1_8_R3.Statistic; import net.minecraft.server.v1_8_R3.WorldServer; import net.minecraft.server.v1_8_R3.WorldSettings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_8_R3.CraftServer; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.entity.Player; import java.lang.reflect.Field; import java.util.UUID; public final class ChunkLoaderNPC extends EntityPlayer implements com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC { private final AxisAlignedBB boundingBox; public ChunkLoaderNPC(Location location, UUID uuid) { super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(), new GameProfile(uuid, NPCHandler.getName(location.getWorld().getName())), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle())); this.boundingBox = new AxisAlignedBB(location.getX(), location.getY(), location.getZ(), location.getX() + 1, location.getY() + 1, location.getZ() + 1); playerConnection = new DummyPlayerConnection(server, this); playerInteractManager.setGameMode(WorldSettings.EnumGamemode.CREATIVE); fallDistance = 0.0F; fauxSleeping = true; try { // Paper affectsSpawning = true; } catch (Throwable ignored) { } spawnIn(world); setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); world.players.add(this); ((WorldServer) world).getPlayerChunkMap().addPlayer(this); super.a(this.boundingBox); } @Override public UUID getUniqueId() { return super.getUniqueID(); } @Override public AxisAlignedBB getBoundingBox() { // boundingBox is null on initialization of the class, which fixes: // https://github.com/BG-Software-LLC/WildLoaders/issues/61 return this.boundingBox == null ? super.getBoundingBox() : this.boundingBox; } @Override public void die() { super.die(); world.players.remove(this); ((WorldServer) world).getPlayerChunkMap().removePlayer(this); } @Override public Location getLocation() { return getBukkitEntity().getLocation(); } @Override public boolean damageEntity(DamageSource damagesource, float f) { return false; } @Override public void a(Statistic statistic, int i) { // Prevent achievements from being given to NPCs. } @Override public void a(Statistic statistic) { // Prevent achievements from being given to NPCs. } @Override public Player getPlayer() { return getBukkitEntity(); } public static class DummyNetworkManager extends NetworkManager { private static Field channelField; private static Field socketAddressField; static { try { channelField = NetworkManager.class.getDeclaredField("channel"); channelField.setAccessible(true); socketAddressField = NetworkManager.class.getDeclaredField("l"); socketAddressField.setAccessible(true); } catch (Exception error) { error.printStackTrace(); } } DummyNetworkManager() { super(EnumProtocolDirection.SERVERBOUND); updateFields(); } private void updateFields() { try { if (channelField != null) { channelField.set(this, new DummyChannel()); } if (socketAddressField != null) { socketAddressField.set(this, null); } } catch (Exception error) { error.printStackTrace(); } } } public static class DummyPlayerConnection extends PlayerConnection { DummyPlayerConnection(MinecraftServer minecraftServer, EntityPlayer entityPlayer) { super(minecraftServer, new DummyNetworkManager(), entityPlayer); } public void a(PacketPlayInWindowClick packetPlayInWindowClick) { } public void a(PacketPlayInTransaction packetPlayInTransaction) { } public void a(PacketPlayInFlying packetPlayInFlying) { } public void a(PacketPlayInUpdateSign packetPlayInUpdateSign) { } public void a(PacketPlayInBlockDig packetPlayInBlockDig) { } public void a(PacketPlayInBlockPlace packetPlayInBlockPlace) { } public void disconnect(String s) { } public void a(PacketPlayInHeldItemSlot packetPlayInHeldItemSlot) { } public void a(PacketPlayInChat packetPlayInChat) { } public void sendPacket(Packet packet) { } } }