feat: add FakePlayer on Disconnect

This commit is contained in:
Simon Giesel 2020-05-04 22:39:01 +02:00
parent fa18a203b1
commit 780e7dc597
4 changed files with 173 additions and 19 deletions

View file

@ -21,18 +21,23 @@ import de.cliffbreak.varo.listeners.PlayerClientOptionsChangeListener;
import de.cliffbreak.varo.listeners.PlayerDeathListener; import de.cliffbreak.varo.listeners.PlayerDeathListener;
import de.cliffbreak.varo.listeners.PlayerJoinQuitListener; import de.cliffbreak.varo.listeners.PlayerJoinQuitListener;
import de.cliffbreak.varo.listeners.PlayerPreLoginListener; import de.cliffbreak.varo.listeners.PlayerPreLoginListener;
import de.cliffbreak.varo.managers.NPCManager;
public class Varo extends JavaPlugin { public class Varo extends JavaPlugin {
public File configurationFile = new File("plugins/CliffbreakVaro", "config.yml"); public File configurationFile = new File("plugins/CliffbreakVaro", "config.yml");
public FileConfiguration config = YamlConfiguration.loadConfiguration(this.configurationFile); public FileConfiguration config = YamlConfiguration.loadConfiguration(this.configurationFile);
public PlayerCache playerCache = new PlayerCache(this); public NPCManager npcManager;
public PlayerCache playerCache;
@Override @Override
public void onEnable() { public void onEnable() {
getLogger().info("CliffbreakVaro is starting..."); getLogger().info("CliffbreakVaro is starting...");
this.npcManager = new NPCManager(this);
this.playerCache = new PlayerCache(this);
// this.config.addDefault("Varo.Start", "TODO: StartDate"); // this.config.addDefault("Varo.Start", "TODO: StartDate");
this.config.addDefault("Varo.Bans", new ArrayList<String>()); this.config.addDefault("Varo.Bans", new ArrayList<String>());
this.config.options().copyDefaults(true); this.config.options().copyDefaults(true);

View file

@ -1,10 +1,6 @@
package de.cliffbreak.varo.commands; package de.cliffbreak.varo.commands;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import com.destroystokyo.paper.Title; import com.destroystokyo.paper.Title;
@ -23,6 +19,7 @@ import org.json.simple.parser.ParseException;
import de.cliffbreak.varo.Varo; import de.cliffbreak.varo.Varo;
import de.cliffbreak.varo.uitls.MessageUtils; import de.cliffbreak.varo.uitls.MessageUtils;
import de.cliffbreak.varo.uitls.WebUtils;
public class VaroCommand implements CommandExecutor { public class VaroCommand implements CommandExecutor {
@ -41,23 +38,13 @@ public class VaroCommand implements CommandExecutor {
if (args.length == 2 && args[0].equals("unban")) { if (args.length == 2 && args[0].equals("unban")) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final ArrayList<String> bans = (ArrayList<String>) this.plugin.config.get("Varo.Bans"); final ArrayList<String> bans = (ArrayList<String>) this.plugin.config.get("Varo.Bans");
String url = "https://api.mojang.com/users/profiles/minecraft/" + args[1];
try { try {
HttpURLConnection connection = ((HttpURLConnection) (new URL(url)).openConnection()); String result = WebUtils.GET("https://api.mojang.com/users/profiles/minecraft/" + args[1]);
connection.setRequestMethod("GET"); if (result.isEmpty()) {
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
connection.disconnect();
if (content.toString().isEmpty()) {
sender.sendMessage("§c§lFehler: §r§cDer Spieler wurde nicht gefunden."); sender.sendMessage("§c§lFehler: §r§cDer Spieler wurde nicht gefunden.");
return true; return true;
} }
JSONObject uuidObject = (JSONObject) JSONValue.parseWithException(content.toString()); JSONObject uuidObject = (JSONObject) JSONValue.parseWithException(result);
if (!bans.contains(uuidObject.get("id").toString())) { if (!bans.contains(uuidObject.get("id").toString())) {
sender.sendMessage("§c§lFehler: §r§cDer Spieler ist nicht gebannt."); sender.sendMessage("§c§lFehler: §r§cDer Spieler ist nicht gebannt.");
return true; return true;
@ -66,7 +53,7 @@ public class VaroCommand implements CommandExecutor {
this.plugin.config.set("Varo.Bans", bans); this.plugin.config.set("Varo.Bans", bans);
this.plugin.saveConfiguration(); this.plugin.saveConfiguration();
sender.sendMessage("§a§lErfolg: §r§aDer Spieler ist nun nicht mehr gebannt."); sender.sendMessage("§a§lErfolg: §r§aDer Spieler ist nun nicht mehr gebannt.");
} catch (ParseException | IOException e) { } catch (IOException | ParseException e) {
sender.sendMessage( sender.sendMessage(
"§c§lFehler:§r§c beim Verbinden mit der Mojang-API ist ein Fehler aufgetreten. Eventuell sind die Mojang Server down."); "§c§lFehler:§r§c beim Verbinden mit der Mojang-API ist ein Fehler aufgetreten. Eventuell sind die Mojang Server down.");
e.printStackTrace(); e.printStackTrace();
@ -94,11 +81,30 @@ public class VaroCommand implements CommandExecutor {
sender.sendMessage(MessageUtils.getRichTextComponent("§9" + "Team 08", "")); sender.sendMessage(MessageUtils.getRichTextComponent("§9" + "Team 08", ""));
sender.sendMessage(MessageUtils.getRichTextComponent("§d" + "Team 09", "")); sender.sendMessage(MessageUtils.getRichTextComponent("§d" + "Team 09", ""));
sender.sendMessage(MessageUtils.getRichTextComponent("§5" + "Team 10", "")); sender.sendMessage(MessageUtils.getRichTextComponent("§5" + "Team 10", ""));
} else if (args.length == 1 && args[0].equals("test")) {
if (sender instanceof Player) {
try {
plugin.npcManager.createClone((Player) sender, false);
} catch (IOException e) {
sender.sendMessage(
"§c§lFehler:§r§c beim Verbinden mit der Mojang-API ist ein Fehler aufgetreten. Eventuell sind die Mojang Server down.");
}
} else {
sender.sendMessage("§c§lFehler:§r§c Dieses Kommando kann nur durch einen Spieler ausgeführt werden.");
}
} else if (args.length == 1 && args[0].equals("testremove")) {
if (sender instanceof Player) {
plugin.npcManager.removeClone(((Player) sender));
} else {
sender.sendMessage("§c§lFehler:§r§c Dieses Kommando kann nur durch einen Spieler ausgeführt werden.");
}
} else { } else {
sender.sendMessage("\n§6========== §b§lCliffbreak.de VARO §r§6============\n "); sender.sendMessage("\n§6========== §b§lCliffbreak.de VARO §r§6============\n ");
sender.sendMessage("§a/varo start: §rStarte das Varo Projekt!"); sender.sendMessage("§a/varo start: §rStarte das Varo Projekt!");
sender.sendMessage("§a/varo unban [Spieler]: §rSpieler wieder auf den Server lassen"); sender.sendMessage("§a/varo unban [Spieler]: §rSpieler wieder auf den Server lassen");
sender.sendMessage("§a/varo teamcolors: §rZeige verfügbare Team-Farben an"); sender.sendMessage("§a/varo teamcolors: §rZeige verfügbare Team-Farben an");
sender.sendMessage("§a/varo test: §rSpawne einen Klon");
sender.sendMessage("§a/varo testremove: §rLösche den Klon");
sender.sendMessage("\n§6=========================================="); sender.sendMessage("\n§6==========================================");
} }
return true; return true;

View file

@ -1,5 +1,6 @@
package de.cliffbreak.varo.listeners; package de.cliffbreak.varo.listeners;
import java.io.IOException;
import java.util.Stack; import java.util.Stack;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent; import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
@ -26,6 +27,11 @@ public class PlayerJoinQuitListener implements Listener {
@EventHandler() @EventHandler()
public void onPlayerQuit(final PlayerQuitEvent e) { public void onPlayerQuit(final PlayerQuitEvent e) {
e.setQuitMessage(null); e.setQuitMessage(null);
try {
plugin.npcManager.createClone(e.getPlayer(), true);
} catch (IOException ex) {
ex.printStackTrace();
}
Bukkit.broadcast( Bukkit.broadcast(
MessageUtils.getRichTextComponent(e.getPlayer().getName(), "§f hat den Server verlassen.", true)); MessageUtils.getRichTextComponent(e.getPlayer().getName(), "§f hat den Server verlassen.", true));
} }
@ -33,6 +39,8 @@ public class PlayerJoinQuitListener implements Listener {
@EventHandler() @EventHandler()
public void onPlayerJoin(final PlayerJoinEvent e) { public void onPlayerJoin(final PlayerJoinEvent e) {
e.setJoinMessage(null); e.setJoinMessage(null);
plugin.npcManager.removeClone(e.getPlayer());
plugin.npcManager.syncClones(e.getPlayer());
Bukkit.broadcast( Bukkit.broadcast(
MessageUtils.getRichTextComponent(e.getPlayer().getName(), "§f hat den Server betreten.", true)); MessageUtils.getRichTextComponent(e.getPlayer().getName(), "§f hat den Server betreten.", true));
e.getPlayer().sendMessage("\n§7§l#### §9Cliffbreak.de - §lVaro §r§9Changelog §7§l####\n \n" e.getPlayer().sendMessage("\n§7§l#### §9Cliffbreak.de - §lVaro §r§9Changelog §7§l####\n \n"
@ -40,6 +48,8 @@ public class PlayerJoinQuitListener implements Listener {
final Stack<String> changes = new Stack<String>(); final Stack<String> changes = new Stack<String>();
changes.push(" §7• §r§lADD: §rAdd a FakePlayer if Player is logged out");
changes.push(" §7• §r§lADD: §rAdd /varo test && /varo testremove");
changes.push(" §7• §r§lFIX: §r/varo Command is only usable by Server Operators now"); changes.push(" §7• §r§lFIX: §r/varo Command is only usable by Server Operators now");
changes.push(" §7• §r§lADD: §rDisallow special Items (Enchanted Golden Apple, Fishing Rod, Totem of Undying)"); changes.push(" §7• §r§lADD: §rDisallow special Items (Enchanted Golden Apple, Fishing Rod, Totem of Undying)");
changes.push(" §7• §r§lADD: §rUse Vanilla Hearts"); changes.push(" §7• §r§lADD: §rUse Vanilla Hearts");

View file

@ -0,0 +1,133 @@
package de.cliffbreak.varo.managers;
import java.io.IOException;
import java.util.ArrayList;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.CraftServer;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
import de.cliffbreak.varo.Varo;
import de.cliffbreak.varo.uitls.WebUtils;
import net.minecraft.server.v1_15_R1.DataWatcherObject;
import net.minecraft.server.v1_15_R1.DataWatcherRegistry;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import net.minecraft.server.v1_15_R1.MinecraftServer;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityHeadRotation;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_15_R1.PacketPlayOutNamedEntitySpawn;
import net.minecraft.server.v1_15_R1.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_15_R1.PlayerConnection;
import net.minecraft.server.v1_15_R1.PlayerInteractManager;
import net.minecraft.server.v1_15_R1.WorldServer;
import net.minecraft.server.v1_15_R1.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
public class NPCManager {
private final Varo plugin;
private final ArrayList<EntityPlayer> players = new ArrayList<EntityPlayer>();
private Scoreboard scoreboard;
private Team afkTeam;
public NPCManager(final Varo plugin) {
this.plugin = plugin;
this.scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
if (scoreboard.getTeam("afk") == null) {
this.afkTeam = scoreboard.registerNewTeam("afk");
} else {
this.afkTeam = scoreboard.getTeam("afk");
}
this.afkTeam.setPrefix("§8§l[AFK] ");
this.afkTeam.setColor(ChatColor.GRAY);
}
public void createClone(final Player player, final boolean shouldHaveAFKPrefix) throws IOException {
final Location location = player.getLocation();
final MinecraftServer nmsServer = ((CraftServer) Bukkit.getServer()).getServer();
final WorldServer nmsWorld = ((CraftWorld) player.getWorld()).getHandle();
final GameProfile gameProfile = new GameProfile(player.getUniqueId(), player.getName());
try {
final String result = WebUtils.GET("https://sessionserver.mojang.com/session/minecraft/profile/"
+ player.getUniqueId().toString().replace("-", "") + "?unsigned=false");
final JSONObject resultObject = (JSONObject) JSONValue.parseWithException(result);
final JSONObject properties = (JSONObject) ((JSONArray) resultObject.get("properties")).get(0);
gameProfile.getProperties().put("textures", new Property("textures", properties.get("value").toString(),
properties.get("signature").toString()));
} catch (IOException | ParseException e) {
plugin.getLogger().info(e.getMessage());
throw new IOException();
}
final EntityPlayer npc = new EntityPlayer(nmsServer, nmsWorld, gameProfile,
new PlayerInteractManager(nmsWorld));
npc.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
if (shouldHaveAFKPrefix) {
this.afkTeam.addEntry(npc.getName());
}
players.add(npc);
for (Player connectionPlayer : Bukkit.getOnlinePlayers()) {
final PlayerConnection connection = ((CraftPlayer) connectionPlayer).getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, npc));
connection.sendPacket(new PacketPlayOutNamedEntitySpawn(npc));
connection.sendPacket(
new PacketPlayOutEntityHeadRotation(npc, (byte) ((location.getYaw() * 256.0F) / 360.0F)));
npc.getDataWatcher().set(new DataWatcherObject<>(16, DataWatcherRegistry.a),
(byte) plugin.playerCache.getSkinParts(player.getUniqueId().toString().replace("-", "")));
npc.getDataWatcher().set(new DataWatcherObject<>(17, DataWatcherRegistry.a),
plugin.playerCache.getMainHandAsByte(player.getUniqueId().toString().replace("-", "")));
connection.sendPacket(new PacketPlayOutEntityMetadata(npc.getId(), npc.getDataWatcher(), true));
}
}
public void syncClones(Player player) {
for (EntityPlayer npc : this.players) {
final PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, npc));
connection.sendPacket(new PacketPlayOutNamedEntitySpawn(npc));
connection.sendPacket(new PacketPlayOutEntityHeadRotation(npc, (byte) ((npc.yaw * 256.0F) / 360.0F)));
npc.getDataWatcher().set(new DataWatcherObject<>(16, DataWatcherRegistry.a),
(byte) plugin.playerCache.getSkinParts(player.getUniqueId().toString().replace("-", "")));
npc.getDataWatcher().set(new DataWatcherObject<>(17, DataWatcherRegistry.a),
plugin.playerCache.getMainHandAsByte(player.getUniqueId().toString().replace("-", "")));
connection.sendPacket(new PacketPlayOutEntityMetadata(npc.getId(), npc.getDataWatcher(), true));
}
}
public void removeClone(Player player) {
this.afkTeam.removeEntry(player.getName());
for (int i = 0; i < this.players.size(); i++) {
EntityPlayer npc = this.players.get(i);
if (npc.getUniqueID().equals(player.getUniqueId())) {
final WorldServer nmsWorld = ((CraftWorld) player.getWorld()).getHandle();
nmsWorld.removeEntity(npc);
for (Player connectionPlayer : Bukkit.getOnlinePlayers()) {
final PlayerConnection connection = ((CraftPlayer) connectionPlayer).getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, npc));
connection.sendPacket(new PacketPlayOutEntityDestroy(npc.getId()));
}
this.players.remove(npc);
}
}
}
}