Commit 5bc7fb79 authored by Ashijin's avatar Ashijin
Browse files

1.19 support part 1

parent 344459d8
......@@ -52,6 +52,12 @@
<version>${mccosmetics.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.lumine</groupId>
<artifactId>MCCosmetics-v1_19_R1</artifactId>
<version>${mccosmetics.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
......
......@@ -13,8 +13,8 @@
</organization>
<properties>
<mccosmetics.version>0.5.0-SNAPSHOT</mccosmetics.version>
<paperapi.version>1.18.2-R0.1-SNAPSHOT</paperapi.version>
<mccosmetics.version>0.6.0-SNAPSHOT</mccosmetics.version>
<paperapi.version>1.19-R0.1-SNAPSHOT</paperapi.version>
<lumineutils.version>1.18-SNAPSHOT</lumineutils.version>
<lombok.version>1.18.22</lombok.version>
<!--suppress UnresolvedMavenProperty -->
......@@ -34,6 +34,7 @@
<module>v1_17_R1</module>
<module>v1_18_R1</module>
<module>v1_18_R2</module>
<module>v1_19_R1</module>
<module>dist</module>
<module>dist-premium</module>
</modules>
......
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>MCCosmetics-v1_19_R1</artifactId>
<parent>
<groupId>io.lumine</groupId>
<artifactId>MCCosmetics-Plugin</artifactId>
<version>${mccosmetics.version}</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-obf</id>
<configuration>
<srgIn>org.spigotmc:minecraft-server:1.19-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.19-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies>
<remappedArtifactAttached>true</remappedArtifactAttached>
<remappedClassifierName>remapped-obf</remappedClassifierName>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-spigot</id>
<configuration>
<inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile>
<srgIn>org.spigotmc:minecraft-server:1.19-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.19-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>nexus</id>
<url>https://mvn.lumine.io/repository/maven/</url>
</repository>
<repository>
<id>lumine</id>
<url>https://mvn.lumine.io/repository/maven-private/</url>
</repository>
<repository>
<id>lumine-snapshots</id>
<url>https://mvn.lumine.io/repository/maven-snapshots/</url>
</repository>
<repository>
<id>lumine-test</id>
<url>https://mvn.lumine.io/repository/maven-test/</url>
</repository>
<repository>
<id>minecraft-libraries</id>
<name>Minecraft Libraries</name>
<url>https://libraries.minecraft.net</url>
</repository>
</repositories>
<dependencies>
<!-- Modules -->
<dependency>
<groupId>io.lumine</groupId>
<artifactId>LumineUtils</artifactId>
<version>${lumineutils.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.lumine</groupId>
<artifactId>MCCosmetics</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- Spigot API -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.19-R0.1-SNAPSHOT</version>
<classifier>shaded</classifier>
<scope>provided</scope>
</dependency>
<!-- Spigot NMS version -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.19-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>datafixerupper</artifactId>
<version>1.0.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.68.Final</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-beta4</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package io.lumine.cosmetics.nms;
import com.google.common.collect.Maps;
import io.lumine.cosmetics.MCCosmeticsPlugin;
import io.lumine.cosmetics.api.cosmetics.Cosmetic;
import io.lumine.cosmetics.managers.back.BackAccessory;
import io.lumine.cosmetics.managers.gestures.Gesture;
import io.lumine.cosmetics.managers.hats.Hat;
import io.lumine.cosmetics.managers.offhand.Offhand;
import io.lumine.cosmetics.managers.sprays.Spray;
import io.lumine.cosmetics.nms.cosmetic.VolatileCosmeticHelper;
import io.lumine.cosmetics.nms.v1_19_R1.cosmetic.*;
import io.lumine.cosmetics.nms.v1_19_R1.network.VolatileChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import lombok.Getter;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.Map;
public class VolatileCodeEnabled_v1_19_R1 implements VolatileCodeHandler {
@Getter private final MCCosmeticsPlugin plugin;
private final Map<Class<? extends Cosmetic>, VolatileCosmeticHelper> cosmeticHelpers = Maps.newConcurrentMap();
public VolatileCodeEnabled_v1_19_R1(MCCosmeticsPlugin plugin) {
this.plugin = plugin;
cosmeticHelpers.put(Hat.class, new VolatileHatImpl(plugin, this));
cosmeticHelpers.put(BackAccessory.class, new VolatileBackImpl(plugin, this));
cosmeticHelpers.put(Spray.class, new VolatileSprayImpl(plugin, this));
cosmeticHelpers.put(Offhand.class, new VolatileOffhandImpl(plugin, this));
cosmeticHelpers.put(Gesture.class, new VolatileGestureImpl(plugin, this));
}
@Override
public VolatileCosmeticHelper getCosmeticHelper(Class<? extends Cosmetic> tClass) {
return cosmeticHelpers.get(tClass);
}
@Override
public Collection<VolatileCosmeticHelper> getCosmeticHelpers() {
return cosmeticHelpers.values();
}
@Override
public void injectPlayer(Player player) {
ServerPlayer ply = ((CraftPlayer) player).getHandle();
VolatileChannelHandler cdh = new VolatileChannelHandler(player, this);
ChannelPipeline pipeline = ply.connection.getConnection().channel.pipeline();
for (String name : pipeline.toMap().keySet()) {
if (pipeline.get(name) instanceof Connection) {
pipeline.addBefore(name, "mc_cosmetics_packet_handler", cdh);
break;
}
}
}
@Override
public void removePlayer(Player player) {
Channel channel = ((CraftPlayer) player).getHandle().connection.getConnection().channel;
channel.eventLoop().submit(() -> {
channel.pipeline().remove("mc_cosmetics_packet_handler");
return null;
});
}
public void broadcast(Packet<?>... packets) {
for(Player player : Bukkit.getOnlinePlayers()) {
var connection = ((CraftPlayer) player).getHandle().connection;
for(Packet<?> packet : packets) {
connection.send(packet);
}
}
}
public void broadcast(Player player, Packet<?>... packets) {
var connection = ((CraftPlayer) player).getHandle().connection;
for(Packet<?> packet : packets) {
connection.send(packet);
}
}
public void broadcastAroundAndSelf(Player wearer, Packet<?>... packets) {
final var level = ((CraftWorld) wearer.getWorld()).getHandle();
final var trackedEntity = level.getChunkSource().chunkMap.entityMap.get(wearer.getEntityId());
if(trackedEntity == null) {
broadcast(wearer.getWorld(), packets);
return;
}
for(Packet<?> packet : packets)
trackedEntity.broadcastAndSend(packet);
}
public void broadcastAround(Player wearer, Packet<?>... packets) {
final var level = ((CraftWorld) wearer.getWorld()).getHandle();
final var trackedEntity = level.getChunkSource().chunkMap.entityMap.get(wearer.getEntityId());
if(trackedEntity == null) {
broadcast(wearer.getWorld(), packets);
return;
}
for(Packet<?> packet : packets)
trackedEntity.broadcast(packet);
}
public void broadcast(World world, Packet<?>... packets) {
for(Player player : world.getPlayers()) {
var connection = ((CraftPlayer) player).getHandle().connection;
for(Packet<?> packet : packets) {
connection.send(packet);
}
}
}
public Entity getEntity(World world, int id) {
ServerLevel level = ((CraftWorld) world).getHandle();
final var entityManager = level.entityManager;
final var entity = entityManager.getEntityGetter().get(id);
return entity == null ? null : entity.getBukkitEntity();
}
@Override
public void removeFakeEntity(int id) {
ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(id);
broadcast(packet);
}
@Override
public void setBodyYaw(LivingEntity entity, double yaw) {
((CraftLivingEntity) entity).getHandle().yBodyRot = (float) yaw;
}
@Override
public float getBodyYaw(LivingEntity entity) {
return ((CraftLivingEntity) entity).getHandle().yBodyRot;
}
}
package io.lumine.cosmetics.nms.v1_19_R1.cosmetic;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import io.lumine.cosmetics.MCCosmeticsPlugin;
import io.lumine.cosmetics.api.cosmetics.Cosmetic;
import io.lumine.cosmetics.api.cosmetics.ItemCosmetic;
import io.lumine.cosmetics.api.players.CosmeticProfile;
import io.lumine.cosmetics.logging.MCLogger;
import io.lumine.cosmetics.managers.back.BackAccessory;
import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R1;
import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper;
import io.lumine.cosmetics.players.Profile;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.decoration.ArmorStand;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class VolatileBackImpl implements VolatileEquipmentHelper {
@Getter
private final MCCosmeticsPlugin plugin;
private final VolatileCodeEnabled_v1_19_R1 nmsHandler;
private final Map<Player, ArmorStand> activeProfile = Maps.newConcurrentMap();
private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap();
public VolatileBackImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R1 nmsHandler) {
this.plugin = plugin;
this.nmsHandler = nmsHandler;
}
@Override
public void apply(CosmeticProfile profile) {
if (profile == null)
return;
Player player = profile.getPlayer();
var maybeEquipped = profile.getEquipped(BackAccessory.class);
if(maybeEquipped.isEmpty()) {
return;
}
var equipped = maybeEquipped.get();
var cosmetic = equipped.getCosmetic();
if (!(cosmetic instanceof ItemCosmetic back)) {
return;
}
var nmsPlayer = ((CraftPlayer) player).getHandle();
var nmsBack = CraftItemStack.asNMSCopy(back.getCosmetic(equipped.getVariant()));
ArmorStand stand = activeProfile.get(player);
if(stand == null) {
playerTracker.put(player.getEntityId(), player);
stand = new ArmorStand(EntityType.ARMOR_STAND, ((CraftWorld) player.getWorld()).getHandle());
stand.moveTo(nmsPlayer.getX(), nmsPlayer.getY() + nmsPlayer.getPassengersRidingOffset() + stand.getMyRidingOffset(), nmsPlayer.getZ(), nmsPlayer.getYRot(), 0);
stand.setMarker(true);
stand.setInvisible(true);
stand.setSilent(true);
activeProfile.put(player, stand);
var mobPacket = new ClientboundAddEntityPacket(stand);
var dataPacket = new ClientboundSetEntityDataPacket(stand.getId(), stand.getEntityData(), true);
var passengersPacket = createPassengerPacket(player.getEntityId(), stand.getId());
nmsHandler.broadcastAroundAndSelf(player, mobPacket, dataPacket, passengersPacket);
}
stand.setItemSlot(EquipmentSlot.HEAD, nmsBack);
var equipmentPacket = new ClientboundSetEquipmentPacket(stand.getId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsBack)));
nmsHandler.broadcastAroundAndSelf(player, equipmentPacket);
}
@Override
public void unapply(CosmeticProfile profile) {
Player player = profile.getPlayer();
ArmorStand stand = activeProfile.remove(player);
if(stand == null)
return;
playerTracker.remove(player.getEntityId());
ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(stand.getId());
nmsHandler.broadcastAroundAndSelf(player, removePacket);
}
@Override
public boolean read(Player sender, Object packet, boolean isCanceled) {
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(sender);
if(profile == null || profile.isHidden(BackAccessory.class))
return true;
if(packet instanceof ServerboundMovePlayerPacket) {
handleRotate(profile);
}else if(packet instanceof ServerboundAcceptTeleportationPacket) {
final var list = handleSpawn(profile);
if(list == null)
return true;
final var connection = ((CraftPlayer) sender).getHandle().connection;
for(Object obj : list) {
connection.send((Packet<?>) obj);
}
}
return true;
}
@Override
public List<Object> write(Player receiver, Object packet) {
if(packet instanceof ClientboundAddPlayerPacket playerPacket) {
int id = playerPacket.getEntityId();
if(playerTracker.containsKey(id)) {
final var spawnedPlayer = playerTracker.get(id);
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer);
if(profile == null || profile.isHidden(BackAccessory.class))
return null;
return handleSpawn(profile);
}
}else if(packet instanceof ClientboundRemoveEntitiesPacket removePacket) {
for(int id : removePacket.getEntityIds()) {
if(playerTracker.containsKey(id)) {
return handleDespawn(playerTracker.get(id));
}
}
}
/*
else if(packet instanceof ClientboundMoveEntityPacket moveEntityPacket) {
FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer());
moveEntityPacket.write(byteBuf);
int id = byteBuf.readVarInt();
if(playerTracker.containsKey(id)) {
final var spawnedPlayer = playerTracker.get(id);
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer);
if(profile == null || profile.isHidden(BackAccessory.class))
return null;
return handleMove(profile, moveEntityPacket);
}
}else if(packet instanceof ClientboundTeleportEntityPacket teleportEntityPacket) {
int id = teleportEntityPacket.getId();
if(playerTracker.containsKey(id)) {
final var spawnedPlayer = playerTracker.get(id);
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer);
if(profile == null || profile.isHidden(BackAccessory.class))
return null;
return handleTeleport(profile);
}
}*/
return null;
}
private void handleRotate(Profile profile) {
if(!hasBack(profile))
return;
final var wearer = profile.getPlayer();
final var nmsPlayer = ((CraftPlayer) wearer).getHandle();
final var stand = activeProfile.get(wearer);
ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(stand, VolatileEquipmentHelper.toByte(nmsPlayer.getYRot()));
nmsHandler.broadcastAroundAndSelf(wearer, packet);
}
private List<Object> handleSpawn(Profile profile) {
if(!hasBack(profile))
return null;
final var wearer = profile.getPlayer();
final var stand = activeProfile.get(wearer);
var mobPacket = new ClientboundAddEntityPacket(stand);
ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(stand.getId(), stand.getEntityData(), true);
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(stand.getId(), List.of(Pair.of(EquipmentSlot.HEAD, stand.getItemBySlot(EquipmentSlot.HEAD))));
ClientboundSetPassengersPacket passengersPacket = createPassengerPacket(wearer.getEntityId(), stand.getId());
return List.of(mobPacket, dataPacket, equipmentPacket, passengersPacket);
}
private List<Object> handleDespawn(Player player) {
final var stand = activeProfile.get(player);
if(stand == null)
return null;
ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(stand.getId());
return List.of(removePacket);
}
private List<Object> handleMove(Profile profile, ClientboundMoveEntityPacket moveEntityPacket) {
if(!hasBack(profile))
return null;
final var wearer = profile.getPlayer();
final var stand = activeProfile.get(wearer);
ClientboundMoveEntityPacket move;
if(moveEntityPacket.hasPosition() && moveEntityPacket.hasRotation()) {
move = new ClientboundMoveEntityPacket.PosRot(
stand.getId(),
moveEntityPacket.getXa(),
moveEntityPacket.getYa(),
moveEntityPacket.getZa(),
moveEntityPacket.getyRot(),
moveEntityPacket.getxRot(),
false);
}else if(moveEntityPacket.hasPosition()) {
move = new ClientboundMoveEntityPacket.Pos(
stand.getId(),
moveEntityPacket.getXa(),
moveEntityPacket.getYa(),
moveEntityPacket.getZa(),
false);
}else {
move = new ClientboundMoveEntityPacket.Rot(
stand.getId(),
moveEntityPacket.getyRot(),
moveEntityPacket.getxRot(),
false);
}
return List.of(move);
}
private List<Object> handleTeleport(Profile profile) {
if(!hasBack(profile))
return null;
final var wearer = profile.getPlayer();
final var nmsPlayer = ((CraftPlayer) wearer).getHandle();
final var stand = activeProfile.get(wearer);
stand.moveTo(nmsPlayer.getX(), nmsPlayer.getY() + nmsPlayer.getPassengersRidingOffset() + stand.getMyRidingOffset(), nmsPlayer.getZ(), nmsPlayer.getYRot(), 0);
return List.of(new ClientboundTeleportEntityPacket(stand));
}
private boolean hasBack(Profile profile) {
if(profile == null)
return false;
var maybeBack = profile.getEquipped(BackAccessory.class);
return maybeBack.isPresent() && maybeBack.get().getCosmetic() instanceof ItemCosmetic && activeProfile.containsKey(profile.getPlayer());
}
private ClientboundSetPassengersPacket createPassengerPacket(int mount, int... driver) {
FriendlyByteBuf bb = new FriendlyByteBuf(Unpooled.buffer());
bb.writeVarInt(mount);
bb.writeVarIntArray(driver);
return new ClientboundSetPassengersPacket(bb);
}
}
\ No newline at end of file
package io.lumine.cosmetics.nms.v1_19_R1.cosmetic;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import io.lumine.cosmetics.MCCosmeticsPlugin;
import io.lumine.cosmetics.api.cosmetics.manager.HideableCosmetic;
import io.lumine.cosmetics.api.players.CosmeticProfile;
import io.lumine.cosmetics.managers.gestures.Gesture;
import io.lumine.cosmetics.managers.gestures.GestureManager;
import io.lumine.cosmetics.managers.gestures.QuitMethod;
import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R1;
import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper;
import io.lumine.cosmetics.players.Profile;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.game.*;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.animal.horse.Horse;
import net.minecraft.world.item.ItemStack;
import org.bukkit.attribute.Attribute;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.attribute.CraftAttributeMap;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class VolatileGestureImpl implements VolatileEquipmentHelper {
private static final List<Pair<EquipmentSlot, ItemStack>> empty = new ArrayList<>();
static {
for(final var slot : EquipmentSlot.values())
empty.add(Pair.of(slot, ItemStack.EMPTY));
}
@Getter
private final MCCosmeticsPlugin plugin;
private final VolatileCodeEnabled_v1_19_R1 nmsHandler;
private final Set<Player> activeProfile = Sets.newConcurrentHashSet();
private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap();
private Horse horse;
public VolatileGestureImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R1 nmsHandler) {
this.plugin = plugin;
this.nmsHandler = nmsHandler;
}
@Override
public void apply(CosmeticProfile profile) {
if (profile == null)
return;
Player player = profile.getPlayer();
if(activeProfile.contains(player))
return;
final var maybeEquipped = profile.getEquipped(Gesture.class);
if(maybeEquipped.isEmpty()) {
return;
}
var opt = maybeEquipped.get().getCosmetic();
if(!(opt instanceof Gesture gesture))
return;
playerTracker.put(player.getEntityId(), player);
activeProfile.add(player);
if(!gesture.isCanMove())
getHorsed(player);
player.setInvisible(true);
for(final var value : ((Profile) profile).getEquipped().values()) {
final var manager = value.getCosmetic().getManager();
if(!(manager instanceof HideableCosmetic hide))
continue;
hide.hide(profile, gesture);
}
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), empty);
nmsHandler.broadcastAroundAndSelf(player, equipmentPacket);
}
@Override
public void unapply(CosmeticProfile profile) {
if (profile == null)
return;
Player player = profile.getPlayer();
if(!activeProfile.contains(player))
return;
activeProfile.remove(player);
playerTracker.remove(player.getEntityId());
nmsHandler.broadcast(player, new ClientboundRemoveEntitiesPacket(horse.getId()));
final var nmsPlayer = ((CraftPlayer) player).getHandle();
List<Pair<EquipmentSlot, ItemStack>> equipment = new ArrayList<>();
for(EquipmentSlot slot : EquipmentSlot.values())
equipment.add(Pair.of(slot, nmsPlayer.getItemBySlot(slot)));
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), equipment);
nmsHandler.broadcastAroundAndSelf(player, equipmentPacket);
player.setInvisible(false);
for(final var value : ((Profile) profile).getEquipped().values()) {
final var manager = value.getCosmetic().getManager();
if(!(manager instanceof HideableCosmetic hide))
continue;
hide.show(profile);
}
}
private ClientboundSetPassengersPacket createPassengerPacket(int mount, int... driver) {
FriendlyByteBuf bb = new FriendlyByteBuf(Unpooled.buffer());
bb.writeVarInt(mount);
bb.writeVarIntArray(driver);
return new ClientboundSetPassengersPacket(bb);
}
private void getHorsed(Player player) {
final var nmsPlayer = ((CraftPlayer) player).getHandle();
if(horse == null) {
horse = new Horse(EntityType.HORSE, ((CraftWorld) player.getWorld()).getHandle());
horse.setInvisible(true);
horse.setHealth(0);
horse.getAttribute(CraftAttributeMap.toMinecraft(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(0);
}
horse.setPos(nmsPlayer.getX(), nmsPlayer.getY() - horse.getPassengersRidingOffset() - nmsPlayer.getMyRidingOffset(), nmsPlayer.getZ());
var mobPacket = new ClientboundAddEntityPacket(horse);
var dataPacket = new ClientboundSetEntityDataPacket(horse.getId(), horse.getEntityData(), true);
var attributesPacket = new ClientboundUpdateAttributesPacket(horse.getId(), horse.getAttributes().getSyncableAttributes());
var passengersPacket = createPassengerPacket(horse.getId(), nmsPlayer.getId());
nmsHandler.broadcast(player, mobPacket, dataPacket, attributesPacket, passengersPacket);
}
@Override
public boolean read(Player sender, Object packet, boolean isCanceled) {
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(sender);
if(profile == null)
return true;
final var maybeEquipped = profile.getEquipped(Gesture.class);
if(maybeEquipped.isEmpty()) {
return true;
}
var opt = maybeEquipped.get().getCosmetic();
if(!(opt instanceof Gesture gesture))
return true;
if(packet instanceof ServerboundPlayerInputPacket inputPacket) {
final var manager = (GestureManager) gesture.getManager();
if(inputPacket.isShiftKeyDown())
manager.quit(sender, QuitMethod.SNEAK);
if(inputPacket.isJumping())
manager.quit(sender, QuitMethod.JUMP);
}else if(packet instanceof ServerboundSetCarriedItemPacket setSlotPacket) {
int oSlot = sender.getInventory().getHeldItemSlot();
if(oSlot != setSlotPacket.getSlot()) {
nmsHandler.broadcast(sender, new ClientboundSetCarriedItemPacket(oSlot));
return false;
}
}
return true;
}
@Override
public List<Object> write(Player receiver, Object packet) {
if(packet instanceof ClientboundSetEquipmentPacket equipmentPacket) {
int id = equipmentPacket.getEntity();
final var spawnedPlayer = playerTracker.get(id);
if(spawnedPlayer == null)
return null;
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer);
if(profile != null)
return List.of(new ClientboundSetEquipmentPacket(id, empty));
}
return null;
}
}
package io.lumine.cosmetics.nms.v1_19_R1.cosmetic;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import io.lumine.cosmetics.MCCosmeticsPlugin;
import io.lumine.cosmetics.api.cosmetics.ItemCosmetic;
import io.lumine.cosmetics.api.players.CosmeticProfile;
import io.lumine.cosmetics.managers.hats.Hat;
import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R1;
import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper;
import io.lumine.cosmetics.players.Profile;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket;
import net.minecraft.world.entity.EquipmentSlot;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Map;
public class VolatileHatImpl implements VolatileEquipmentHelper {
@Getter private final MCCosmeticsPlugin plugin;
private final VolatileCodeEnabled_v1_19_R1 nmsHandler;
private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap();
public VolatileHatImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R1 nmsHandler) {
this.plugin = plugin;
this.nmsHandler = nmsHandler;
}
@Override
public void apply(CosmeticProfile profile) {
if (profile == null)
return;
Player player = profile.getPlayer();
final var maybeEquipped = profile.getEquipped(Hat.class);
if(maybeEquipped.isEmpty()) {
return;
}
var opt = maybeEquipped.get().getCosmetic();
if(!(opt instanceof Hat hat))
return;
var nmsHat = CraftItemStack.asNMSCopy(hat.getCosmetic(maybeEquipped.get().getVariant()));
playerTracker.put(player.getEntityId(), player);
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsHat)));
nmsHandler.broadcastAroundAndSelf(player, equipmentPacket);
}
@Override
public void unapply(CosmeticProfile profile) {
final var nmsPlayer = ((CraftPlayer) profile.getPlayer()).getHandle();
final var item = nmsPlayer.getItemBySlot(EquipmentSlot.HEAD);
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(nmsPlayer.getId(), List.of(Pair.of(EquipmentSlot.HEAD, item)));
nmsHandler.broadcastAroundAndSelf(nmsPlayer.getBukkitEntity(), equipmentPacket);
}
@Override
public boolean read(Player sender, Object packet, boolean isCanceled) {
if(packet instanceof ServerboundAcceptTeleportationPacket) {
final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(sender);
if(profile == null || profile.isHidden(Hat.class))
return true;
handleSpawn(profile);
}
return true;
}
@Override
public List<Object> write(Player receiver, Object packet) {
if(packet instanceof ClientboundAddPlayerPacket playerPacket) {
int id = playerPacket.getEntityId();
Profile profile = getProfile(receiver, id);
if(profile != null && !profile.isHidden(Hat.class)) {
handleSpawn(profile);
}
}else if(packet instanceof ClientboundSetEquipmentPacket equipmentPacket) {
int id = equipmentPacket.getEntity();
Profile profile = getProfile(receiver, id);
if(profile != null && !profile.isHidden(Hat.class)) {
handleSpawn(profile);
}
}
return null;
}
private Profile getProfile(Player receiver, int id) {
final var entity = nmsHandler.getEntity(receiver.getWorld(), id);
if(!(entity instanceof Player player))
return null;
return plugin.getProfiles().getProfile(player);
}
public void handleSpawn(Profile profile) {
final var maybeEquipped = profile.getEquipped(Hat.class);
if(maybeEquipped.isEmpty()) {
return;
}
var equip = maybeEquipped.get();
var opt = equip.getCosmetic();
if(!(opt instanceof ItemCosmetic hat))
return;
final var player = profile.getPlayer();
final var nmsHat = CraftItemStack.asNMSCopy(hat.getCosmetic(equip.getVariant()));
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsHat)));
FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer());
byteBuf.writeByte(80);
equipmentPacket.write(byteBuf);
final var pipeline = ((CraftPlayer) player).getHandle().connection.getConnection().channel.pipeline();
pipeline.writeAndFlush(byteBuf);
}
}
package io.lumine.cosmetics.nms.v1_19_R1.cosmetic;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import io.lumine.cosmetics.MCCosmeticsPlugin;
import io.lumine.cosmetics.api.cosmetics.ItemCosmetic;
import io.lumine.cosmetics.api.players.CosmeticProfile;
import io.lumine.cosmetics.managers.offhand.Offhand;
import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R1;
import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper;
import io.lumine.cosmetics.players.Profile;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.world.entity.EquipmentSlot;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Map;
public class VolatileOffhandImpl implements VolatileEquipmentHelper {
@Getter private final MCCosmeticsPlugin plugin;
private final VolatileCodeEnabled_v1_19_R1 nmsHandler;
private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap();
public VolatileOffhandImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R1 nmsHandler) {
this.plugin = plugin;
this.nmsHandler = nmsHandler;
}
@Override
public void apply(CosmeticProfile profile) {
if (profile == null)
return;
Player player = profile.getPlayer();
final var maybeEquipped = profile.getEquipped(Offhand.class);
if(maybeEquipped.isEmpty()) {
return;
}
var equip = maybeEquipped.get();
var opt = equip.getCosmetic();
if(!(opt instanceof ItemCosmetic offhand))
return;
var nmsOffhand = CraftItemStack.asNMSCopy(offhand.getCosmetic(equip.getVariant()));
playerTracker.put(player.getEntityId(), player);
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.OFFHAND, nmsOffhand)));
nmsHandler.broadcastAroundAndSelf(player, equipmentPacket);
}
@Override
public void unapply(CosmeticProfile profile) {
final var nmsPlayer = ((CraftPlayer) profile.getPlayer()).getHandle();
final var item = nmsPlayer.getItemBySlot(EquipmentSlot.OFFHAND);
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(nmsPlayer.getId(), List.of(Pair.of(EquipmentSlot.OFFHAND, item)));
nmsHandler.broadcastAroundAndSelf(nmsPlayer.getBukkitEntity(), equipmentPacket);
}
@Override
public List<Object> write(Player receiver, Object packet) {
if(packet instanceof ClientboundAddPlayerPacket playerPacket) {
int id = playerPacket.getEntityId();
Profile profile = getProfile(receiver, id);
if(profile != null && !profile.isHidden(Offhand.class))
handleSpawn(profile);
}else if(packet instanceof ClientboundSetEquipmentPacket equipmentPacket) {
int id = equipmentPacket.getEntity();
Profile profile = getProfile(receiver, id);
if(profile != null && !profile.isHidden(Offhand.class))
handleSpawn(profile);
}
return null;
}
private Profile getProfile(Player receiver, int id) {
final var entity = nmsHandler.getEntity(receiver.getWorld(), id);
if(!(entity instanceof Player player))
return null;
return plugin.getProfiles().getProfile(player);
}
public void handleSpawn(Profile profile) {
final var maybeEquipped = profile.getEquipped(Offhand.class);
if(maybeEquipped.isEmpty()) {
return;
}
var equip = maybeEquipped.get();
var opt = equip.getCosmetic();
if(!(opt instanceof ItemCosmetic offhand))
return;
final var player = profile.getPlayer();
final var nmsOffhand = CraftItemStack.asNMSCopy(offhand.getCosmetic(equip.getVariant()));
ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.OFFHAND, nmsOffhand)));
FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer());
byteBuf.writeByte(80);
equipmentPacket.write(byteBuf);
final var pipeline = ((CraftPlayer) player).getHandle().connection.getConnection().channel.pipeline();
pipeline.writeAndFlush(byteBuf);
}
}
package io.lumine.cosmetics.nms.v1_19_R1.cosmetic;
import io.lumine.cosmetics.MCCosmeticsPlugin;
import io.lumine.cosmetics.managers.sprays.Spray;
import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R1;
import io.lumine.cosmetics.nms.cosmetic.VolatileSprayHelper;
import lombok.Getter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
public class VolatileSprayImpl implements VolatileSprayHelper {
@Getter private final MCCosmeticsPlugin plugin;
private final VolatileCodeEnabled_v1_19_R1 nmsHandler;
public VolatileSprayImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R1 nmsHandler) {
this.plugin = plugin;
this.nmsHandler = nmsHandler;
}
private static final ItemStack map = new ItemStack(Material.FILLED_MAP);
private static final MapMeta mapMeta = (MapMeta) map.getItemMeta();
@Override
public int drawSpray(Spray spray, Location location, BlockFace face, int rotation) {
var world = ((CraftWorld) location.getWorld()).getHandle();
var pos = new BlockPos(location.getX(), location.getY(), location.getZ());
var image = spray.getImage();
mapMeta.setMapId(image.getMapNumber());
map.setItemMeta(mapMeta);
var nmsMap = CraftItemStack.asNMSCopy(map);
final int dir = switch(face) {
case DOWN -> 0;
case UP -> 1;
case NORTH -> 2;
case SOUTH -> 3;
case WEST -> 4;
case EAST -> 5;
default -> 1;
};
var frame = new ItemFrame(world, pos, Direction.UP);
frame.setItem(nmsMap);
frame.setInvisible(true);
frame.setRotation(rotation);
var packetAdd = new ClientboundAddEntityPacket(frame, dir);
var packetData = new ClientboundSetEntityDataPacket(frame.getId(), frame.getEntityData(), true);
var packetMap = constructMapPacket(image.getMapNumber(), image.getPixels());
nmsHandler.broadcast(packetAdd, packetData, packetMap);
return frame.getId();
}
private static final int startX = 0;
private static final int startY = 0;
private static final int mapWidth = 128;
private static final int mapHeight = 128;
private static final byte mapScale = 1;
private static final boolean mapLocked = true;
private ClientboundMapItemDataPacket constructMapPacket(int id, byte[] pixels) {
var mapData = constructMapData(startX, startY, mapWidth, mapHeight, pixels);
var packet = new ClientboundMapItemDataPacket(id, mapScale, mapLocked, null, mapData);
return packet;
}
private MapItemSavedData.MapPatch constructMapData(int startX, int startY, int width, int height, byte[] pixels) {
return new MapItemSavedData.MapPatch(startX, startY, width, height, pixels);
}
}
package io.lumine.cosmetics.nms.v1_19_R1.network;
import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R1;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import lombok.Getter;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class VolatileChannelHandler extends ChannelDuplexHandler {
private final VolatileCodeEnabled_v1_19_R1 nmsHandler;
@Getter private final Player player;
public VolatileChannelHandler(Player player, VolatileCodeEnabled_v1_19_R1 nmsHandler) {
this.player = player;
this.nmsHandler = nmsHandler;
}
@Override
public void write(ChannelHandlerContext ctx, Object obj, ChannelPromise promise) {
try {
List<Object> packets = new ArrayList<>();
for(final var helper : nmsHandler.getCosmeticHelpers()) {
final var writes = helper.write(player, obj);
if(writes != null)
packets.addAll(writes);
}
if(!packets.contains(obj))
super.write(ctx, obj, promise);
packets.remove(obj);
for (var p : packets) {
super.write(ctx, p, promise.channel().newPromise());
}
}catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
boolean isCanceled = false;
for(final var helper : nmsHandler.getCosmeticHelpers()) {
isCanceled |= !helper.read(player, obj, isCanceled);
}
if(!isCanceled)
super.channelRead(ctx, obj);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment