Added full support for 1.16.4

This commit is contained in:
OmerBenGera 2020-11-06 14:12:23 +02:00
parent e4262dc286
commit 07cd799cad
3 changed files with 622 additions and 0 deletions

View File

@ -0,0 +1,147 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.npc.DummyChannel;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import net.minecraft.server.v1_16_R3.EnumGamemode;
import net.minecraft.server.v1_16_R3.EnumProtocolDirection;
import net.minecraft.server.v1_16_R3.MinecraftServer;
import net.minecraft.server.v1_16_R3.NetworkManager;
import net.minecraft.server.v1_16_R3.Packet;
import net.minecraft.server.v1_16_R3.PacketPlayInBlockDig;
import net.minecraft.server.v1_16_R3.PacketPlayInBlockPlace;
import net.minecraft.server.v1_16_R3.PacketPlayInChat;
import net.minecraft.server.v1_16_R3.PacketPlayInFlying;
import net.minecraft.server.v1_16_R3.PacketPlayInHeldItemSlot;
import net.minecraft.server.v1_16_R3.PacketPlayInTransaction;
import net.minecraft.server.v1_16_R3.PacketPlayInUpdateSign;
import net.minecraft.server.v1_16_R3.PacketPlayInWindowClick;
import net.minecraft.server.v1_16_R3.PlayerConnection;
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
import java.lang.reflect.Field;
import java.util.UUID;
public final class ChunkLoaderNPC_v1_16_R3 extends EntityPlayer implements ChunkLoaderNPC {
private boolean dieCall = false;
public ChunkLoaderNPC_v1_16_R3(Location location, UUID uuid){
super(((CraftServer) Bukkit.getServer()).getServer(), ((CraftWorld) location.getWorld()).getHandle(),
new GameProfile(uuid, "Loader-" + location.getWorld().getName()), new PlayerInteractManager(((CraftWorld) location.getWorld()).getHandle()));
playerConnection = new DummyPlayerConnection(server, this);
this.playerInteractManager.setGameMode(EnumGamemode.CREATIVE);
clientViewDistance = 1;
fauxSleeping = true;
spawnIn(world);
setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
((WorldServer) world).addPlayerJoin(this);
}
@Override
public UUID getUniqueId() {
return super.getUniqueID();
}
@Override
public void die() {
if(!dieCall) {
dieCall = true;
getWorldServer().removePlayer(this);
dieCall = false;
}
else {
super.die();
}
}
@Override
public Location getLocation() {
return getBukkitEntity().getLocation();
}
private static class DummyNetworkManager extends NetworkManager{
DummyNetworkManager(){
super(EnumProtocolDirection.SERVERBOUND);
updateFields();
}
private void updateFields() {
try {
Field channelField = NetworkManager.class.getDeclaredField("channel");
channelField.setAccessible(true);
channelField.set(this, new DummyChannel());
channelField.setAccessible(false);
Field socketAddressField = NetworkManager.class.getDeclaredField("socketAddress");
socketAddressField.setAccessible(true);
socketAddressField.set(this, null);
}
catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
private 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) {
}
}
}

View File

@ -0,0 +1,179 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.api.holograms.Hologram;
import net.minecraft.server.v1_16_R3.AxisAlignedBB;
import net.minecraft.server.v1_16_R3.DamageSource;
import net.minecraft.server.v1_16_R3.EntityArmorStand;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EnumHand;
import net.minecraft.server.v1_16_R3.EnumInteractionResult;
import net.minecraft.server.v1_16_R3.EnumItemSlot;
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
import net.minecraft.server.v1_16_R3.ItemStack;
import net.minecraft.server.v1_16_R3.NBTTagCompound;
import net.minecraft.server.v1_16_R3.SoundEffect;
import net.minecraft.server.v1_16_R3.Vec3D;
import net.minecraft.server.v1_16_R3.World;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftArmorStand;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage;
import org.bukkit.entity.Entity;
import javax.annotation.Nullable;
@SuppressWarnings("unused")
public final class EntityHolograms_v1_16_R3 extends EntityArmorStand implements Hologram {
private CraftEntity bukkitEntity;
EntityHolograms_v1_16_R3(World world, double x, double y, double z){
super(world, x, y, z);
setInvisible(true);
setSmall(true);
setArms(false);
setNoGravity(true);
setBasePlate(true);
setMarker(true);
super.collides = false;
super.setCustomNameVisible(true);
super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));
}
@Override
public void setHologramName(String name) {
super.setCustomName(CraftChatMessage.fromString(name)[0]);
}
@Override
public void removeHologram() {
super.die();
}
@Override
public Entity getEntity() {
return getBukkitEntity();
}
@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(@Nullable IChatBaseComponent ichatbasecomponent) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean flag) {
// 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 die() {
// Prevent being killed.
}
@Override
public CraftEntity getBukkitEntity() {
if (bukkitEntity == null) {
bukkitEntity = new CraftArmorStand(super.world.getServer(), this);
}
return bukkitEntity;
}
}

View File

@ -0,0 +1,296 @@
package com.bgsoftware.wildloaders.nms;
import com.bgsoftware.wildloaders.WildLoadersPlugin;
import com.bgsoftware.wildloaders.api.holograms.Hologram;
import com.bgsoftware.wildloaders.api.loaders.ChunkLoader;
import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC;
import com.bgsoftware.wildloaders.loaders.ITileEntityChunkLoader;
import com.bgsoftware.wildloaders.loaders.WChunkLoader;
import net.minecraft.server.v1_16_R3.Block;
import net.minecraft.server.v1_16_R3.BlockPosition;
import net.minecraft.server.v1_16_R3.Chunk;
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
import net.minecraft.server.v1_16_R3.IBlockData;
import net.minecraft.server.v1_16_R3.ITickable;
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.NBTTagLong;
import net.minecraft.server.v1_16_R3.NBTTagString;
import net.minecraft.server.v1_16_R3.TileEntity;
import net.minecraft.server.v1_16_R3.TileEntityMobSpawner;
import net.minecraft.server.v1_16_R3.TileEntityTypes;
import net.minecraft.server.v1_16_R3.World;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings("unused")
public final class NMSAdapter_v1_16_R3 implements NMSAdapter {
private static final WildLoadersPlugin plugin = WildLoadersPlugin.getPlugin();
@Override
public String getTag(org.bukkit.inventory.ItemStack itemStack, String key, String def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 8))
return def;
return tagCompound.getString(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, String value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagString.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public long getTag(org.bukkit.inventory.ItemStack itemStack, String key, long def) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
if(!tagCompound.hasKeyOfType(key, 4))
return def;
return tagCompound.getLong(key);
}
@Override
public org.bukkit.inventory.ItemStack setTag(org.bukkit.inventory.ItemStack itemStack, String key, long value) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound tagCompound = nmsItem.getOrCreateTag();
tagCompound.set(key, NBTTagLong.a(value));
nmsItem.setTag(tagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public org.bukkit.inventory.ItemStack getPlayerSkull(org.bukkit.inventory.ItemStack itemStack, String texture) {
ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack);
NBTTagCompound nbtTagCompound = nmsItem.getOrCreateTag();
NBTTagCompound skullOwner = nbtTagCompound.hasKey("SkullOwner") ? nbtTagCompound.getCompound("SkullOwner") : new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound signature = new NBTTagCompound();
signature.setString("Value", texture);
textures.add(signature);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
skullOwner.setString("Id", UUID.randomUUID().toString());
nbtTagCompound.set("SkullOwner", skullOwner);
nmsItem.setTag(nbtTagCompound);
return CraftItemStack.asBukkitCopy(nmsItem);
}
@Override
public ChunkLoaderNPC createNPC(Location location, UUID uuid) {
return new ChunkLoaderNPC_v1_16_R3(location, uuid);
}
@Override
public ITileEntityChunkLoader createLoader(ChunkLoader chunkLoader) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
TileEntityChunkLoader tileEntityChunkLoader = new TileEntityChunkLoader(chunkLoader, world, blockPosition);
world.tileEntityListTick.add(tileEntityChunkLoader);
for(org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) {
Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = -1);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
return tileEntityChunkLoader;
}
@Override
public void removeLoader(ChunkLoader chunkLoader, boolean spawnParticle) {
Location loaderLoc = chunkLoader.getLocation();
assert loaderLoc.getWorld() != null;
WorldServer world = ((CraftWorld) loaderLoc.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(loaderLoc.getX(), loaderLoc.getY(), loaderLoc.getZ());
long tileEntityLong = ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4);
TileEntityChunkLoader tileEntityChunkLoader = TileEntityChunkLoader.tileEntityChunkLoaderMap.remove(tileEntityLong);
if(tileEntityChunkLoader != null) {
tileEntityChunkLoader.holograms.forEach(EntityHolograms_v1_16_R3::removeHologram);
tileEntityChunkLoader.removed = true;
world.tileEntityListTick.remove(tileEntityChunkLoader);
}
if(spawnParticle)
world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));
for(org.bukkit.Chunk bukkitChunk : chunkLoader.getLoadedChunks()) {
Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();
chunk.tileEntities.values().stream().filter(tileEntity -> tileEntity instanceof TileEntityMobSpawner)
.forEach(tileEntity -> ((TileEntityMobSpawner) tileEntity).getSpawner().requiredPlayerRange = 16);
world.setForceLoaded(chunk.getPos().x, chunk.getPos().z, true);
}
}
@Override
public void updateSpawner(Location location, boolean reset) {
assert location.getWorld() != null;
World world = ((CraftWorld) location.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ());
IBlockData blockData = world.getType(blockPosition);
TileEntityMobSpawner mobSpawner = (TileEntityMobSpawner) world.getTileEntity(blockPosition);
if(mobSpawner == null)
return;
mobSpawner.getSpawner().requiredPlayerRange = reset ? 16 : -1;
}
private static final class TileEntityChunkLoader extends TileEntity implements ITickable, ITileEntityChunkLoader {
private static final Map<Long, TileEntityChunkLoader> tileEntityChunkLoaderMap = new HashMap<>();
private final List<EntityHolograms_v1_16_R3> holograms = new ArrayList<>();
private final WChunkLoader chunkLoader;
private short currentTick = 20;
private short daysAmount, hoursAmount, minutesAmount, secondsAmount;
private boolean removed = false;
TileEntityChunkLoader(ChunkLoader chunkLoader, World world, BlockPosition blockPosition){
super(TileEntityTypes.COMMAND_BLOCK);
this.chunkLoader = (WChunkLoader) chunkLoader;
setLocation(world, blockPosition);
if(!this.chunkLoader.isInfinite()) {
long timeLeft = chunkLoader.getTimeLeft();
daysAmount = (short) (timeLeft / 86400);
timeLeft = timeLeft % 86400;
hoursAmount = (short) (timeLeft / 3600);
timeLeft = timeLeft % 3600;
minutesAmount = (short) (timeLeft / 60);
timeLeft = timeLeft % 60;
secondsAmount = (short) timeLeft;
}
tileEntityChunkLoaderMap.put(ChunkCoordIntPair.pair(blockPosition.getX() >> 4, blockPosition.getZ() >> 4), this);
List<String> hologramLines = this.chunkLoader.getHologramLines();
double currentY = position.getY() + 1;
for(int i = hologramLines.size(); i > 0; i--){
EntityHolograms_v1_16_R3 hologram = new EntityHolograms_v1_16_R3(world, position.getX() + 0.5, currentY, position.getZ() + 0.5);
updateName(hologram, hologramLines.get(i - 1));
world.addEntity(hologram);
currentY += 0.23;
holograms.add(hologram);
}
}
@Override
public void w() {
tick();
}
@Override
public void tick() {
if(removed || ++currentTick <= 20)
return;
currentTick = 0;
if(chunkLoader.isNotActive()){
chunkLoader.remove();
return;
}
if(chunkLoader.isInfinite())
return;
List<String> hologramLines = chunkLoader.getHologramLines();
int hologramsAmount = holograms.size();
for (int i = hologramsAmount; i > 0; i--) {
EntityHolograms_v1_16_R3 hologram = holograms.get(hologramsAmount - i);
updateName(hologram, hologramLines.get(i - 1));
}
chunkLoader.tick();
if(!removed) {
secondsAmount--;
if (secondsAmount < 0) {
secondsAmount = 59;
minutesAmount--;
if (minutesAmount < 0) {
minutesAmount = 59;
hoursAmount--;
if (hoursAmount < 0) {
hoursAmount = 23;
daysAmount--;
}
}
}
}
}
@Override
public Collection<Hologram> getHolograms() {
return Collections.unmodifiableList(holograms);
}
private void updateName(EntityHolograms_v1_16_R3 hologram, String line){
assert chunkLoader.getWhoPlaced().getName() != null;
hologram.setHologramName(line
.replace("{0}", chunkLoader.getWhoPlaced().getName())
.replace("{1}", daysAmount + "")
.replace("{2}", hoursAmount + "")
.replace("{3}", minutesAmount + "")
.replace("{4}", secondsAmount + "")
);
}
}
}