Skip to content

Instantly share code, notes, and snippets.

@DanielTheDev
Last active April 29, 2023 19:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanielTheDev/687ff9236d59ae63410a82c17d1bb423 to your computer and use it in GitHub Desktop.
Save DanielTheDev/687ff9236d59ae63410a82c17d1bb423 to your computer and use it in GitHub Desktop.
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import net.minecraft.EnumChatFormat;
import net.minecraft.core.BlockPosition;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketDataSerializer;
import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.network.syncher.DataWatcher;
import net.minecraft.network.syncher.DataWatcherObject;
import net.minecraft.network.syncher.DataWatcherRegistry;
import net.minecraft.network.syncher.DataWatcherSerializer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityPose;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.EnumItemSlot;
import net.minecraft.world.entity.animal.EntityParrot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.EnumGamemode;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.scores.ScoreboardTeam;
import net.minecraft.world.scores.ScoreboardTeamBase;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftParrot;
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_18_R1.util.CraftChatMessage;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class NPC {
private static AtomicInteger atomicInteger;
private final int entityID; //unique entityID the server holds to find/modify existing entities. Be careful when assigning values that they do not overlap
private final Location location;
private GameProfile profile;
private MetaData metadata = new MetaData();
static {
try {
Field field = Entity.class.getDeclaredField("b");
field.setAccessible(true);
atomicInteger = (AtomicInteger) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public NPC(UUID uuid, Location location, String displayName) {
this.entityID = atomicInteger.incrementAndGet();
this.profile = new GameProfile(uuid, displayName);
this.location = location;
}
public NPC(Location location, String displayName) {
this(UUID.randomUUID(), location, displayName);
}
public void spawnNPC(Collection<Player> players) {
players.forEach(this::spawnNPC);
}
public void spawnNPC(Player player) {
this.addToTabList(player);
this.sendPacket(player, this.getEntitySpawnPacket());
this.updateMetadata(player);
}
public void destroyNPC(Collection<Player> players) {
players.forEach(this::destroyNPC);
}
public void destroyNPC(Player player) {
this.sendPacket(player, this.getPlayerInfoPacket(PlayerInfo.REMOVE_PLAYER));
this.sendPacket(player, this.getEntityDestroyPacket());
}
public void reloadNPC(Collection<Player> players) {
players.forEach(this::reloadNPC);
}
public void reloadNPC(Player player) {
this.destroyNPC(player);
this.spawnNPC(player);
}
public void teleportNPC(Collection<Player> players, Location location, boolean onGround) {
players.forEach(p->this.teleportNPC(p, location, onGround));
}
public void teleportNPC(Player player, Location location, boolean onGround) {
this.location.setX(location.getX());
this.location.setY(location.getY());
this.location.setZ(location.getZ());
this.location.setPitch(location.getPitch());
this.location.setYaw(location.getYaw());
this.rotateHead(player, location.getPitch(), location.getYaw());
this.sendPacket(player, this.getEntityTeleportPacket(onGround));
}
public void updateMetadata(Collection<Player> players) {
players.forEach(this::updateMetadata);
}
public void updateMetadata(Player player) {
this.sendPacket(player, this.getEntityMetadataPacket());
}
public void updateGameMode(Collection<Player> players) {
players.forEach(this::updateGameMode);
}
public void updateGameMode(Player player) {
this.sendPacket(player, this.getPlayerInfoPacket(PlayerInfo.UPDATE_GAME_MODE));
}
public void setPing(Collection<Player> players, Ping ping) {
players.forEach(p->this.setPing(p, ping));
}
public void setPing(Player player, Ping ping) {
this.sendPacket(player, this.getUpdatePlayerInfoPacket(PlayerInfo.UPDATE_LATENCY, ping));
}
public void setGameMode(Collection<Player> players, GameMode gameMode) {
players.forEach(p->this.setGameMode(p, gameMode));
}
public void setGameMode(Player player, GameMode gameMode) {
this.sendPacket(player, this.getUpdatePlayerInfoPacket(PlayerInfo.UPDATE_GAME_MODE, gameMode));
}
public void setTabListName(Collection<Player> players, String displayName) {
players.forEach(p->this.setTabListName(p, displayName));
}
public void setTabListName(Player player, String displayName) {
this.sendPacket(player, this.getUpdatePlayerInfoPacket(PlayerInfo.UPDATE_DISPLAY_NAME, displayName));
}
public void removeFromTabList(Collection<Player> players) {
players.forEach(this::removeFromTabList);
}
public void removeFromTabList(Player player) {
this.sendPacket(player, this.getPlayerInfoPacket(PlayerInfo.REMOVE_PLAYER));
}
public void addToTabList(Collection<Player> players) {
players.forEach(this::addToTabList);
}
public void addToTabList(Player player) {
this.sendPacket(player, this.getPlayerInfoPacket(PlayerInfo.ADD_PLAYER));
}
public void playAnimation(Collection<Player> players, Animation animation) {
players.forEach(p->this.playAnimation(p, animation));
}
public void playAnimation(Player player, Animation animation) {
this.sendPacket(player, this.getEntityAnimationPacket(animation));
}
public void lookAtPlayer(Collection<Player> players, Player target) {
players.forEach(p->this.lookAtPlayer(p, target));
}
public void lookAtPlayer(Player player, Player target) {
this.lookAtPoint(player, target.getEyeLocation());
}
public void lookAtPoint(Collection<Player> players, Location location) {
players.forEach(p->this.lookAtPoint(p, location));
}
public void lookAtPoint(Player player, Location location) {
Location eyeLocation = this.getEyeLocation();
float yaw = (float) Math.toDegrees(Math.atan2(location.getZ() - eyeLocation.getZ(), location.getX()-eyeLocation.getX())) - 90;
yaw = (float) (yaw + Math.ceil( -yaw / 360 ) * 360);
float deltaXZ = (float) Math.sqrt(Math.pow(eyeLocation.getX()-location.getX(), 2) + Math.pow(eyeLocation.getZ()-location.getZ(), 2));
float pitch = (float) Math.toDegrees(Math.atan2(deltaXZ, location.getY()-eyeLocation.getY())) - 90;
pitch = (float) (pitch + Math.ceil( -pitch / 360 ) * 360);
this.rotateHead(player, pitch, yaw);
}
public void rotateHead(Collection<Player> players, float pitch, float yaw) {
players.forEach(p->this.rotateHead(p, pitch, yaw));
}
public void rotateHead(Player player, float pitch, float yaw) {
this.location.setPitch(pitch);
this.location.setYaw(yaw);
this.sendPacket(player, this.getEntityLookPacket());
this.sendPacket(player, this.getEntityHeadRotatePacket());
}
public void setEquipment(Collection<Player> players, ItemSlot slot, org.bukkit.inventory.ItemStack itemStack) {
players.forEach(p->this.setEquipment(p, slot, itemStack));
}
public void setEquipment(Player player, ItemSlot slot, org.bukkit.inventory.ItemStack itemStack) {
this.sendPacket(player, this.getEntityEquipmentPacket(slot.getNMSItemSlot(), CraftItemStack.asNMSCopy(itemStack)));
}
public void setPassenger(Collection<Player> players, int... entityIDs) {
players.forEach(p->this.setPassenger(p, entityIDs));
}
public void setPassenger(Player player, int... entityIDs) {
this.sendPacket(player, getEntityAttachPacket(entityIDs));
}
private void sendPacket(Player player, Packet<?> packet) {
((CraftPlayer)(player)).getHandle().b.a(packet);
}
public void setTeamFeatures(Player player, TeamFeatures teamFeatures) {
ScoreboardTeam team = new ScoreboardTeam(new Scoreboard(), this.profile.getName());
team.a(teamFeatures.isNameTagVisible() ? ScoreboardTeamBase.EnumNameTagVisibility.a : ScoreboardTeamBase.EnumNameTagVisibility.b);
team.a(teamFeatures.getGlowColor().getNMSColor());
PacketPlayOutScoreboardTeam createPacket = PacketPlayOutScoreboardTeam.a(team, true);
PacketPlayOutScoreboardTeam joinPacket = PacketPlayOutScoreboardTeam.a(team, this.profile.getName(), PacketPlayOutScoreboardTeam.a.a);
this.sendPacket(player, createPacket);
this.sendPacket(player, joinPacket);
}
public NBTTagCompound createParrot(Consumer<Parrot> callback, World world) {
EntityParrot entityParrot = new EntityParrot(EntityTypes.al, ((CraftWorld)world).getHandle());
CraftParrot parrot = new CraftParrot((CraftServer) Bukkit.getServer(), entityParrot);
callback.accept(parrot);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
entityParrot.d(nbtTagCompound);
return nbtTagCompound;
}
public void setParrotLeftShoulder(Consumer<Parrot> callback, World world) {
this.metadata.setLeftShoulder(this.createParrot(callback, world));
}
public void setParrotRightShoulder(Consumer<Parrot> callback, World world) {
this.metadata.setRightShoulder(this.createParrot(callback, world));
}
private PacketPlayOutMount getEntityAttachPacket(int[] entityIDs) {
return this.createDataSerializer(data->{
data.d(this.entityID);
data.a(entityIDs);
return new PacketPlayOutMount(data);
});
}
private PacketPlayOutEntity.PacketPlayOutEntityLook getEntityLookPacket() {
return new PacketPlayOutEntity.PacketPlayOutEntityLook(this.entityID, (byte)((int)(this.location.getYaw() * 256.0F / 360.0F)), (byte)((int)(this.location.getPitch() * 256.0F / 360.0F)), true);
}
private PacketPlayOutEntityTeleport getEntityTeleportPacket(boolean onGround) {
return this.createDataSerializer(data->{
data.d(this.entityID);
data.writeDouble(this.location.getX());
data.writeDouble(this.location.getY());
data.writeDouble(this.location.getZ());
data.writeByte((byte)((int)(this.location.getYaw() * 256.0F / 360.0F)));
data.writeByte((byte)((int)(this.location.getPitch() * 256.0F / 360.0F)));
data.writeBoolean(onGround);
return new PacketPlayOutEntityTeleport(data);
});
}
private PacketPlayOutEntityHeadRotation getEntityHeadRotatePacket() {
return this.createDataSerializer(data->{
data.d(this.entityID);
data.writeByte((byte)((int)(this.location.getYaw() * 256.0F / 360.0F)));
return new PacketPlayOutEntityHeadRotation(data);
});
}
private PacketPlayOutEntityEquipment getEntityEquipmentPacket(EnumItemSlot slot, ItemStack itemStack) {
return new PacketPlayOutEntityEquipment(this.entityID, Arrays.asList(new Pair<EnumItemSlot, ItemStack>(slot, itemStack)));
}
private PacketPlayOutAnimation getEntityAnimationPacket(Animation animation) {
return this.createDataSerializer((data)->{
data.d(this.entityID);
data.writeByte((byte)animation.getType());
return new PacketPlayOutAnimation(data);
});
}
private PacketPlayOutEntityDestroy getEntityDestroyPacket(){
return new PacketPlayOutEntityDestroy(this.entityID);
}
private PacketPlayOutEntityMetadata getEntityMetadataPacket() {
return this.createDataSerializer((data)->{
data.d(this.entityID);
DataWatcher.a(this.metadata.getList(), data);
return new PacketPlayOutEntityMetadata(data);
});
}
private PacketPlayOutNamedEntitySpawn getEntitySpawnPacket() {
return this.createDataSerializer((data)->{
data.d(this.entityID);
data.a(this.profile.getId());
data.writeDouble(this.location.getX());
data.writeDouble(this.location.getY());
data.writeDouble(this.location.getZ());
data.writeByte((byte)((int)(this.location.getYaw() * 256.0F / 360.0F)));
data.writeByte((byte)((int)(this.location.getPitch() * 256.0F / 360.0F)));
return new PacketPlayOutNamedEntitySpawn(data);
});
}
public PacketPlayOutPlayerInfo getUpdatePlayerInfoPacket(PlayerInfo playerInfo, Object obj) {
return this.createDataSerializer((data)->{
PacketPlayOutPlayerInfo.EnumPlayerInfoAction action = playerInfo.getNMSAction();
PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData;
if(playerInfo == PlayerInfo.UPDATE_LATENCY) {
playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, ((Ping)obj).getMilliseconds(), null, null);
} else if(playerInfo == PlayerInfo.UPDATE_GAME_MODE) {
playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, 0, ((GameMode)obj).getNMSGameMode(), null);
} else if(playerInfo == PlayerInfo.UPDATE_DISPLAY_NAME) {
playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, 0, null, CraftChatMessage.fromString(((String)obj))[0]);
} else {
throw new NullPointerException();
}
List<PacketPlayOutPlayerInfo.PlayerInfoData> list = Arrays.asList(playerInfoData);
data.a(playerInfo.getNMSAction());
Method method = playerInfo.getNMSAction().getDeclaringClass().getDeclaredMethod("a", PacketDataSerializer.class, PacketPlayOutPlayerInfo.PlayerInfoData.class);
method.setAccessible(true);
data.a(list, (a,b)->this.unsafe(()->method.invoke(action, a, b)));
return new PacketPlayOutPlayerInfo(data);
});
}
public PacketPlayOutPlayerInfo getPlayerInfoPacket(PlayerInfo playerInfo) {
return this.createDataSerializer((data)->{
PacketPlayOutPlayerInfo.EnumPlayerInfoAction action = playerInfo.getNMSAction();
PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, Ping.FIVE_BARS.getMilliseconds(), GameMode.CREATIVE.getNMSGameMode(), CraftChatMessage.fromString(this.getProfile().getName())[0]);
List<PacketPlayOutPlayerInfo.PlayerInfoData> list = Arrays.asList(playerInfoData);
data.a(playerInfo.getNMSAction());
Method method = playerInfo.getNMSAction().getDeclaringClass().getDeclaredMethod("a", PacketDataSerializer.class, PacketPlayOutPlayerInfo.PlayerInfoData.class);
method.setAccessible(true);
data.a(list, (a,b)->this.unsafe(()->method.invoke(action, a, b)));
return new PacketPlayOutPlayerInfo(data);
});
}
public int getEntityID() {
return entityID;
}
public GameProfile getProfile() {
return profile;
}
public MetaData getMetadata() {
return metadata;
}
public Location getLocation() {
return location;
}
public Location getEyeLocation() {
return this.location.clone().add(0, EntityTypes.bi.m().b * 0.85F, 0);
}
public MetaData getMetaData() {
return this.metadata;
}
public void setMetaData(MetaData metaData) {
this.metadata = metaData;
}
public void setSkin(SkinTextures skinTextures) {
this.profile.getProperties().put("textures", new Property("textures", skinTextures.getTexture(), skinTextures.getSignature()));
}
public void setASyncSkinByUsername(Plugin plugin, Collection<Player> players, String username) {
this.setASyncSkinByUsername(plugin, players, username, (a,b)->{});
}
public void setASyncSkinByUsername(Plugin plugin, Player player, String username) {
this.setASyncSkinByUsername(plugin, player, username, (a,b)->{});
}
public void setASyncSkinByUUID(Plugin plugin, Collection<Player> players, UUID uuid) {
this.setASyncSkinByUUID(plugin, players, uuid, (a,b)->{});
}
public void setASyncSkinByUUID(Plugin plugin, Player player, UUID uuid) {
this.setASyncSkinByUUID(plugin, player, uuid, (a,b)->{});
}
public void setASyncSkinByUsername(Plugin plugin, Player player, String username, BiConsumer<Boolean, NPC> callback) {
SkinTextures.getByUsername(plugin, username, (success, skin)->setASyncSkin(success, skin, player, callback));
}
public void setASyncSkinByUsername(Plugin plugin, Collection<Player> players, String username, BiConsumer<Boolean, NPC> callback) {
SkinTextures.getByUsername(plugin, username, (success, skin)->setASyncSkin(success, skin, players, callback));
}
public void setASyncSkinByUUID(Plugin plugin, Player player, UUID uuid, BiConsumer<Boolean, NPC> callback) {
SkinTextures.getByUUID(plugin, uuid, (success, skin)->setASyncSkin(success, skin, player, callback));
}
public void setASyncSkinByUUID(Plugin plugin, Collection<Player> players, UUID uuid, BiConsumer<Boolean, NPC> callback) {
SkinTextures.getByUUID(plugin, uuid, (success, skin)->setASyncSkin(success, skin, players, callback));
}
private void setASyncSkin(boolean success, SkinTextures skin, Collection<Player> players, BiConsumer<Boolean, NPC> callback) {
if(success) {
this.setSkin(skin);
this.reloadNPC(players);
}
callback.accept(success, this);
}
private void setASyncSkin(boolean success, SkinTextures skin, Player player, BiConsumer<Boolean, NPC> callback) {
this.setASyncSkin(success, skin, Arrays.asList(player), callback);
}
public void setDisplayName(String displayName) {
GameProfile swapProfile = new GameProfile(this.profile.getId(), displayName);
swapProfile.getProperties().putAll(this.profile.getProperties());
this.profile = swapProfile;
}
public class MetaData {
//Entity metadata
private final DataWatcher.Item<Byte> entityState = a(0, (byte) EntityState.createMask(EntityState.DEFAULT));
private final DataWatcher.Item<Integer> airTicks = a(1, 300);
private final DataWatcher.Item<Optional<IChatBaseComponent>> customName = a(2, Optional.empty(), DataWatcherRegistry.f);
private final DataWatcher.Item<Boolean> customNameVisible = a(3, false);
private final DataWatcher.Item<Boolean> silent = a(4, false);
private final DataWatcher.Item<Boolean> gravity = a(5, false);
private final DataWatcher.Item<EntityPose> pose = a(6, Pose.STANDING.getNMSPose());
private final DataWatcher.Item<Integer> frozenTicks = a(7, 0); //shaking at tick 140
//LivingEntity metadata
private final DataWatcher.Item<Byte> handStatus = a(8, (byte)HandStatus.createMask(HandStatus.MAIN_HAND));
private final DataWatcher.Item<Float> health = a(9, 1.0F);
private final DataWatcher.Item<Integer> potionEffectColor = a(10, 0);
private final DataWatcher.Item<Boolean> isPotionEffectAmbient = a(11, false);
private final DataWatcher.Item<Integer> arrowsInEntity = a(12, 0);
private final DataWatcher.Item<Integer> absorptionHealth = a(13, 0);
private final DataWatcher.Item<Optional<BlockPosition>> sleepingBedLocation = a(14, Optional.empty(), DataWatcherRegistry.m);
//Player metadata
private final DataWatcher.Item<Float> additionalHearts = a(15, 0.0F);
private final DataWatcher.Item<Integer> score = a(16, 0);
private final DataWatcher.Item<Byte> skinStatus = a(17, (byte)SkinStatus.createMask(SkinStatus.ALL_ENABLED));
private final DataWatcher.Item<Byte> hand = a(18, (byte)Hand.RIGHT.getType());
private final DataWatcher.Item<NBTTagCompound> leftShoulder = a(19, new NBTTagCompound());
private final DataWatcher.Item<NBTTagCompound> rightShoulder = a(20, new NBTTagCompound());
private final List<DataWatcher.Item<?>> list;
public MetaData() {
this.list = new ArrayList<>(Arrays.asList(
this.entityState,
this.airTicks,
this.customName,
this.customNameVisible,
this.silent,
this.gravity,
this.pose,
this.frozenTicks,
this.handStatus,
this.health,
this.potionEffectColor,
this.isPotionEffectAmbient,
this.arrowsInEntity,
this.absorptionHealth,
this.sleepingBedLocation,
this.additionalHearts,
this.score,
this.skinStatus,
this.hand,
this.leftShoulder,
this.rightShoulder));
}
public EntityState[] getEntityState() {
return EntityState.fromMask(entityState.b());
}
public Integer getAirTicks() {
return airTicks.b();
}
public Optional<IChatBaseComponent> getCustomName() {
return customName.b();
}
public Boolean isCustomNameVisible() {
return customNameVisible.b();
}
public Boolean isSilent() {
return silent.b();
}
public Boolean hasGravity() {
return gravity.b();
}
public Pose getPose() {
return Pose.from(this.pose.b());
}
public Integer getFrozenTicks() {
return frozenTicks.b();
}
public HandStatus[] getHandStatus() {
return HandStatus.fromMask(handStatus.b());
}
public Float getHealth() {
return health.b();
}
public Integer getPotionEffectColor() {
return potionEffectColor.b();
}
public Boolean isPotionEffectAmbient() {
return isPotionEffectAmbient.b();
}
public Integer getArrowsInEntity() {
return arrowsInEntity.b();
}
public Integer getAbsorptionHealth() {
return absorptionHealth.b();
}
public Optional<BlockPosition> getSleepingBedLocation() {
return sleepingBedLocation.b();
}
public Float getAdditionalHearts() {
return additionalHearts.b();
}
public Integer getScore() {
return score.b();
}
public SkinStatus[] getSkinStatus() {
return SkinStatus.fromMask(skinStatus.b());
}
public Hand getHand() {
return Hand.fromByte(hand.b());
}
public NBTTagCompound getLeftShoulder() {
return leftShoulder.b();
}
public NBTTagCompound getRightShoulder() {
return rightShoulder.b();
}
public void setEntityState(EntityState... entityState) {
this.entityState.a((byte) EntityState.createMask(entityState));
}
public void setAirTicks(Integer airTicks) {
this.airTicks.a(airTicks);
}
public void setCustomName(String customName) {
this.customName.a(Optional.ofNullable(IChatBaseComponent.a(customName)));
}
public void setCustomNameVisible(Boolean customNameVisible) {
this.customNameVisible.a(customNameVisible);
}
public void setSilent(Boolean silent) {
this.silent.a(silent);
}
public void setGravity(Boolean gravity) {
this.gravity.a(gravity);
}
public void setPose(Pose pose) {
this.pose.a(pose.getNMSPose());
}
public void setFrozenTicks(Integer frozenTicks) {
this.frozenTicks.a(frozenTicks);
}
public void setShaking(boolean shaking) {
this.setFrozenTicks(shaking ? 140 : 0);
}
public void setHandStatus(HandStatus handStatus) {
this.handStatus.a((byte) HandStatus.createMask(handStatus));
}
public void setHealth(Float health) {
this.health.a(health);
}
public void setPotionEffectColor(Integer potionEffectColor) {
this.potionEffectColor.a(potionEffectColor);
}
public void setIsPotionEffectAmbient(Boolean isPotionEffectAmbient) {
this.isPotionEffectAmbient.a(isPotionEffectAmbient);
}
public void setArrowsInEntity(Integer arrowsInEntity) {
this.arrowsInEntity.a(arrowsInEntity);
}
public void setAbsorptionHealth(Integer absorptionHealth) {
this.absorptionHealth.a(absorptionHealth);
}
public void setSleepingBedLocation(BlockPosition sleepingBedLocation) {
this.sleepingBedLocation.a(Optional.ofNullable(sleepingBedLocation));
}
public void setAdditionalHearts(Float additionalHearts) {
this.additionalHearts.a(additionalHearts);
}
public void setScore(Integer score) {
this.score.a(score);
}
public void setSkinStatus(SkinStatus... skinStatus) {
this.skinStatus.a((byte) SkinStatus.createMask(skinStatus));
}
public void setHand(Hand hand) {
this.hand.a((byte) hand.getType());
}
public void setLeftShoulder(NBTTagCompound leftShoulder) {
this.leftShoulder.a(leftShoulder);
}
public void setRightShoulder(NBTTagCompound rightShoulder) {
this.rightShoulder.a(rightShoulder);
}
public List<DataWatcher.Item<?>> getList() {
return list;
}
private static <T> DataWatcher.Item<T> a(int index, T value) {
DataWatcherSerializer<?> serializer = null;
if(value instanceof Byte) {
serializer = DataWatcherRegistry.a;
} else if(value instanceof Float) {
serializer = DataWatcherRegistry.c;
} else if(value instanceof Integer) {
serializer = DataWatcherRegistry.b;
} else if(value instanceof String) {
serializer = DataWatcherRegistry.d;
} else if(value instanceof Boolean) {
serializer = DataWatcherRegistry.i;
} else if(value instanceof NBTTagCompound) {
serializer = DataWatcherRegistry.p;
} else if(value instanceof BlockPosition) {
serializer = DataWatcherRegistry.m;
} else if(value instanceof IChatBaseComponent) {
serializer = DataWatcherRegistry.e;
} else if(value instanceof EntityPose) {
serializer = DataWatcherRegistry.s;
}
return a(index, value, (DataWatcherSerializer<T>)serializer);
}
private static <T> DataWatcher.Item<T> a(int index, T value, DataWatcherSerializer<T> serializer) {
return new DataWatcher.Item<T>(new DataWatcherObject<T>(index, serializer), value);
}
}
public static class TeamFeatures {
private boolean nameTagVisible;
private boolean collision;
private GlowColor glowColor;
public TeamFeatures() {
this(true, true, GlowColor.NONE);
}
public TeamFeatures(boolean nameTagVisible, boolean collision, GlowColor glowColor) {
this.nameTagVisible = nameTagVisible;
this.collision = collision;
this.glowColor = glowColor;
}
public boolean isNameTagVisible() {
return nameTagVisible;
}
public void setNameTagVisible(boolean nameTagVisible) {
this.nameTagVisible = nameTagVisible;
}
public boolean isCollision() {
return collision;
}
public void setCollision(boolean collision) {
this.collision = collision;
}
public GlowColor getGlowColor() {
return glowColor;
}
public void setGlowColor(GlowColor glowColor) {
this.glowColor = glowColor;
}
}
public enum EntityState {
DEFAULT(0x00),
ON_FIRE(0x01),
@Deprecated CROUCHING(0x02),
@Deprecated UNUSED(0x04),
SPRINTING(0x08),
SWIMMING(0x10),
INVISIBLE(0x20),
GLOWING(0x40),
FLYING(0x80),
ALL(0xFF);
private final int mask;
EntityState(int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
public static int createMask(EntityState... entityStates) {
int mask = 0;
for(EntityState entityState : entityStates) {
mask |= entityState.mask;
}
return mask;
}
public static EntityState[] fromMask(int mask) {
List<EntityState> list = new ArrayList<>();
for(EntityState entityState : values()) {
if((entityState.mask & mask) == entityState.mask) {
list.add(entityState);
}
}
return list.toArray(new EntityState[list.size()]);
}
}
public enum SkinStatus {
CAPE_ENABLED(0x01),
JACKET_ENABLED(0x02),
LEFT_SLEEVE_ENABLED(0x04),
RIGHT_SLEEVE_ENABLED(0x08),
LEFT_PANTS_LEG_ENABLED(0x10),
RIGHT_PANTS_LEG_ENABLED(0x20),
HAT_ENABLED(0x40),
@Deprecated UNUSED(0x80),
ALL_ENABLED(0xFF);
private final int mask;
SkinStatus(int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
public static int createMask(SkinStatus... skinStatuses) {
int mask = 0;
for(SkinStatus handStatus : skinStatuses) {
mask |= handStatus.mask;
}
return mask;
}
public static SkinStatus[] fromMask(int mask) {
List<SkinStatus> list = new ArrayList<>();
for(SkinStatus skinStatus : values()) {
if((skinStatus.mask & mask) == skinStatus.mask) {
list.add(skinStatus);
}
}
return list.toArray(new SkinStatus[list.size()]);
}
}
public enum Pose {
STANDING(EntityPose.a),
FALL_FLYING(EntityPose.b),
SLEEPING(EntityPose.c),
SWIMMING(EntityPose.d),
SPIN_ATTACK(EntityPose.e),
CROUCHING(EntityPose.f),
LONG_JUMPING(EntityPose.g),
DYING(EntityPose.h);
private final EntityPose nmsPose;
Pose(EntityPose nmsPose) {
this.nmsPose = nmsPose;
}
public EntityPose getNMSPose() {
return nmsPose;
}
public static Pose from(EntityPose entityPose) {
for(Pose pose : values()) {
if(pose.nmsPose == entityPose) {
return pose;
}
}
return null;
}
}
public enum PlayerInfo {
ADD_PLAYER(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a),
UPDATE_GAME_MODE(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.b),
UPDATE_LATENCY(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.c),
UPDATE_DISPLAY_NAME(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.d),
REMOVE_PLAYER(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e);
private final PacketPlayOutPlayerInfo.EnumPlayerInfoAction nmsAction;
PlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction nmsAction) {
this.nmsAction = nmsAction;
}
public PacketPlayOutPlayerInfo.EnumPlayerInfoAction getNMSAction() {
return nmsAction;
}
}
public enum Ping {
NO_CONNECTION(-1),
ONE_BAR(1000),
TWO_BARS(999),
THREE_BARS(599),
FOUR_BARS(299),
FIVE_BARS(149);
private final int milliseconds;
Ping(int milliseconds) {
this.milliseconds = milliseconds;
}
public int getMilliseconds() {
return milliseconds;
}
}
public enum ItemSlot {
MAIN_HAND(EnumItemSlot.a),
OFF_HAND(EnumItemSlot.b),
BOOTS(EnumItemSlot.c),
LEGGINGS(EnumItemSlot.d),
CHESTPLATE(EnumItemSlot.e),
HELMET(EnumItemSlot.f);
private final EnumItemSlot nmsItemSlot;
ItemSlot(EnumItemSlot nmsItemSlot) {
this.nmsItemSlot = nmsItemSlot;
}
public EnumItemSlot getNMSItemSlot() {
return nmsItemSlot;
}
}
public enum HandStatus {
MAIN_HAND(0x00),
HAND_ACTIVE(0x01),
OFF_HAND(0x02),
RIPTIDE_SPIN_ATTACK(0x04),
ALL(0x07);
private final int mask;
HandStatus(int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
public static int createMask(HandStatus... handStatuses) {
int mask = 0;
for(HandStatus handStatus : handStatuses) {
mask |= handStatus.mask;
}
return mask;
}
public static HandStatus[] fromMask(int mask) {
List<HandStatus> list = new ArrayList<>();
for(HandStatus handStatus : values()) {
if((handStatus.mask & mask) == handStatus.mask) {
list.add(handStatus);
}
}
return list.toArray(new HandStatus[list.size()]);
}
}
public enum Hand {
LEFT(0),
RIGHT(1);
private final int type;
Hand(int type) {
this.type = type;
}
public int getType() {
return type;
}
public static Hand fromByte(byte type) {
for(Hand hand : values()) {
if(type == hand.type) {
return hand;
}
}
return null;
}
}
public enum GlowColor {
BLACK(EnumChatFormat.a),
DARK_BLUE(EnumChatFormat.b),
DARK_GREEN(EnumChatFormat.c),
DARK_AQUA(EnumChatFormat.d),
DARK_RED(EnumChatFormat.e),
DARK_PURPLE(EnumChatFormat.f),
GOLD(EnumChatFormat.g),
GRAY(EnumChatFormat.h),
DARK_GRAY(EnumChatFormat.i),
BLUE(EnumChatFormat.j),
GREEN(EnumChatFormat.k),
AQUA(EnumChatFormat.l),
RED(EnumChatFormat.m),
LIGHT_PURPLE(EnumChatFormat.n),
YELLOW(EnumChatFormat.o),
WHITE(EnumChatFormat.p),
NONE(EnumChatFormat.v);
private final EnumChatFormat nmsColor;
GlowColor(EnumChatFormat nmsColor) {
this.nmsColor = nmsColor;
}
public EnumChatFormat getNMSColor() {
return nmsColor;
}
}
public enum GameMode {
SURVIVAL(EnumGamemode.a),
CREATIVE(EnumGamemode.b),
ADVENTURE(EnumGamemode.c),
SPECTATOR(EnumGamemode.d);
private final EnumGamemode nmsGameMode;
GameMode(EnumGamemode nmsGameMode) {
this.nmsGameMode = nmsGameMode;
}
public EnumGamemode getNMSGameMode() {
return nmsGameMode;
}
}
public enum Animation {
SWING_MAIN_HAND(0),
TAKE_DAMAGE(1),
LEAVE_BED(2),
SWING_OFFHAND(3),
CRITICAL_EFFECT(4),
MAGIC_CRITICAL_EFFECT(5);
private final int type;
Animation(int type) {
this.type = type;
}
public int getType() {
return type;
}
}
private void unsafe(UnsafeRunnable run) {
try {
run.run();
} catch (Exception e) {
e.printStackTrace();
}
}
private <T> T createDataSerializer(UnsafeFunction<PacketDataSerializer, T> callback) {
PacketDataSerializer data = new PacketDataSerializer(Unpooled.buffer());
T result = null;
try {
result = callback.apply(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
data.release();
}
return result;
}
public static class SkinTextures {
private static final String TEXTURE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false";
private static final String UUID_URL = "https://api.mojang.com/profiles/minecraft";
private final String texture;
private final String signature;
public SkinTextures(String textures, String signature) {
this.texture = textures;
this.signature = signature;
}
public String getTexture() {
return texture;
}
public String getSignature() {
return signature;
}
public static void getByUsername(Plugin plugin, String username, BiConsumer<Boolean, SkinTextures> callback) {
new BukkitRunnable(){
@Override
public void run() {
JSONArray array = new JSONArray();
array.add(username);
UUID result = null;
try {
HttpRequest request = HttpRequest.newBuilder(new URI(UUID_URL))
.setHeader("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(array.toString()))
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if(response.statusCode() == HttpURLConnection.HTTP_OK) {
JSONArray uuidArray = (JSONArray) new JSONParser().parse(response.body());
if(uuidArray.size() > 0) {
String uuidStr = (String) ((JSONObject) uuidArray.get(0)).get("id");
result = UUID.fromString(uuidStr.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
}
}
} catch (URISyntaxException | InterruptedException | IOException | ParseException e) {
e.printStackTrace();
}
if(result == null) {
new BukkitRunnable(){
@Override
public void run() {
callback.accept(false, null);
}
}.runTask(plugin);
} else {
SkinTextures.getByUUID(plugin, result, callback);
}
}
}.runTaskAsynchronously(plugin);
}
public static void getByUUID(Plugin plugin, UUID uuid, BiConsumer<Boolean, SkinTextures> callback) {
new BukkitRunnable(){
@Override
public void run() {
SkinTextures result = null;
try {
HttpRequest request = HttpRequest.newBuilder(new URI(String.format(TEXTURE_URL, uuid.toString().replace("-", ""))))
.timeout(Duration.ofSeconds(5))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if(response.statusCode() == HttpURLConnection.HTTP_OK) {
JSONArray properties = (JSONArray) ((JSONObject) new JSONParser().parse(response.body())).get("properties");
for(int t = 0; t < properties.size(); t++) {
JSONObject obj = (JSONObject) properties.get(t);
if(obj.containsKey("name") && obj.get("name").equals("textures")) {
result = new SkinTextures((String)obj.get("value"), (String)obj.get("signature"));
}
}
}
} catch (URISyntaxException | InterruptedException | IOException | ParseException e) {
e.printStackTrace();
}
final SkinTextures skinTextures = result;
new BukkitRunnable(){
@Override
public void run() {
if(skinTextures == null) {
callback.accept(false, null);
} else {
callback.accept(true, skinTextures);
}
}
}.runTask(plugin);
}
}.runTaskAsynchronously(plugin);
}
public static CompletableFuture<SkinTextures> getByUsername(String username) {
return CompletableFuture.supplyAsync(()->{
JSONArray array = new JSONArray();
array.add(username);
UUID result = null;
try {
HttpRequest request = HttpRequest.newBuilder(new URI(UUID_URL))
.setHeader("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(array.toString()))
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
JSONArray uuidArray = (JSONArray) new JSONParser().parse(response.body());
if (uuidArray.size() > 0) {
String uuidStr = (String) ((JSONObject) uuidArray.get(0)).get("id");
result = UUID.fromString(uuidStr.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
}
}
} catch (URISyntaxException | InterruptedException | IOException | ParseException e) {
e.printStackTrace();
}
if(result == null)
throw new IllegalArgumentException("SkinTextures not found by username");
else {
return getByUUID(result).join();
}
});
}
public static CompletableFuture<SkinTextures> getByUUID(UUID uuid) {
return CompletableFuture.supplyAsync(()->{
SkinTextures result = null;
try {
HttpRequest request = HttpRequest.newBuilder(new URI(String.format(TEXTURE_URL, uuid.toString().replace("-", ""))))
.timeout(Duration.ofSeconds(5))
.GET().build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
JSONArray properties = (JSONArray) ((JSONObject) new JSONParser().parse(response.body())).get("properties");
for (int t = 0; t < properties.size(); t++) {
JSONObject obj = (JSONObject) properties.get(t);
if (obj.containsKey("name") && obj.get("name").equals("textures")) {
result = new SkinTextures((String) obj.get("value"), (String) obj.get("signature"));
}
}
}
} catch (URISyntaxException | InterruptedException | IOException | ParseException e) {
e.printStackTrace();
}
if(result==null)
throw new IllegalArgumentException("SkinTextures not found by uuid");
else
return result;
});
}
}
@FunctionalInterface
private interface UnsafeRunnable {
void run() throws Exception;
}
@FunctionalInterface
private interface UnsafeFunction<K, T> {
T apply(K k) throws Exception;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment