Equipment and EquipmentSlot now have their own class;

ItemStack#AIR added;
NPC#getMainHand, getOffHand, getHelmet, getChestPlate, getLeggings, getBoots added;
NPCManager#updateEquipment;

PlayerManager#sendPacket works again
This commit is contained in:
retrooper committed 2022-01-13 22:03:26 +01:00
1 parent 56ebeffda1
commit 79f176221a
11 files changed
+321 -107

No files matched your search

@@ -20,6 +20,7 @@ package com.github.retrooper.packetevents.manager.npc;
import com.github.retrooper.packetevents.protocol.chat.component.BaseComponent;
import com.github.retrooper.packetevents.protocol.chat.component.impl.TextComponent;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.player.GameProfile;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.Location;
@@ -31,6 +32,12 @@ public class NPC {
private final GameProfile profile;
private int displayPing = 0;
private Location location = new Location(0.0, 0.0, 0.0, 0.0f, 0.0f);
private ItemStack mainHand = null;
private ItemStack offHand = null;
private ItemStack helmet = null;
private ItemStack chestPlate = null;
private ItemStack leggings = null;
private ItemStack boots = null;
public NPC(BaseComponent displayName, int entityId, GameProfile profile) {
this.displayName = displayName;
@@ -38,6 +45,54 @@ public class NPC {
this.profile = profile;
}
public ItemStack getMainHand() {
return mainHand;
}
public void setMainHand(ItemStack mainHand) {
this.mainHand = mainHand;
}
public ItemStack getOffHand() {
return offHand;
}
public void setOffHand(ItemStack offHand) {
this.offHand = offHand;
}
public ItemStack getHelmet() {
return helmet;
}
public void setHelmet(ItemStack helmet) {
this.helmet = helmet;
}
public ItemStack getChestplate() {
return chestPlate;
}
public void setChestplate(ItemStack chestPlate) {
this.chestPlate = chestPlate;
}
public ItemStack getLeggings() {
return leggings;
}
public void setLeggings(ItemStack leggings) {
this.leggings = leggings;
}
public ItemStack getBoots() {
return boots;
}
public void setBoots(ItemStack boots) {
this.boots = boots;
}
public BaseComponent getDisplayName() {
return displayName;
}
@@ -19,7 +19,11 @@
package com.github.retrooper.packetevents.manager.npc;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.channel.ChannelAbstract;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.player.Equipment;
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.wrapper.play.server.*;
@@ -169,4 +173,56 @@ public class NPCManager {
}
}
}
public void updateEquipment(NPC npc) {
Set<ChannelAbstract> targetChannels = TARGET_CHANNELS.get(npc);
if (targetChannels != null && !targetChannels.isEmpty()) {
for (ChannelAbstract channel : targetChannels) {
List<Equipment> equipmentList = new ArrayList<>();
ItemStack handItem = npc.getMainHand();
if (handItem == null) {
handItem = ItemStack.AIR;
}
equipmentList.add(new Equipment(EquipmentSlot.MAINHAND,
handItem));
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
ItemStack offHandItem = npc.getOffHand();
if (offHandItem == null) {
offHandItem = ItemStack.AIR;
}
equipmentList.add(new Equipment(EquipmentSlot.OFFHAND,
offHandItem));
}
ItemStack helmetItem = npc.getHelmet();
if (helmetItem == null) {
helmetItem = ItemStack.AIR;
}
equipmentList.add(new Equipment(EquipmentSlot.HELMET,
helmetItem));
ItemStack chestPlateItem = npc.getChestplate();
if (chestPlateItem == null) {
chestPlateItem = ItemStack.AIR;
}
equipmentList.add(new Equipment(EquipmentSlot.CHESTPLATE,
chestPlateItem));
ItemStack leggingsItem = npc.getLeggings();
if (leggingsItem == null) {
leggingsItem = ItemStack.AIR;
}
equipmentList.add(new Equipment(EquipmentSlot.LEGGINGS,
leggingsItem));
ItemStack bootsItem = npc.getBoots();
if (bootsItem == null) {
bootsItem = ItemStack.AIR;
}
equipmentList.add(new Equipment(EquipmentSlot.BOOTS,
bootsItem));
WrapperPlayServerEntityEquipment equipmentPacket
= new WrapperPlayServerEntityEquipment(npc.getId(),
equipmentList);
}
}
}
}
@@ -23,10 +23,13 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.buffer.ByteBufAbstract;
import com.github.retrooper.packetevents.netty.channel.ChannelAbstract;
import com.github.retrooper.packetevents.protocol.ConnectionState;
import com.github.retrooper.packetevents.protocol.player.GameProfile;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.Equipment;
import com.github.retrooper.packetevents.protocol.player.GameProfile;
import com.github.retrooper.packetevents.util.PacketTransformationUtil;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
@@ -101,24 +104,10 @@ public interface PlayerManager {
}
default void sendPacket(ChannelAbstract channel, PacketWrapper<?> wrapper) {
boolean shouldSend = true;
if (wrapper instanceof WrapperPlayServerDestroyEntities) {
WrapperPlayServerDestroyEntities destroyEntities = (WrapperPlayServerDestroyEntities) wrapper;
if (destroyEntities.getEntityIds().length > 1 && wrapper.getServerVersion() == ServerVersion.V_1_17) {
//Transform into multiple packets
for (int entityId : destroyEntities.getEntityIds()) {
WrapperPlayServerDestroyEntities newPacket = new WrapperPlayServerDestroyEntities(entityId);
newPacket.prepareForSend();
//Duplicate buffer
sendPacket(channel, newPacket.buffer);
shouldSend = false;
}
}
}
if (shouldSend) {
wrapper.prepareForSend();
//We duplicate the buffer, so the user can send the same wrapper object multiple times
sendPacket(channel, wrapper.buffer);
PacketWrapper<?>[] wrappers = PacketTransformationUtil.transform(wrapper);
for (PacketWrapper<?> packet : wrappers) {
packet.prepareForSend();
sendPacket(channel, packet.buffer);
}
}
@@ -133,22 +122,10 @@ public interface PlayerManager {
}
default void sendPacketSilently(ChannelAbstract channel, PacketWrapper<?> wrapper) {
boolean shouldSend = true;
if (wrapper instanceof WrapperPlayServerDestroyEntities) {
WrapperPlayServerDestroyEntities destroyEntities = (WrapperPlayServerDestroyEntities) wrapper;
if (destroyEntities.getEntityIds().length > 1 && wrapper.getServerVersion() == ServerVersion.V_1_17) {
//Transform into multiple packets
for (int entityId : destroyEntities.getEntityIds()) {
WrapperPlayServerDestroyEntities newPacket = new WrapperPlayServerDestroyEntities(entityId);
newPacket.prepareForSend();
sendPacketSilently(channel, newPacket.buffer);
shouldSend = false;
}
}
}
if (shouldSend) {
wrapper.prepareForSend();
sendPacketSilently(channel, wrapper.buffer);
PacketWrapper<?>[] wrappers = PacketTransformationUtil.transform(wrapper);
for (PacketWrapper<?> packet : wrappers) {
packet.prepareForSend();
sendPacketSilently(channel, packet.buffer);
}
}
@@ -30,6 +30,7 @@ import java.util.List;
public class ItemStack {
public static final ItemStack EMPTY = new ItemStack(ItemTypes.AIR, -1, new NBTCompound(), -1);
public static final ItemStack AIR = new ItemStack(ItemTypes.AIR, ItemTypes.AIR.getMaxAmount(), new NBTCompound(), 0);
private final ItemType type;
private int amount;
private NBTCompound nbt;
@@ -0,0 +1,56 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.player;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
public class Equipment {
private EquipmentSlot slot;
private ItemStack item;
public Equipment(EquipmentSlot slot, ItemStack item) {
this.slot = slot;
this.item = item;
}
public EquipmentSlot getSlot() {
return slot;
}
public void setSlot(EquipmentSlot slot) {
this.slot = slot;
}
public ItemStack getItem() {
return item;
}
public void setItem(ItemStack item) {
this.item = item;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Equipment) {
Equipment equipment = (Equipment) obj;
return equipment.getSlot() == slot && equipment.getItem().equals(item);
}
return false;
}
}
@@ -0,0 +1,56 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.player;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import org.jetbrains.annotations.Nullable;
public enum EquipmentSlot {
MAINHAND(0),
OFFHAND(0),
BOOTS(1),
LEGGINGS(2),
CHESTPLATE(3),
HELMET(4);
private byte legacyId;
EquipmentSlot(int legacyId) {
this.legacyId =(byte) legacyId;
}
public int getId(ServerVersion version) {
if (version.isOlderThan(ServerVersion.V_1_9)) {
return legacyId;
}
else {
return ordinal();
}
}
@Nullable
public static EquipmentSlot getById(ServerVersion version, int id) {
for (EquipmentSlot slot : values()) {
if (slot.getId(version) == id) {
return slot;
}
}
return null;
}
}
@@ -0,0 +1,58 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.util;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.Equipment;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
public class PacketTransformationUtil {
public static PacketWrapper<?>[] transform(PacketWrapper<?> wrapper) {
if (wrapper instanceof WrapperPlayServerDestroyEntities) {
WrapperPlayServerDestroyEntities destroyEntities = (WrapperPlayServerDestroyEntities) wrapper;
int len = destroyEntities.getEntityIds().length;
if (wrapper.getServerVersion() == ServerVersion.V_1_17 && len > 1) {
//Transform into multiple packets
PacketWrapper<?>[] output = new PacketWrapper[len];
for (int i = 0; i < len; i++) {
int entityId = destroyEntities.getEntityIds()[i];
output[i] = new WrapperPlayServerDestroyEntities(entityId);
}
//TODO Potentially free the previous buffer
return output;
}
} else if (wrapper instanceof WrapperPlayServerEntityEquipment) {
WrapperPlayServerEntityEquipment entityEquipment = (WrapperPlayServerEntityEquipment) wrapper;
int len = entityEquipment.getEquipment().size();
if (entityEquipment.getServerVersion().isOlderThan(ServerVersion.V_1_16) && len > 1) {
//Transform into multiple packets
PacketWrapper<?>[] output = new PacketWrapper[len];
for (int i = 0; i < len; i++) {
Equipment equipment = entityEquipment.getEquipment().get(i);
output[i] = new WrapperPlayServerEntityEquipment(entityEquipment.getEntityId(), equipment);
}
//TODO Potentially free the previous buffer
return output;
}
}
return new PacketWrapper<?>[]{wrapper};
}
}
@@ -22,7 +22,10 @@ import com.github.retrooper.packetevents.event.impl.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.Equipment;
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -58,7 +61,7 @@ public class WrapperPlayServerEntityEquipment extends PacketWrapper<WrapperPlayS
byte value;
do {
value = readByte();
EquipmentSlot equipmentSlot = EquipmentSlot.getById(value & Byte.MAX_VALUE);
EquipmentSlot equipmentSlot = EquipmentSlot.getById(serverVersion, value & Byte.MAX_VALUE);
ItemStack itemStack = readItemStack();
equipment.add(new Equipment(equipmentSlot, itemStack));
} while ((value & Byte.MIN_VALUE) != 0);
@@ -66,10 +69,10 @@ public class WrapperPlayServerEntityEquipment extends PacketWrapper<WrapperPlayS
else {
EquipmentSlot slot;
if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_9)) {
slot = EquipmentSlot.getById(readVarInt());
slot = EquipmentSlot.getById(serverVersion, readVarInt());
}
else {
slot = EquipmentSlot.getById(readShort());
slot = EquipmentSlot.getById(serverVersion, readShort());
}
equipment.add(new Equipment(slot, readItemStack()));
}
@@ -93,17 +96,17 @@ public class WrapperPlayServerEntityEquipment extends PacketWrapper<WrapperPlayS
for (int i = 0; i < this.equipment.size(); i++) {
Equipment equipment = this.equipment.get(i);
boolean last = i == (this.equipment.size() - 1);
writeByte(last ? equipment.getSlot().getId() : (equipment.getSlot().getId() | Byte.MIN_VALUE));
writeByte(last ? equipment.getSlot().getId(serverVersion) : (equipment.getSlot().getId(serverVersion) | Byte.MIN_VALUE));
writeItemStack(equipment.getItem());
}
}
else {
Equipment equipment = this.equipment.get(0);
if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_9)) {
writeVarInt(equipment.getSlot().getId());
writeVarInt(equipment.getSlot().getId(serverVersion));
}
else {
writeShort(equipment.getSlot().getId());
writeShort(equipment.getSlot().getId(serverVersion));
}
writeItemStack(equipment.getItem());
}
@@ -124,48 +127,4 @@ public class WrapperPlayServerEntityEquipment extends PacketWrapper<WrapperPlayS
public void setEquipment(List<Equipment> equipment) {
this.equipment = equipment;
}
public enum EquipmentSlot {
MAINHAND,
OFFHAND,
BOOTS,
LEGGINGS,
CHESTPLATE,
HELMET;
public int getId() {
return ordinal();
}
public static EquipmentSlot getById(int id) {
return values()[id];
}
}
public static class Equipment {
private EquipmentSlot slot;
private ItemStack item;
public Equipment(EquipmentSlot slot, ItemStack item) {
this.slot = slot;
this.item = item;
}
public EquipmentSlot getSlot() {
return slot;
}
public void setSlot(EquipmentSlot slot) {
this.slot = slot;
}
public ItemStack getItem() {
return item;
}
public void setItem(ItemStack item) {
this.item = item;
}
}
}
@@ -30,6 +30,7 @@ import com.github.retrooper.packetevents.protocol.chat.component.impl.TextCompon
import com.github.retrooper.packetevents.protocol.chat.component.impl.TranslatableComponent;
import com.github.retrooper.packetevents.protocol.entity.data.provider.EntityDataProvider;
import com.github.retrooper.packetevents.protocol.entity.data.provider.PlayerDataProvider;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameProfile;
@@ -69,7 +70,7 @@ public class PacketEventsPlugin extends JavaPlugin {
PacketEvents.getAPI().getSettings().debug(true).bStats(false);
PacketListenerAbstract debugListener = new PacketListenerAbstract(PacketListenerPriority.NORMAL, true) {
PacketListenerAbstract debugListener = new PacketListenerAbstract(PacketListenerPriority.NORMAL, false) {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
Player player = event.getPlayer() == null ? null : (Player) event.getPlayer();
@@ -135,7 +136,7 @@ public class PacketEventsPlugin extends JavaPlugin {
WrapperPlayServerBlockChange bc = new WrapperPlayServerBlockChange(event);
Vector3i pos = bc.getBlockPosition();
WrappedBlockState state = WrappedBlockState.getByGlobalId(bc.getBlockId());
}/* else if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
} else if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
WrapperPlayServerSpawnLivingEntity spawnLivingEntity = new WrapperPlayServerSpawnLivingEntity(event);
if (spawnLivingEntity.getEntityType().equals(EntityTypes.PIG)) {
event.setCancelled(true);
@@ -152,8 +153,10 @@ public class PacketEventsPlugin extends JavaPlugin {
targetLocation);
npc.setLocation(targetLocation);
PacketEvents.getAPI().getNPCManager().spawn(event.getChannel(), npc);
//npc.setMainHand(handItem);
}
}*/ else if (event.getPacketType() == PacketType.Play.Server.CHAT_MESSAGE) {
} else if (event.getPacketType() == PacketType.Play.Server.CHAT_MESSAGE) {
WrapperPlayServerChatMessage cm = new WrapperPlayServerChatMessage(event);
BaseComponent component = cm.getChatComponent();
if (component instanceof TextComponent) {
@@ -193,7 +196,7 @@ public class PacketEventsPlugin extends JavaPlugin {
}
}
};
//PacketEvents.getAPI().getEventManager().registerListener(debugListener);
PacketEvents.getAPI().getEventManager().registerListener(debugListener);
}
@@ -59,11 +59,12 @@ public class PacketEncoderModern extends MessageToByteEncoder<Object> {
if (needsCompress) {
recompress(ctx, byteBuf);
}
if (packetSendEvent.getPostTask() != null) {
//TODO Post-task
/*if (packetSendEvent.getPostTask() != null) {
((ChannelHandlerContext) ctx.rawChannelHandlerContext()).newPromise().addListener(f -> {
packetSendEvent.getPostTask().run();
});
}
}*/
} else {
//Make the buffer unreadable for the next handlers
byteBuf.clear();
@@ -81,12 +82,14 @@ public class PacketEncoderModern extends MessageToByteEncoder<Object> {
e.printStackTrace();
}
} else {
out.writeBytes((ByteBuf) o);
}
if (out.isReadable()) {
//byteBuf is released in the handle method
handle(PacketEvents.getAPI().getNettyManager().wrapChannelHandlerContext(ctx), PacketEvents.getAPI().getNettyManager().wrapByteBuf(out));
ByteBuf in = (ByteBuf) o;
if (in.isReadable()) {
out.writeBytes(in);
} else {
return;
}
}
handle(PacketEvents.getAPI().getNettyManager().wrapChannelHandlerContext(ctx), PacketEvents.getAPI().getNettyManager().wrapByteBuf(out));
}
private boolean handleCompressionOrder(ChannelHandlerContextAbstract ctx, ByteBufAbstract buf) {
@@ -107,17 +107,7 @@ public class PlayerManagerImpl implements PlayerManager {
@Override
public void sendPacket(ChannelAbstract channel, ByteBufAbstract byteBuf) {
if (channel.isOpen()) {
//Call our own encoder
ChannelHandlerAbstract handler = channel.pipeline().get(PacketEvents.ENCODER_NAME);
ChannelHandlerContextAbstract ctx = channel.pipeline().context(PacketEvents.ENCODER_NAME);
ByteBufAbstract output = PacketEvents.getAPI().getNettyManager().buffer();
try {
CustomPipelineUtil.callEncode(handler.rawChannelHandler(), ctx.rawChannelHandlerContext(), byteBuf.rawByteBuf(), output.rawByteBuf());
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//Now call the encoders after ours
channel.pipeline().context(PacketEvents.ENCODER_NAME).writeAndFlush(byteBuf);
channel.writeAndFlush(byteBuf);
}
}