diff --git a/build.gradle b/build.gradle index 38e07fd..f653a14 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ repositories { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' - compile 'org.spigotmc:spigot:1.16.1-R0.1-SNAPSHOT' + compile 'org.spigotmc:spigot:1.16.3-R0.1-SNAPSHOT' } import org.apache.tools.ant.filters.ReplaceTokens diff --git a/src/main/java/nl/kallestruik/vanillatweaks/VanillaTweaks.java b/src/main/java/nl/kallestruik/vanillatweaks/VanillaTweaks.java index 168145b..094e750 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/VanillaTweaks.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/VanillaTweaks.java @@ -5,13 +5,9 @@ import nl.kallestruik.vanillatweaks.commands.CommandToggletrample; import nl.kallestruik.vanillatweaks.core.TweakManager; import nl.kallestruik.vanillatweaks.core.TweakStates; import nl.kallestruik.vanillatweaks.tweaks.craftingtweaks.*; -import nl.kallestruik.vanillatweaks.tweaks.croptweaks.MobsCantTrampleCrops; -import nl.kallestruik.vanillatweaks.tweaks.croptweaks.PlayersCantTrampleCrops; +import nl.kallestruik.vanillatweaks.tweaks.croptweaks.*; import nl.kallestruik.vanillatweaks.tweaks.dispensertweaks.DispensersCanPlantSaplings; -import nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks.ArmorStandArmorSwapping; -import nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks.HoesHarvestArea; -import nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks.LilypadBonemealing; -import nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks.SeedDropPlanting; +import nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks.*; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; @@ -30,6 +26,7 @@ public final class VanillaTweaks extends JavaPlugin { * Commands */ getCommand("toggletrample").setExecutor(new CommandToggletrample()); + getCommand("player").setExecutor(new CommandPlayer()); /* * Crafting Tweaks @@ -59,6 +56,7 @@ public final class VanillaTweaks extends JavaPlugin { * Miscellaneous Tweaks */ TweakManager.registerTweak(new ArmorStandArmorSwapping(), this); + TweakManager.registerTweak(new FakePlayers(), this); TweakManager.registerTweak(new HoesHarvestArea(), this); TweakManager.registerTweak(new LilypadBonemealing(), this); TweakManager.registerTweak(new SeedDropPlanting(), this); diff --git a/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandPlayer.java b/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandPlayer.java new file mode 100644 index 0000000..71c956c --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandPlayer.java @@ -0,0 +1,33 @@ +package nl.kallestruik.vanillatweaks.commands; + +import nl.kallestruik.vanillatweaks.fakeplayer.FakePlayerManager; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class CommandPlayer implements CommandExecutor { + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) + return false; + + if (args.length < 2) + return false; + + Player player = ((Player) sender); + Location loc = player.getLocation(); + + switch (args[1]) { + case "spawn": + FakePlayerManager.spawnFakePlayer(loc, args[0]); + break; + case "kill": + FakePlayerManager.killFakePlayer(args[0]); + break; + } + + return true; + } +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandToggletrample.java b/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandToggletrample.java index 7958418..1090419 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandToggletrample.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/commands/CommandToggletrample.java @@ -19,10 +19,10 @@ public class CommandToggletrample implements CommandExecutor { Player player = (Player) sender; if (PlayersCantTrampleCrops.trampleEnabled.remove(player.getUniqueId())) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2Crop Trampling: &2&lEnabled")); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2Crop Trampling: &4&lDisabled")); } else { PlayersCantTrampleCrops.trampleEnabled.add(player.getUniqueId()); - player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2Crop Trampling: &4&lDisabled")); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2Crop Trampling: &2&lEnabled")); } return true; } diff --git a/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakeConnection.java b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakeConnection.java new file mode 100644 index 0000000..a6548c2 --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakeConnection.java @@ -0,0 +1,39 @@ +package nl.kallestruik.vanillatweaks.fakeplayer; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.minecraft.server.v1_16_R2.EnumProtocolDirection; +import net.minecraft.server.v1_16_R2.NetworkManager; +import net.minecraft.server.v1_16_R2.Packet; + +import javax.annotation.Nullable; + +public class FakeConnection extends NetworkManager { + public boolean open = true; + + public FakeConnection(EnumProtocolDirection enumprotocoldirection) { + super(enumprotocoldirection); + } + + // isOpen() + @Override + public boolean isConnected() { + return this.open; + } + + // hasChannel() + @Override + public boolean i() { + return false; + } + + @Override + public void sendPacket(Packet packet, @Nullable GenericFutureListener> genericfuturelistener) {} + + // disableAutoRead() + @Override + public void stopReading() {} + + @Override + public void handleDisconnection() {} +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayer.java b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayer.java new file mode 100644 index 0000000..9bf7a3b --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayer.java @@ -0,0 +1,157 @@ +package nl.kallestruik.vanillatweaks.fakeplayer; + +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_16_R2.*; + +import nl.kallestruik.vanillatweaks.util.ReflectionUtil; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; + +import javax.annotation.Nullable; +import java.util.List; + +public class FakePlayer extends EntityPlayer { + private boolean hasStartingPos; + private double startingX, startingY, startingZ; + private float startingYaw, startingPitch; + + public FakePlayer(MinecraftServer minecraftserver, WorldServer worldserver, GameProfile gameprofile, PlayerInteractManager playerinteractmanager) { + super(minecraftserver, worldserver, gameprofile, playerinteractmanager); + this.hasStartingPos = false; + } + + private FakePlayer(MinecraftServer server, WorldServer worldIn, GameProfile profile, PlayerInteractManager interactionManagerIn, double x, double y, double z, float yaw, float pitch) { + super(server, worldIn, profile, interactionManagerIn); + this.hasStartingPos = true; + this.startingX = x; + this.startingY = y; + this.startingZ = z; + this.startingYaw = yaw; + this.startingPitch = pitch; + } + + @Nullable + public static FakePlayer atLocation(Location location, String name) { + // Split the location into its parts for use later. + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + double yaw = location.getYaw(); + double pitch = location.getPitch(); + + try { + // Get the minecraft server instance. + MinecraftServer minecraftServer = MinecraftServer.getServer(); + // Create an empty variable for the world server. + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + // Get the game profile from the cache (or retrieve it if it is not cached) + GameProfile gameProfile = minecraftServer.getUserCache().getProfile(name); + + if (gameProfile == null) { + return null; + } + if (gameProfile.getProperties().containsKey("textures")) { + gameProfile = TileEntitySkull.b(gameProfile, null, true).get(); + } + + // Create a player interact manager using the world server. + PlayerInteractManager playerInteractManager = new PlayerInteractManager(worldServer); + + // Create an instance of our fake player. + FakePlayer instance = new FakePlayer(minecraftServer, worldServer, gameProfile, playerInteractManager, x, y, z, (float) yaw, (float) pitch); + // Create a fake connection for our fake player. + FakeConnection connection = new FakeConnection(EnumProtocolDirection.SERVERBOUND); + + // Set access to connected channels so we can add our own connection. + ServerConnection serverConnection = minecraftServer.getServerConnection(); + ((List) ReflectionUtil.getValueFromField(serverConnection, "connectedChannels")).add(connection); + + // Connect the fake player to the server using the fake connection. + FakePlayerList.a(minecraftServer.getPlayerList(), connection, instance); + + // Check if the fake player is not yet in the correct world. + if (!instance.world.getDimensionKey().equals(worldServer.getDimensionKey())) { + // Store the old world of the fake player. + WorldServer old_world = (WorldServer) instance.world; + // Remove the fake player from the old world. + old_world.removePlayer(instance); + // Make the fake player not be dead. + instance.dead = false; + // Create the fake player in the new world. + worldServer.addEntity(instance); + // Spawn the fake player in the new world. + instance.spawnIn(worldServer); + // Move the fake player to the new world for the server. + minecraftServer.getPlayerList().moveToWorld(instance, old_world, true, null, false); + // requestTeleport(x, y, z, yaw, pitch) + // Request the teleport from the fake player. + instance.playerConnection.a(x, y, z, (float) yaw, (float) pitch); + // Set the fake player's world to the new world. + instance.playerInteractManager.world = worldServer; + } + + /// Set the fake players health to max. + instance.setHealth(20.0F); + // Make the fake player not be dead. + instance.dead = false; + // a == requestTeleport + // Request the teleport from the fake player. + instance.playerConnection.a(x, y, z, (float) yaw, (float) pitch); + // G == stepHeight + // Set the fake players step height to 0.6 (The normal value). + instance.G = 0.6F; + // Set the fake players gamemode to survival. + playerInteractManager.setGameMode(EnumGamemode.SURVIVAL); + // Tell everyone in the world about the fake player and where he is. + minecraftServer.getPlayerList().a(new PacketPlayOutEntityHeadRotation(instance, (byte) (instance.yaw * 256 / 360)), instance.world.getDimensionKey()); + minecraftServer.getPlayerList().a(new PacketPlayOutEntityTeleport(instance), instance.world.getDimensionKey()); + // Move the fake player for the worlds chunk provider. + instance.getWorldServer().getChunkProvider().movePlayer(instance); + // bp == PLAYER_MODEL_PARTS + instance.datawatcher.set(bj, (byte) 0x7f); // show all model layers (incl. capes) + + return instance; + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public void applyStartingPosition() { + if (hasStartingPos) { + this.setPositionRotation(startingX, startingY, startingZ, startingYaw, startingPitch); + this.setMot(new Vec3D(0, 0, 0)); + } + } + + + + @Override + public void killEntity() { + this.server.a(new TickTask(this.server.ah(), () -> { + this.playerConnection.a(new ChatComponentText("Killed")); + })); + } + + @Override + public void tick() { + super.tick(); + if (this.H()) { + this.I(); + } + this.movementTick(); + if (this.server.ah() % 10 == 0) { + this.playerConnection.syncPosition(); + this.getWorldServer().getChunkProvider().movePlayer(this); + } + } + + @Override + public void die(DamageSource cause) { + super.die(cause); + setHealth(20); + this.foodData = new FoodMetaData(this); + killEntity(); + } +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerConnection.java b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerConnection.java new file mode 100644 index 0000000..eb3e038 --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerConnection.java @@ -0,0 +1,50 @@ +package nl.kallestruik.vanillatweaks.fakeplayer; + +import net.minecraft.server.v1_16_R2.*; +import nl.kallestruik.vanillatweaks.util.ReflectionUtil; + +import java.lang.reflect.Field; + +public class FakePlayerConnection extends PlayerConnection { + + public FakePlayerConnection(MinecraftServer minecraftserver, NetworkManager networkmanager, EntityPlayer entityplayer) { + super(minecraftserver, networkmanager, entityplayer); + } + + @Override + public void tick() { + super.tick(); + } + + @Override + public void sendPacket(final Packet packet) { + if (packet instanceof PacketPlayOutKeepAlive) { + PacketPlayOutKeepAlive ping = (PacketPlayOutKeepAlive) packet; + PacketPlayInKeepAlive pong = new PacketPlayInKeepAlive(); + try { + Field pingId = ReflectionUtil.getField(PacketPlayOutKeepAlive.class, "a"); + Field pongId = ReflectionUtil.getField(PacketPlayInKeepAlive.class, "a"); + + pingId.setAccessible(true); + pongId.setAccessible(true); + + pongId.set(pong, pingId.get(ping)); + } catch (Exception e) { + e.printStackTrace(); + } + + this.a(pong); + } + } + + @Override + public void disconnect(String message) { + player.killEntity(); + } + + @Override + public void a(IChatBaseComponent text_1) { + super.a(text_1); + ((FakeConnection) this.a()).open = false; + } +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerList.java b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerList.java new file mode 100644 index 0000000..ffcd870 --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerList.java @@ -0,0 +1,240 @@ +package nl.kallestruik.vanillatweaks.fakeplayer; + +import com.mojang.authlib.GameProfile; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import io.netty.buffer.Unpooled; +import net.minecraft.server.v1_16_R2.*; +import nl.kallestruik.vanillatweaks.util.ReflectionUtil; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R2.CraftServer; +import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_16_R2.util.CraftChatMessage; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerJoinEvent; +import org.spigotmc.event.player.PlayerSpawnLocationEvent; + +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +public class FakePlayerList { + + public static void a(PlayerList playerList, NetworkManager networkmanager, EntityPlayer entityplayer) { + MinecraftServer server = ((MinecraftServer) ReflectionUtil.getValueFromField(playerList, "server")); + Logger LOGGER = ((Logger) ReflectionUtil.getValueFromField(playerList, "LOGGER")); + + GameProfile gameprofile = entityplayer.getProfile(); + UserCache usercache = server.getUserCache(); + GameProfile gameprofile1 = usercache.getProfile(gameprofile.getId()); + String s = gameprofile1 == null ? gameprofile.getName() : gameprofile1.getName(); + usercache.a(gameprofile); + NBTTagCompound nbttagcompound = playerList.a(entityplayer); + if (nbttagcompound != null && nbttagcompound.hasKey("bukkit")) { + NBTTagCompound bukkit = nbttagcompound.getCompound("bukkit"); + s = bukkit.hasKeyOfType("lastKnownName", 8) ? bukkit.getString("lastKnownName") : s; + } + + ResourceKey resourcekey; + if (nbttagcompound != null) { + DataResult dataresult = DimensionManager.a(new Dynamic(DynamicOpsNBT.a, nbttagcompound.get("Dimension"))); + Logger logger = LOGGER; + logger.getClass(); + logger.getClass(); + resourcekey = (ResourceKey)dataresult.resultOrPartial(logger::error).orElse(World.OVERWORLD); + } else { + resourcekey = World.OVERWORLD; + } + + WorldServer worldserver = server.getWorldServer(resourcekey); + WorldServer[] worldserver1 = new WorldServer[1]; + if (worldserver == null) { + LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourcekey); + worldserver1[0] = server.E(); + } else { + worldserver1[0] = worldserver; + } + + entityplayer.spawnIn(worldserver1[0]); + entityplayer.playerInteractManager.a((WorldServer)entityplayer.world); + String s1 = "local"; + if (networkmanager.getSocketAddress() != null) { + s1 = networkmanager.getSocketAddress().toString(); + } + + Player bukkitPlayer = entityplayer.getBukkitEntity(); + PlayerSpawnLocationEvent ev = new PlayerSpawnLocationEvent(bukkitPlayer, bukkitPlayer.getLocation()); + Bukkit.getPluginManager().callEvent(ev); + Location loc = ev.getSpawnLocation(); + worldserver1[0] = ((CraftWorld)loc.getWorld()).getHandle(); + entityplayer.spawnIn(worldserver1[0]); + entityplayer.playerInteractManager.a((WorldServer)entityplayer.world); + entityplayer.setPosition(loc.getX(), loc.getY(), loc.getZ()); + + //entityplayer.setYawPitch(loc.getYaw(), loc.getPitch()); + try { + Method setYawPitch = Entity.class.getDeclaredMethod("setYawPitch", float.class, float.class); + setYawPitch.setAccessible(true); + setYawPitch.invoke(entityplayer, loc.getYaw(), loc.getPitch()); + } catch (Exception e) { + e.printStackTrace(); + } + + WorldData worlddata = worldserver1[0].getWorldData(); + + //playerList.a(entityplayer, (EntityPlayer)null, worldserver1); + try { + Method a = PlayerList.class.getDeclaredMethod("a", EntityPlayer.class, EntityPlayer.class, WorldServer.class); + a.setAccessible(true); + a.invoke(playerList, entityplayer, null, worldserver1[0]); + } catch (Exception e) { + e.printStackTrace(); + } + + //PlayerConnection playerconnection = new PlayerConnection(server, networkmanager, entityplayer); + PlayerConnection playerconnection; + if (entityplayer instanceof FakePlayer) { + playerconnection = new FakePlayerConnection(server, networkmanager, entityplayer); + } else { + playerconnection = new PlayerConnection(server, networkmanager, entityplayer); + } + + GameRules gamerules = worldserver1[0].getGameRules(); + boolean flag = gamerules.getBoolean(GameRules.DO_IMMEDIATE_RESPAWN); + boolean flag1 = gamerules.getBoolean(GameRules.REDUCED_DEBUG_INFO); + + try { + playerconnection.sendPacket(new PacketPlayOutLogin(entityplayer.getId(), entityplayer.playerInteractManager.getGameMode(), entityplayer.playerInteractManager.c(), BiomeManager.a(worldserver1[0].getSeed()), worlddata.isHardcore(), server.F(), ((IRegistryCustom.Dimension) ReflectionUtil.getValueFromField(playerList, "s")), worldserver1[0].getDimensionManager(), worldserver1[0].getDimensionKey(), playerList.getMaxPlayers(), worldserver1[0].spigotConfig.viewDistance, flag1, !flag, worldserver1[0].isDebugWorld(), worldserver1[0].isFlatWorld())); + } catch (Exception e) { + e.printStackTrace(); + } + + entityplayer.getBukkitEntity().sendSupportedChannels(); + playerconnection.sendPacket(new PacketPlayOutCustomPayload(PacketPlayOutCustomPayload.a, (new PacketDataSerializer(Unpooled.buffer())).a(playerList.getServer().getServerModName()))); + playerconnection.sendPacket(new PacketPlayOutServerDifficulty(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); + playerconnection.sendPacket(new PacketPlayOutAbilities(entityplayer.abilities)); + playerconnection.sendPacket(new PacketPlayOutHeldItemSlot(entityplayer.inventory.itemInHandIndex)); + playerconnection.sendPacket(new PacketPlayOutRecipeUpdate(server.getCraftingManager().b())); + playerconnection.sendPacket(new PacketPlayOutTags(server.getTagRegistry())); + playerList.d(entityplayer); + entityplayer.getStatisticManager().c(); + entityplayer.getRecipeBook().a(entityplayer); + playerList.sendScoreboard(worldserver1[0].getScoreboard(), entityplayer); + server.invalidatePingSample(); + ChatMessage chatmessage; + if (entityplayer.getProfile().getName().equalsIgnoreCase(s)) { + chatmessage = new ChatMessage("multiplayer.player.joined", new Object[]{entityplayer.getScoreboardDisplayName()}); + } else { + chatmessage = new ChatMessage("multiplayer.player.joined.renamed", new Object[]{entityplayer.getScoreboardDisplayName(), s}); + } + + chatmessage.a(EnumChatFormat.YELLOW); + String joinMessage = CraftChatMessage.fromComponent(chatmessage); + playerconnection.a(entityplayer.locX(), entityplayer.locY(), entityplayer.locZ(), entityplayer.yaw, entityplayer.pitch); + playerList.players.add(entityplayer); + + //playerList.playersByName.put(entityplayer.getName().toLowerCase(Locale.ROOT), entityplayer); + ((Map) ReflectionUtil.getValueFromField(playerList, "playersByName")).put(entityplayer.getName().toLowerCase(Locale.ROOT), entityplayer); + + //playerList.j.put(entityplayer.getUniqueID(), entityplayer); + ((Map) ReflectionUtil.getValueFromField(playerList, "j")).put(entityplayer.getUniqueID(), entityplayer); + + PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(((CraftServer) Bukkit.getServer()).getPlayer(entityplayer), joinMessage); + Bukkit.getServer().getPluginManager().callEvent(playerJoinEvent); + if (entityplayer.playerConnection.networkManager.isConnected()) { + joinMessage = playerJoinEvent.getJoinMessage(); + int i; + if (joinMessage != null && joinMessage.length() > 0) { + IChatBaseComponent[] var27; + int var26 = (var27 = CraftChatMessage.fromString(joinMessage)).length; + + for(i = 0; i < var26; ++i) { + IChatBaseComponent line = var27[i]; + server.getPlayerList().sendAll(new PacketPlayOutChat(line, ChatMessageType.SYSTEM, SystemUtils.b)); + } + } + + PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer}); + + for(i = 0; i < playerList.players.size(); ++i) { + EntityPlayer entityplayer1 = (EntityPlayer)playerList.players.get(i); + if (entityplayer1.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) { + entityplayer1.playerConnection.sendPacket(packet); + } + + if (entityplayer.getBukkitEntity().canSee(entityplayer1.getBukkitEntity())) { + entityplayer.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer1})); + } + } + + entityplayer.sentListPacket = true; + entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityMetadata(entityplayer.getId(), ((DataWatcher) ReflectionUtil.getValueFromField(entityplayer, "datawatcher")), true)); + if (entityplayer.world == worldserver1[0] && !worldserver1[0].getPlayers().contains(entityplayer)) { + worldserver1[0].addPlayerJoin(entityplayer); + server.getBossBattleCustomData().a(entityplayer); + } + + worldserver1[0] = entityplayer.getWorldServer(); + playerList.a(entityplayer, worldserver1[0]); + if (!server.getResourcePack().isEmpty()) { + entityplayer.setResourcePack(server.getResourcePack(), server.getResourcePackHash()); + } + + Iterator iterator = entityplayer.getEffects().iterator(); + + while(iterator.hasNext()) { + MobEffect mobeffect = (MobEffect)iterator.next(); + playerconnection.sendPacket(new PacketPlayOutEntityEffect(entityplayer.getId(), mobeffect)); + } + + if (nbttagcompound != null && nbttagcompound.hasKeyOfType("RootVehicle", 10)) { + NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("RootVehicle"); + Entity entity = EntityTypes.a(nbttagcompound1.getCompound("Entity"), worldserver1[0], (entity1x) -> { + return !worldserver1[0].addEntitySerialized(entity1x) ? null : entity1x; + }); + if (entity != null) { + UUID uuid; + if (nbttagcompound1.b("Attach")) { + uuid = nbttagcompound1.a("Attach"); + } else { + uuid = null; + } + + Iterator iterator1; + Entity entity1; + if (entity.getUniqueID().equals(uuid)) { + entityplayer.a(entity, true); + } else { + iterator1 = entity.getAllPassengers().iterator(); + + while(iterator1.hasNext()) { + entity1 = (Entity)iterator1.next(); + if (entity1.getUniqueID().equals(uuid)) { + entityplayer.a(entity1, true); + break; + } + } + } + + if (!entityplayer.isPassenger()) { + LOGGER.warn("Couldn't reattach entity to player"); + worldserver1[0].removeEntity(entity); + iterator1 = entity.getAllPassengers().iterator(); + + while(iterator1.hasNext()) { + entity1 = (Entity)iterator1.next(); + worldserver1[0].removeEntity(entity1); + } + } + } + } + + entityplayer.syncInventory(); + LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", entityplayer.getDisplayName().getString(), s1, entityplayer.getId(), worldserver1[0].worldDataServer.getName(), entityplayer.locX(), entityplayer.locY(), entityplayer.locZ()); + } + } +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerManager.java b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerManager.java new file mode 100644 index 0000000..34e0014 --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/fakeplayer/FakePlayerManager.java @@ -0,0 +1,44 @@ +package nl.kallestruik.vanillatweaks.fakeplayer; + +import net.minecraft.server.v1_16_R2.EntityPlayer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class FakePlayerManager { + + public static void spawnFakePlayer(Location loc, String name) { + Player player = Bukkit.getPlayer(name); + if (player != null && player.isOnline()) + return; + + FakePlayer.atLocation(loc, name); + } + + public static void killFakePlayer(String name) { + Player player = Bukkit.getPlayer(name); + if (player == null || !player.isOnline()) + return; + + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + + if (!(entityPlayer instanceof FakePlayer)) + return; + + entityPlayer.killEntity(); + } + + public static void killAllFakePlayers() { + for (Player player : Bukkit.getOnlinePlayers()) { + if (!player.isOnline()) + continue; + + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + if (!(entityPlayer instanceof FakePlayer)) + continue; + + entityPlayer.killEntity(); + } + } +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/AlternativeDispenserRecipe.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/AlternativeDispenserRecipe.java index 20e1e54..a4d75ce 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/AlternativeDispenserRecipe.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/AlternativeDispenserRecipe.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -33,6 +34,8 @@ public class AlternativeDispenserRecipe implements Tweak { dispenserRecipe.setIngredient('T', Material.STICK); dispenserRecipe.setIngredient('D', Material.DROPPER); dispenserRecipe.setIngredient('S', Material.STRING); + + Bukkit.getServer().addRecipe(dispenserRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableDragonsBreath.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableDragonsBreath.java index 89d4062..72d870e 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableDragonsBreath.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableDragonsBreath.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,6 +33,8 @@ public class CraftableDragonsBreath implements Tweak { dragonBreathRecipe.shape("GCG", " G "); dragonBreathRecipe.setIngredient('G', Material.GLASS); dragonBreathRecipe.setIngredient('C', Material.POPPED_CHORUS_FRUIT); + + Bukkit.getServer().addRecipe(dragonBreathRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableNametag.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableNametag.java index 00fdb9e..8a367c0 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableNametag.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableNametag.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,6 +33,8 @@ public class CraftableNametag implements Tweak { nametagRecipe.shape(" I", " P ", "P "); nametagRecipe.setIngredient('I', Material.IRON_INGOT); nametagRecipe.setIngredient('P', Material.PAPER); + + Bukkit.getServer().addRecipe(nametagRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSaddle.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSaddle.java index f875805..33b96f3 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSaddle.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSaddle.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -33,6 +34,8 @@ public class CraftableSaddle implements Tweak { saddleRecipe.setIngredient('L', Material.LEATHER); saddleRecipe.setIngredient('S', Material.STRING); saddleRecipe.setIngredient('I', Material.IRON_INGOT); + + Bukkit.getServer().addRecipe(saddleRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableShulkerShell.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableShulkerShell.java index 3b9fce6..5c16545 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableShulkerShell.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableShulkerShell.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,6 +33,8 @@ public class CraftableShulkerShell implements Tweak { shulkerShellRecipe.shape("BBB","F F"); shulkerShellRecipe.setIngredient('B', Material.PURPUR_SLAB); shulkerShellRecipe.setIngredient('F', Material.POPPED_CHORUS_FRUIT); + + Bukkit.getServer().addRecipe(shulkerShellRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSponge.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSponge.java index b26d798..7b01081 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSponge.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/CraftableSponge.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,6 +33,8 @@ public class CraftableSponge implements Tweak { spongeRecipe.shape("KKK","KDK","KKK"); spongeRecipe.setIngredient('K', Material.KELP); spongeRecipe.setIngredient('D', Material.YELLOW_DYE); + + Bukkit.getServer().addRecipe(spongeRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/IceDecompression.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/IceDecompression.java index 9c48968..87c7016 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/IceDecompression.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/IceDecompression.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,10 +33,14 @@ public class IceDecompression implements Tweak { ShapelessRecipe packedIceRecipe = new ShapelessRecipe(packedIceKey, new ItemStack(Material.PACKED_ICE, 9)); packedIceRecipe.addIngredient(Material.BLUE_ICE); + Bukkit.getServer().addRecipe(packedIceRecipe); + // Packed Ice -> Ice NamespacedKey iceKey = new NamespacedKey(plugin, "ice"); ShapelessRecipe iceRecipe = new ShapelessRecipe(iceKey, new ItemStack(Material.ICE, 9)); iceRecipe.addIngredient(Material.PACKED_ICE); + + Bukkit.getServer().addRecipe(iceRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/LogsToChests.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/LogsToChests.java index f0806dc..d7223f4 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/LogsToChests.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/LogsToChests.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,6 +33,8 @@ public class LogsToChests implements Tweak { ShapedRecipe chestRecipe = new ShapedRecipe(chestKey, new ItemStack(Material.CHEST, 4)); chestRecipe.shape("WWW", "W W", "WWW"); chestRecipe.setIngredient('W', MaterialGroups.ALL_LOG); + + Bukkit.getServer().addRecipe(chestRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/MaterialGroups.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/MaterialGroups.java index 1140a74..556dbd0 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/MaterialGroups.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/MaterialGroups.java @@ -8,23 +8,33 @@ public class MaterialGroups { Material.OAK_LOG, Material.STRIPPED_OAK_LOG, Material.OAK_WOOD, + Material.STRIPPED_OAK_WOOD, Material.BIRCH_LOG, Material.STRIPPED_BIRCH_LOG, Material.BIRCH_WOOD, + Material.STRIPPED_BIRCH_WOOD, Material.SPRUCE_LOG, Material.STRIPPED_SPRUCE_LOG, Material.SPRUCE_WOOD, + Material.STRIPPED_SPRUCE_WOOD, Material.JUNGLE_LOG, Material.STRIPPED_JUNGLE_LOG, Material.JUNGLE_WOOD, + Material.STRIPPED_JUNGLE_WOOD, Material.ACACIA_LOG, Material.STRIPPED_ACACIA_LOG, Material.ACACIA_WOOD, + Material.STRIPPED_ACACIA_WOOD, Material.DARK_OAK_LOG, Material.STRIPPED_DARK_OAK_LOG, Material.DARK_OAK_WOOD, + Material.STRIPPED_DARK_OAK_WOOD, + Material.CRIMSON_STEM, + Material.STRIPPED_CRIMSON_STEM, Material.CRIMSON_HYPHAE, Material.STRIPPED_CRIMSON_HYPHAE, + Material.WARPED_STEM, + Material.STRIPPED_WARPED_STEM, Material.WARPED_HYPHAE, Material.STRIPPED_WARPED_HYPHAE); public static final RecipeChoice ALL_WOOL = new RecipeChoice.MaterialChoice( diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/WoolToString.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/WoolToString.java index 32147d0..d9435ef 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/WoolToString.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/craftingtweaks/WoolToString.java @@ -1,6 +1,7 @@ package nl.kallestruik.vanillatweaks.tweaks.craftingtweaks; import nl.kallestruik.vanillatweaks.core.Tweak; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -30,6 +31,8 @@ public class WoolToString implements Tweak { NamespacedKey stringKey = new NamespacedKey(plugin, "string"); ShapelessRecipe stringRecipe = new ShapelessRecipe(stringKey, new ItemStack(Material.STRING, 4)); stringRecipe.addIngredient(MaterialGroups.ALL_WOOL); + + Bukkit.getServer().addRecipe(stringRecipe); } @Override diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/HoesHarvestArea.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/HoesHarvestArea.java similarity index 97% rename from src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/HoesHarvestArea.java rename to src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/HoesHarvestArea.java index 9472a87..4e151b1 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/HoesHarvestArea.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/HoesHarvestArea.java @@ -1,4 +1,4 @@ -package nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks; +package nl.kallestruik.vanillatweaks.tweaks.croptweaks; import nl.kallestruik.vanillatweaks.core.Tweak; import org.bukkit.*; diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/LilypadBonemealing.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/LilypadBonemealing.java similarity index 97% rename from src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/LilypadBonemealing.java rename to src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/LilypadBonemealing.java index 0f296d1..60483ae 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/LilypadBonemealing.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/LilypadBonemealing.java @@ -1,4 +1,4 @@ -package nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks; +package nl.kallestruik.vanillatweaks.tweaks.croptweaks; import nl.kallestruik.vanillatweaks.util.Util; import nl.kallestruik.vanillatweaks.core.Tweak; diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/PlayersCantTrampleCrops.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/PlayersCantTrampleCrops.java index cab31e4..951fe49 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/PlayersCantTrampleCrops.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/PlayersCantTrampleCrops.java @@ -67,6 +67,9 @@ public class PlayersCantTrampleCrops implements Tweak, Listener { if (!(event.getEntity() instanceof Player)) return; + if (trampleEnabled.contains(event.getEntity().getUniqueId())) + return; + event.setCancelled(true); } diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/SeedDropPlanting.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/SeedDropPlanting.java similarity index 97% rename from src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/SeedDropPlanting.java rename to src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/SeedDropPlanting.java index 2ef482c..71570e1 100644 --- a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/SeedDropPlanting.java +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/croptweaks/SeedDropPlanting.java @@ -1,4 +1,4 @@ -package nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks; +package nl.kallestruik.vanillatweaks.tweaks.croptweaks; import nl.kallestruik.vanillatweaks.core.Tweak; import org.bukkit.*; diff --git a/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/FakePlayers.java b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/FakePlayers.java new file mode 100644 index 0000000..2f9935e --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/tweaks/miscellaneoustweaks/FakePlayers.java @@ -0,0 +1,33 @@ +package nl.kallestruik.vanillatweaks.tweaks.miscellaneoustweaks; + +import nl.kallestruik.vanillatweaks.core.Tweak; +import nl.kallestruik.vanillatweaks.fakeplayer.FakePlayerManager; +import org.bukkit.plugin.java.JavaPlugin; + +public class FakePlayers implements Tweak { + + @Override + public String getIdentifier() { + return "FakePlayers"; + } + + @Override + public void onRegister(JavaPlugin pluginInstance) { + + } + + @Override + public void onUnRegister() { + + } + + @Override + public void onEnable() { + + } + + @Override + public void onDisable() { + FakePlayerManager.killAllFakePlayers(); + } +} diff --git a/src/main/java/nl/kallestruik/vanillatweaks/util/ReflectionUtil.java b/src/main/java/nl/kallestruik/vanillatweaks/util/ReflectionUtil.java new file mode 100644 index 0000000..5507463 --- /dev/null +++ b/src/main/java/nl/kallestruik/vanillatweaks/util/ReflectionUtil.java @@ -0,0 +1,32 @@ +package nl.kallestruik.vanillatweaks.util; + +import java.lang.reflect.Field; + +public class ReflectionUtil { + + public static Field getField(Class clazz, String fieldName) + throws NoSuchFieldException { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) { + throw e; + } else { + return getField(superClass, fieldName); + } + } + } + + public static Object getValueFromField(Object instance, String fieldName) { + try { + Field connectedChannelsField = getField(instance.getClass(), fieldName); + connectedChannelsField.setAccessible(true); //required if field is not normally accessible + + return connectedChannelsField.get(instance); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/resources/tweak_states.yml b/src/main/resources/tweak_states.yml index c0cc618..d5a6e81 100644 --- a/src/main/resources/tweak_states.yml +++ b/src/main/resources/tweak_states.yml @@ -14,3 +14,4 @@ MobsCantTrampleCrops: true CraftableDragonsBreath: true ArmorSwapping: true HoesHarvestArea: true +FakePlayers: false