Varo/varo/src/main/java/de/cliffbreak/varo/managers/NPCManager.java
2020-05-29 14:18:54 +02:00

296 lines
No EOL
15 KiB
Java

package de.cliffbreak.varo.managers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.World;
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.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.scheduler.BukkitRunnable;
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.utils.ImprovedOfflinePlayer;
import de.cliffbreak.varo.utils.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.EnumItemSlot;
import net.minecraft.server.v1_15_R1.MinecraftServer;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityEquipment;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityHeadRotation;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityStatus;
import net.minecraft.server.v1_15_R1.PacketPlayOutNamedEntitySpawn;
import net.minecraft.server.v1_15_R1.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_15_R1.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
import net.minecraft.server.v1_15_R1.PlayerConnection;
import net.minecraft.server.v1_15_R1.PlayerInteractManager;
import net.minecraft.server.v1_15_R1.WorldServer;
public class NPCManager {
private final Varo plugin;
private final ArrayList<EntityPlayer> npcs = new ArrayList<EntityPlayer>();
private final ArrayList<Integer> isDying = new ArrayList<Integer>();
private final HashMap<UUID, PlayerInventory> inventories = new HashMap<UUID, PlayerInventory>();
public NPCManager(final Varo plugin) {
this.plugin = plugin;
addAllClones();
}
public void createClone(final Player player) {
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());
inventories.put(player.getUniqueId(), player.getInventory());
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) {
this.plugin.getLogger().info(e.getMessage());
}
final PlayerInteractManager playerInteractManager = new PlayerInteractManager(nmsWorld);
final EntityPlayer npc = new EntityPlayer(nmsServer, nmsWorld, gameProfile, playerInteractManager);
npc.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
npc.setHealth((float) player.getHealth());
npcs.add(npc);
for (final Player connectionPlayer : Bukkit.getOnlinePlayers()) {
final PlayerConnection connection = ((CraftPlayer) connectionPlayer).getHandle().playerConnection;
new BukkitRunnable() {
@Override
public void run() {
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, npc));
}
}.runTaskLater(this.plugin, 20);
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) this.plugin.getPlayerCache().getSkinParts(player.getUniqueId().toString().replace("-", "")));
npc.getDataWatcher().set(new DataWatcherObject<>(17, DataWatcherRegistry.a),
this.plugin.getPlayerCache().getMainHandAsByte(player.getUniqueId().toString().replace("-", "")));
connection.sendPacket(new PacketPlayOutEntityMetadata(npc.getId(), npc.getDataWatcher(), true));
sendEquipmentPackets(connection, npc.getId(), player.getInventory());
}
}
public void createOfflineClone(final UUID uuid, final String name) {
final String compressedUuid = uuid.toString().replace("-", "");
final Location location = this.plugin.getPlayerCache().getPlayerLocationCache(compressedUuid);
final MinecraftServer nmsServer = ((CraftServer) Bukkit.getServer()).getServer();
final WorldServer nmsWorld = ((CraftWorld) location.getWorld()).getHandle();
final GameProfile gameProfile = new GameProfile(uuid, name);
ImprovedOfflinePlayer iop = new ImprovedOfflinePlayer(uuid.toString());
iop.getInventoryItems();
// final Inventory inventory = this.plugin.getPlayerCache().getInventory(compressedUuid);
// for (ItemStack item : inventory.getContents()) {
// System.out.println(item);
// }
// inventories.put(uuid, inventory);
try {
final String result = WebUtils.GET(
"https://sessionserver.mojang.com/session/minecraft/profile/" + compressedUuid + "?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) {
this.plugin.getLogger().info(e.getMessage());
}
final PlayerInteractManager playerInteractManager = new PlayerInteractManager(nmsWorld);
final EntityPlayer npc = new EntityPlayer(nmsServer, nmsWorld, gameProfile, playerInteractManager);
npc.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
// npc.setHealth(this.plugin.getPlayerCache().getHealth(compressedUuid));
// npcs.add(npc);
// for (final Player connectionPlayer : Bukkit.getOnlinePlayers()) {
// final PlayerConnection connection = ((CraftPlayer) connectionPlayer).getHandle().playerConnection;
// new BukkitRunnable() {
// @Override
// public void run() {
// connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, npc));
// }
// }.runTaskLater(this.plugin, 20);
// 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) this.plugin.getPlayerCache().getSkinParts(compressedUuid));
// npc.getDataWatcher().set(new DataWatcherObject<>(17, DataWatcherRegistry.a),
// this.plugin.getPlayerCache().getMainHandAsByte(compressedUuid));
// connection.sendPacket(new PacketPlayOutEntityMetadata(npc.getId(), npc.getDataWatcher(), true));
// // sendEquipmentPackets(connection, npc.getId(), inventory);
// }
}
private void sendEquipmentPackets(final PlayerConnection connection, final int id,
final PlayerInventory inventory) {
connection.sendPacket(new PacketPlayOutEntityEquipment(id, EnumItemSlot.MAINHAND,
CraftItemStack.asNMSCopy(inventory.getItemInMainHand())));
connection.sendPacket(new PacketPlayOutEntityEquipment(id, EnumItemSlot.OFFHAND,
CraftItemStack.asNMSCopy(inventory.getItemInOffHand())));
connection.sendPacket(new PacketPlayOutEntityEquipment(id, EnumItemSlot.FEET,
CraftItemStack.asNMSCopy(inventory.getBoots())));
connection.sendPacket(new PacketPlayOutEntityEquipment(id, EnumItemSlot.LEGS,
CraftItemStack.asNMSCopy(inventory.getLeggings())));
connection.sendPacket(new PacketPlayOutEntityEquipment(id, EnumItemSlot.CHEST,
CraftItemStack.asNMSCopy(inventory.getChestplate())));
connection.sendPacket(new PacketPlayOutEntityEquipment(id, EnumItemSlot.HEAD,
CraftItemStack.asNMSCopy(inventory.getHelmet())));
}
public void syncClones(final Player player) {
for (final EntityPlayer npc : this.npcs) {
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) this.plugin.getPlayerCache().getSkinParts(player.getUniqueId().toString().replace("-", "")));
npc.getDataWatcher().set(new DataWatcherObject<>(17, DataWatcherRegistry.a),
this.plugin.getPlayerCache().getMainHandAsByte(player.getUniqueId().toString().replace("-", "")));
connection.sendPacket(new PacketPlayOutEntityMetadata(npc.getId(), npc.getDataWatcher(), true));
sendEquipmentPackets(connection, npc.getId(), this.inventories.get(npc.getUniqueID()));
}
}
public boolean isNPC(final int id) {
for (final EntityPlayer npc : this.npcs) {
if (npc.getId() == id)
return true;
}
return false;
}
public void addDamage(final Player damager, final int id, final double damage, final boolean isCritical) {
for (final EntityPlayer npc : this.npcs) {
if (npc.getId() == id) {
npc.setHealth((float) (npc.getHealth() - damage));
final World world = npc.getWorld().getWorld();
final Location loc = new Location(world, npc.locX(), npc.locY(), npc.locZ());
if (npc.getHealth() > 0.0F) {
for (final Player connectionPlayer : Bukkit.getOnlinePlayers()) {
final PlayerConnection connection = ((CraftPlayer) connectionPlayer)
.getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutEntityStatus(npc, (byte) 2)); // Send HURT (2) Animation
}
world.playSound(loc, Sound.ENTITY_PLAYER_HURT, 1.0F, 1.0F);
world.playSound(loc, Sound.ENTITY_PLAYER_ATTACK_STRONG, 1.0F, 1.0F);
if (isCritical)
world.playSound(loc, Sound.ENTITY_PLAYER_ATTACK_CRIT, 1.0F, 1.0F);
} else {
if (this.isDying.contains(npc.getId())) {
return;
}
this.isDying.add(npc.getId());
// Send Death Animation Packet
for (final Player connectionPlayer : Bukkit.getOnlinePlayers()) {
final PlayerConnection connection = ((CraftPlayer) connectionPlayer)
.getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutEntityMetadata(npc.getId(), npc.getDataWatcher(), true));
}
if (isCritical)
world.playSound(loc, Sound.ENTITY_PLAYER_ATTACK_CRIT, 1.0F, 1.0F);
world.playSound(loc, Sound.ENTITY_PLAYER_DEATH, 1.0F, 1.0F);
new BukkitRunnable() {
@Override
public void run() {
for (final ItemStack item : inventories.get(npc.getUniqueID())) {
if (item != null)
world.dropItem(loc, item);
}
}
}.runTask(this.plugin); // Run Task in sync to be thread safe
this.plugin.getBanUtils().addBan(npc.getUniqueID());
Bukkit.broadcastMessage(this.plugin.getMessageUtils()
.getDeathMessage(npc.getBukkitEntity().getPlayer(), damager, DamageCause.CUSTOM));
this.plugin.getDatabase().addKill(damager.getUniqueId().toString().replace("-", ""),
npc.getUniqueID().toString().replace("-", ""));
this.plugin.getDiscordBot().broadcastMessage("Der Spieler <@!" + this.plugin.getTeamManager()
.getDiscordIdByUuid(npc.getUniqueID().toString().replace("-", "")) + "> ist gestorben.");
new BukkitRunnable() {
@Override
public void run() {
removeClone(npc.getUniqueID());
}
}.runTaskLater(this.plugin, 20);
}
}
}
}
private void addAllClones() {
final ArrayList<Team> teams = this.plugin.getTeamManager().getTeams();
for (final Team team : teams) {
for (String player : team.getEntries()) {
UUID uuid = this.plugin.getTeamManager().getUuidFromPlayerName(player);
this.createOfflineClone(uuid, player);
}
}
}
public void removeClone(final UUID uuid) {
for (int i = 0; i < this.npcs.size(); i++) {
final EntityPlayer npc = this.npcs.get(i);
if (npc.getUniqueID().equals(uuid)) {
final WorldServer nmsWorld = npc.getWorldServer();
for (final Player connectionPlayer : Bukkit.getOnlinePlayers()) {
final PlayerConnection connection = ((CraftPlayer) connectionPlayer).getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutEntityDestroy(npc.getId()));
// connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, npc));
}
new BukkitRunnable() {
@Override
public void run() {
nmsWorld.removeEntity(npc);
npcs.remove(npc);
}
}.runTask(this.plugin);
}
}
}
}