Commit aeaa885a authored by Ash's avatar Ash
Browse files

1.20.3

parent 15868a27
No related merge requests found
Pipeline #9432 failed with stages
in 1 minute and 48 seconds
......@@ -123,6 +123,11 @@
<artifactId>v1_20_R2</artifactId>
<version>v1_20_R2</version>
</dependency>
<dependency>
<groupId>com.ticxo.playeranimator</groupId>
<artifactId>v1_20_R3</artifactId>
<version>v1_20_R3</version>
</dependency>
</dependencies>
</project>
......@@ -12,7 +12,9 @@ import com.ticxo.playeranimator.nms.v1_19_R1.NMSHandler_v1_19_R1;
import com.ticxo.playeranimator.nms.v1_19_R1_2.NMSHandler_v1_19_R1_2;
import com.ticxo.playeranimator.nms.v1_19_R2.NMSHandler_v1_19_R2;
import com.ticxo.playeranimator.nms.v1_19_R3.NMSHandler_v1_19_R3;
import com.ticxo.playeranimator.nms.v1_20_R1.NMSHandler_v1_20_R1;
import com.ticxo.playeranimator.nms.v1_20_R2.NMSHandler_v1_20_R2;
import com.ticxo.playeranimator.nms.v1_20_R3.NMSHandler_v1_20_R3;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
......@@ -73,8 +75,9 @@ public class PlayerAnimatorImpl extends PlayerAnimator {
}
case "v1_19_R2" -> setNms(new NMSHandler_v1_19_R2());
case "v1_19_R3" -> setNms(new NMSHandler_v1_19_R3());
case "v1_20_R1" -> setNms(new NMSHandler_v1_20_R2());
case "v1_20_R1" -> setNms(new NMSHandler_v1_20_R1());
case "v1_20_R2" -> setNms(new NMSHandler_v1_20_R2());
case "v1_20_R3" -> setNms(new NMSHandler_v1_20_R3());
default -> throw new IllegalStateException("Version not supported");
}
}
......
......@@ -21,10 +21,11 @@
<module>v1_19_R3</module>
<module>v1_20_R1</module>
<module>v1_20_R2</module>
<module>v1_20_R3</module>
</modules>
<properties>
<project.api.version>R1.2.7</project.api.version>
<project.api.version>R1.2.8</project.api.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
......
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>PlayerAnimator-parent</artifactId>
<groupId>com.ticxo.playeranimator</groupId>
<version>parent</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>v1_20_R3</artifactId>
<version>v1_20_R3</version>
<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.20.3-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.20.3-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.20.3-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.20.3-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.20.3-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.ticxo.playeranimator</groupId>
<artifactId>api</artifactId>
<version>api</version>
<scope>provided</scope>
</dependency>
<!-- NMS Libraries -->
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.5.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>datafixerupper</artifactId>
<version>5.0.28</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.76.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>authlib</artifactId>
<version>3.5.41</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
package com.ticxo.playeranimator.nms.v1_20_R3;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.ticxo.playeranimator.api.nms.INMSHandler;
import com.ticxo.playeranimator.api.nms.IRangeManager;
import com.ticxo.playeranimator.api.nms.IRenderer;
import com.ticxo.playeranimator.api.texture.TextureWrapper;
import com.ticxo.playeranimator.nms.v1_20_R3.entity.RangeManager;
import com.ticxo.playeranimator.nms.v1_20_R3.entity.RendererImpl;
import com.ticxo.playeranimator.nms.v1_20_R3.network.PAChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.Connection;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Field;
import java.util.UUID;
public class NMSHandler_v1_20_R3 implements INMSHandler {
private Connection getConnection(ServerPlayer player) {
try {
Field f = ServerGamePacketListenerImpl.class.getDeclaredField("c");
f.setAccessible(true);
return (Connection) f.get(player.connection);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1) {
e1.printStackTrace();
}
return null;
}
@Override
public void injectPlayer(Player player) {
ServerPlayer ply = ((CraftPlayer) player).getHandle();
PAChannelHandler cdh = new PAChannelHandler(ply);
Connection connection = getConnection(ply);
if (connection == null) return;
ChannelPipeline pipeline = connection.channel.pipeline();
for (String name : pipeline.toMap().keySet()) {
if (pipeline.get(name) instanceof Connection) {
pipeline.addBefore(name, "player_animator_packet_handler", cdh);
break;
}
}
}
@Override
public void removePlayer(Player player) {
Connection connection = getConnection(((CraftPlayer) player).getHandle());
if (connection == null) return;
Channel channel = connection.channel;
channel.eventLoop().submit(() -> {
channel.pipeline().remove("player_animator_packet_handler");
return null;
});
}
@Override
public IRangeManager createRangeManager(Entity entity) {
ServerLevel level = ((CraftWorld) entity.getWorld()).getHandle();
ChunkMap.TrackedEntity trackedEntity = level.getChunkSource().chunkMap.entityMap.get(entity.getEntityId());
return new RangeManager(trackedEntity);
}
@Override
public IRenderer createRenderer() {
return new RendererImpl();
}
@Override
public String getTexture(Player player) {
return ((CraftPlayer) player).getHandle().getGameProfile().getProperties().get("textures").iterator().next().getValue();
}
@Override
public ItemStack setSkullTexture(ItemStack skull, TextureWrapper texture) {
if (skull == null)
skull = new ItemStack(Material.PLAYER_HEAD);
final var nmsSkull = CraftItemStack.asNMSCopy(skull);
final var tag = nmsSkull.getOrCreateTag();
final var profile = new GameProfile(UUID.randomUUID(), null);
profile.getProperties().put("textures", new Property("textures", texture.toBase64()));
tag.put("SkullOwner", NbtUtils.writeGameProfile(new CompoundTag(), profile));
nmsSkull.setTag(tag);
return CraftItemStack.asBukkitCopy(nmsSkull);
}
}
package com.ticxo.playeranimator.nms.v1_20_R3.entity;
import com.ticxo.playeranimator.api.nms.IRangeManager;
import com.ticxo.playeranimator.api.utils.FieldUtils;
import net.minecraft.server.level.ChunkMap;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
public class RangeManager implements IRangeManager {
private final ChunkMap.TrackedEntity tracked;
public RangeManager(ChunkMap.TrackedEntity tracked) {
this.tracked = tracked;
}
@Override
public void addPlayer(Player player) {
tracked.seenBy.add(((CraftPlayer) player).getHandle().connection);
}
@Override
public void removePlayer(Player player) {
tracked.seenBy.remove(((CraftPlayer) player).getHandle().connection);
}
@Override
public void setRenderDistance(int radius) {
try {
FieldUtils.getField(ChunkMap.TrackedEntity.class, "d").setInt(tracked, radius);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public Set<Player> getPlayerInRange() {
Set<Player> list = new HashSet<>();
tracked.seenBy.forEach(serverPlayerConnection -> list.add(serverPlayerConnection.getPlayer().getBukkitEntity()));
return list;
}
}
package com.ticxo.playeranimator.nms.v1_20_R3.entity;
import com.mojang.datafixers.util.Pair;
import com.ticxo.playeranimator.api.PlayerAnimator;
import com.ticxo.playeranimator.api.model.player.LimbType;
import com.ticxo.playeranimator.api.model.player.PlayerBone;
import com.ticxo.playeranimator.api.nms.IRenderer;
import net.minecraft.core.Rotations;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.entity.AreaEffectCloud;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.item.ItemStack;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.EulerAngle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RendererImpl implements IRenderer {
private final List<Pair<EquipmentSlot, ItemStack>> equipments = new ArrayList<>();
private ArmorStand armorStand;
private AreaEffectCloud cloud;
private PlayerBone limb;
@Override
public void setLimb(PlayerBone limb) {
this.limb = limb;
final var nmsWorld = ((CraftWorld) limb.getModel().getBase().getWorld()).getHandle();
if(armorStand == null)
armorStand = new ArmorStand(EntityType.ARMOR_STAND, nmsWorld);
armorStand.setInvisible(true);
armorStand.setRightArmPose(new Rotations(0, 0, 0));
armorStand.setLeftArmPose(new Rotations(0, 0, 0));
if(cloud == null)
cloud = new AreaEffectCloud(EntityType.AREA_EFFECT_CLOUD, nmsWorld);
cloud.setRadius(0);
cloud.setInvisible(true);
armorStand.startRiding(cloud);
if(limb.getType().isItem()) {
if(!(limb.getModel().getBase() instanceof LivingEntity living))
return;
if(limb.getType() == LimbType.RIGHT_ITEM) {
final var item = living.getEquipment().getItemInMainHand();
equipments.add(Pair.of(EquipmentSlot.MAINHAND, CraftItemStack.asNMSCopy(item)));
}else {
final var item = living.getEquipment().getItemInOffHand();
equipments.add(Pair.of(EquipmentSlot.OFFHAND, CraftItemStack.asNMSCopy(item)));
}
}else {
org.bukkit.inventory.ItemStack playerHead = PlayerAnimator.api.getNms().setSkullTexture(null, limb.getModel().getTexture());
ItemMeta meta = playerHead.getItemMeta();
meta.setCustomModelData(limb.getModel().getTexture().isSlim() ? limb.getType().getSlimId() : limb.getType().getModelId());
playerHead.setItemMeta(meta);
equipments.add(Pair.of(EquipmentSlot.MAINHAND, CraftItemStack.asNMSCopy(playerHead)));
}
}
@Override
public void spawn() {
final var packets = getSpawnPackets();
for(final var player : limb.getModel().getSeenBy())
sendPackets(player, packets);
}
@Override
public void spawn(Player player) {
sendPackets(player, getSpawnPackets());
}
@Override
public void despawn() {
final var packets = getDespawnPackets();
for(final var player : limb.getModel().getSeenBy())
sendPackets(player, packets);
}
@Override
public void despawn(Player player) {
sendPackets(player, getDespawnPackets());
}
@Override
public void update() {
final var packets = getMovePackets();
for(final var player : limb.getModel().getSeenBy())
sendPackets(player, packets);
}
private void sendPackets(Player player, List<Packet<?>> packets) {
ServerGamePacketListenerImpl packetListener = ((CraftPlayer) player).getHandle().connection;
//final var pipeline = ((CraftPlayer) player).getHandle().connection.connection.channel.pipeline();
for(Packet<?> packet : packets)
packetListener.send(packet);
//pipeline.flush();
}
private List<Packet<?>> getSpawnPackets() {
final var finalLocation = limb.getPosition().toLocation(limb.getModel().getBase().getWorld());
cloud.setPos(finalLocation.getX(), finalLocation.getY(), finalLocation.getZ());
armorStand.moveTo(finalLocation.getX(), finalLocation.getY() + armorStand.getMyRidingOffset(cloud), finalLocation.getZ(), limb.getModel().getBaseYaw(), 0);
ClientboundAddEntityPacket asSpawn = new ClientboundAddEntityPacket(armorStand);
ClientboundSetEntityDataPacket asMeta = new ClientboundSetEntityDataPacket(armorStand.getId(), armorStand.getEntityData().getNonDefaultValues());
ClientboundSetEquipmentPacket asEquip = new ClientboundSetEquipmentPacket(armorStand.getId(), equipments);
ClientboundAddEntityPacket aecSpawn = new ClientboundAddEntityPacket(cloud);
ClientboundSetEntityDataPacket aecMeta = new ClientboundSetEntityDataPacket(cloud.getId(), cloud.getEntityData().getNonDefaultValues());
ClientboundSetPassengersPacket mount = new ClientboundSetPassengersPacket(cloud);
return Arrays.asList(asSpawn, asMeta, asEquip, aecSpawn, aecMeta, mount);
}
private List<Packet<?>> getDespawnPackets() {
ClientboundRemoveEntitiesPacket remove = new ClientboundRemoveEntitiesPacket(armorStand.getId(), cloud.getId());
return List.of(remove);
}
private List<Packet<?>> getMovePackets() {
final var finalLocation = limb.getPosition().toLocation(limb.getModel().getBase().getWorld());
final var finalRotation = limb.getRotation();
cloud.setPos(finalLocation.getX(), finalLocation.getY(), finalLocation.getZ());
if(limb.getType() == LimbType.LEFT_ITEM)
armorStand.setLeftArmPose(toNMS(finalRotation));
else
armorStand.setRightArmPose(toNMS(finalRotation));
ClientboundTeleportEntityPacket teleport = new ClientboundTeleportEntityPacket(cloud);
ClientboundMoveEntityPacket.Rot rotate = new ClientboundMoveEntityPacket.Rot(armorStand.getId(), IRenderer.rotByte(limb.getModel().getBaseYaw()), (byte) 0, false);
ClientboundSetEntityDataPacket meta = new ClientboundSetEntityDataPacket(armorStand.getId(), armorStand.getEntityData().getNonDefaultValues());
return Arrays.asList(teleport, rotate, meta);
}
private Rotations toNMS(EulerAngle angle) {
return new Rotations((float)Math.toDegrees(angle.getX()), (float)Math.toDegrees(angle.getY()), (float)Math.toDegrees(angle.getZ()));
}
}
package com.ticxo.playeranimator.nms.v1_20_R3.network;
import com.ticxo.playeranimator.api.PlayerAnimator;
import com.ticxo.playeranimator.api.model.player.PlayerModel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import lombok.Getter;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.entity.LevelEntityGetter;
import org.bukkit.entity.Entity;
import java.lang.reflect.Method;
public class PAChannelHandler extends ChannelDuplexHandler {
private static Method entityGetter;
static {
for(var method : ServerLevel.class.getMethods()) {
if(LevelEntityGetter.class.isAssignableFrom(method.getReturnType()) && method.getReturnType() != LevelEntityGetter.class) {
entityGetter = method;
break;
}
}
}
@Getter private final ServerPlayer player;
public PAChannelHandler(ServerPlayer player) {
this.player = player;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if(msg instanceof ClientboundAddEntityPacket packet) {
handleEntitySpawn(packet.getId());
}else if(msg instanceof ClientboundRemoveEntitiesPacket packet) {
for(int id : packet.getEntityIds()) {
handleEntityDespawn(id);
}
}
super.write(ctx, msg, promise);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
}
private void handleEntitySpawn(int id) {
final var entity = getEntityAsync(player.serverLevel(), id);
PlayerModel model = PlayerAnimator.api.getModelManager().getPlayerModel(entity);
if(model == null)
return;
model.spawn(player.getBukkitEntity());
}
private void handleEntityDespawn(int id) {
final var entity = getEntityAsync(player.serverLevel(), id);
PlayerModel model = PlayerAnimator.api.getModelManager().getPlayerModel(entity);
if(model == null)
return;
model.despawn(player.getBukkitEntity());
}
private Entity getEntityAsync(ServerLevel world, int id) {
final var entity = getEntityGetter(world).get(id);
return entity == null ? null : entity.getBukkitEntity();
}
public static LevelEntityGetter<net.minecraft.world.entity.Entity> getEntityGetter(ServerLevel level) {
if(entityGetter == null)
return level.entityManager.getEntityGetter();
try {
return (LevelEntityGetter<net.minecraft.world.entity.Entity>) entityGetter.invoke(level);
}catch (Throwable ignored) {
return null;
}
}
}
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