Skip to content
This repository was archived by the owner on Feb 17, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions paper/src/main/java/net/minelink/ctplus/NpcManager.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package net.minelink.ctplus;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minelink.ctplus.event.NpcDespawnEvent;
import net.minelink.ctplus.event.NpcDespawnReason;
import net.minelink.ctplus.task.NpcDespawnTask;
Expand All @@ -11,9 +8,12 @@
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.metadata.FixedMetadataValue;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public final class NpcManager {

private final CombatTagPlus plugin;
Expand Down Expand Up @@ -53,13 +53,6 @@ public Npc spawn(Player player) {
entity.getInventory().setArmorContents(player.getInventory().getArmorContents());
entity.addPotionEffects(player.getActivePotionEffects());

// Should fix some visual glitches, such as health bars displaying zero
// TODO: Find another solution. This one causes the player to be added to the NMS PlayerList, that's not ideal.
entity.teleport(player, PlayerTeleportEvent.TeleportCause.PLUGIN);

// Send equipment packets to nearby players
plugin.getNpcPlayerHelper().updateEquipment(entity);

entity.setMetadata("NPC", new FixedMetadataValue(plugin, true));

// Play a nice little effect indicating the NPC was spawned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public void despawnNpc(PlayerJoinEvent event) {
// Attempt to despawn NPC
Npc npc = plugin.getNpcManager().getSpawnedNpc(event.getPlayer().getUniqueId());
if (npc != null) {
event.getPlayer().teleport(npc.getEntity().getLocation());

plugin.getNpcManager().despawn(npc);
}
}
Expand Down
47 changes: 41 additions & 6 deletions paper/src/main/java/net/minelink/ctplus/nms/NpcPlayer.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
package net.minelink.ctplus.nms;

import com.destroystokyo.paper.profile.ProfileProperty;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import java.util.Map;
import java.util.UUID;
import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import net.minelink.ctplus.CombatTagPlus;
import net.minelink.ctplus.compat.base.NpcIdentity;
import net.minelink.ctplus.compat.base.NpcNameGeneratorFactory;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;

import java.util.Map;

public class NpcPlayer extends ServerPlayer {

private NpcIdentity identity;
Expand All @@ -29,15 +43,36 @@ public static NpcPlayer valueOf(Player player) {
ServerLevel worldServer = ((CraftWorld) player.getWorld()).getHandle();
GameProfile gameProfile = new GameProfile(player.getUniqueId(), NpcNameGeneratorFactory.getNameGenerator().generate(player));

for (Map.Entry<String, Property> entry: ((CraftPlayer) player).getProfile().getProperties().entries()) {
gameProfile.getProperties().put(entry.getKey(), entry.getValue());
}

NpcPlayer npcPlayer = new NpcPlayer(minecraftServer, worldServer, gameProfile);
npcPlayer.identity = new NpcIdentity(player);

new NpcPlayerConnection(npcPlayer);

ProfileProperty property = player.getPlayerProfile().getProperties().iterator().next();
String texture = property.getValue();
String signature = property.getSignature();

npcPlayer.getGameProfile().getProperties().put("textures", new Property("textures", texture, signature));

return npcPlayer;
}

@Override
public void tick(){
super.tick();
doTick();
}

@Override
public boolean hurt(DamageSource damageSource, float f) {
boolean damaged = super.hurt(damageSource, f);
if (damaged) {
if (this.hurtMarked) {
this.hurtMarked = false;
Bukkit.getScheduler().runTask(CombatTagPlus.getPlugin(CombatTagPlus.class), () -> NpcPlayer.this.hurtMarked = true);
}
}
return damaged;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@

import com.google.common.collect.Lists;
import com.mojang.datafixers.util.Pair;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.food.FoodData;
Expand All @@ -29,31 +27,50 @@
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;

public class NpcPlayerHelperImpl implements NpcPlayerHelper {
@Override
public Player spawn(Player player) {
NpcPlayer npcPlayer = NpcPlayer.valueOf(player);
ServerLevel worldServer = ((CraftWorld) player.getWorld()).getHandle();
Location l = player.getLocation();

npcPlayer.spawnIn(worldServer);
npcPlayer.forceSetPositionRotation(l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch());
npcPlayer.gameMode.setLevel(worldServer);
npcPlayer.spawnInvulnerableTime = 0;
NpcPlayer npcPlayer = NpcPlayer.valueOf(player);

for (ServerPlayer serverPlayer : MinecraftServer.getServer().getPlayerList().getPlayers()) {
if (serverPlayer instanceof NpcPlayer) continue;
Location location = player.getLocation();

ClientboundPlayerInfoPacket packet = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, npcPlayer);
serverPlayer.connection.send(packet);
}
npcPlayer.setPos(location.getX(), location.getY(), location.getZ());
npcPlayer.setXRot(location.getYaw());
npcPlayer.setYRot(location.getPitch());

npcPlayer.getBukkitEntity().setNoDamageTicks(0);

worldServer.entityManager.getEntityGetter().get(player.getUniqueId()).remove(Entity.RemovalReason.DISCARDED);
worldServer.entityManager.addNewEntity(npcPlayer);
worldServer.addNewPlayer(npcPlayer);
showAll(npcPlayer, location);

return npcPlayer.getBukkitEntity();
}

public static void showAll(ServerPlayer entityPlayer, Location location) {
ClientboundPlayerInfoPacket playerInfoAdd = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER);
ClientboundAddPlayerPacket namedEntitySpawn = new ClientboundAddPlayerPacket(entityPlayer);
ClientboundRotateHeadPacket headRotation = new ClientboundRotateHeadPacket(entityPlayer, (byte) ((location.getYaw() * 256f) / 360f));
ClientboundPlayerInfoPacket playerInfoRemove = new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.REMOVE_PLAYER);
for (Player player : Bukkit.getOnlinePlayers()) {
ServerGamePacketListenerImpl connection = ((CraftPlayer) player).getHandle().connection;
connection.send(playerInfoAdd);
connection.send(namedEntitySpawn);
connection.send(headRotation);
connection.send(playerInfoRemove);
}
entityPlayer.getEntityData().
set(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION, (byte) 0xFF);
}

@Override
public void despawn(Player player) {
ServerPlayer entity = ((CraftPlayer) player).getHandle();
Expand Down