Rework the component array modifier to work in 1.9.4 and up
Fixes #215
Dieser Commit ist enthalten in:
Ursprung
a995866d5b
Commit
e34105e754
@ -17,9 +17,6 @@
|
|||||||
|
|
||||||
package com.comphenix.protocol.events;
|
package com.comphenix.protocol.events;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
@ -105,11 +102,16 @@ import com.comphenix.protocol.wrappers.WrappedServerPing;
|
|||||||
import com.comphenix.protocol.wrappers.WrappedStatistic;
|
import com.comphenix.protocol.wrappers.WrappedStatistic;
|
||||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||||
|
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||||
|
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Minecraft packet indirectly.
|
* Represents a Minecraft packet indirectly.
|
||||||
*
|
*
|
||||||
@ -659,15 +661,19 @@ public class PacketContainer implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Retrieves a read/write structure for arrays of chat components.
|
* Retrieves a read/write structure for arrays of chat components.
|
||||||
* <p>
|
* <p>
|
||||||
* This modifier will automatically marshall between WrappedChatComponent and the
|
* This modifier will automatically marshal between WrappedChatComponent and the
|
||||||
* internal Minecraft IChatBaseComponent.
|
* internal Minecraft IChatBaseComponent (1.9.2 and below) or the internal
|
||||||
|
* NBTCompound (1.9.4 and up).
|
||||||
|
* <p>
|
||||||
|
* Note that in 1.9.4 and up this modifier only works properly with sign
|
||||||
|
* tile entities.
|
||||||
* @return A modifier for ChatComponent array fields.
|
* @return A modifier for ChatComponent array fields.
|
||||||
*/
|
*/
|
||||||
public StructureModifier<WrappedChatComponent[]> getChatComponentArrays() {
|
public StructureModifier<WrappedChatComponent[]> getChatComponentArrays() {
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.<WrappedChatComponent[]>withType(
|
return structureModifier.<WrappedChatComponent[]>withType(
|
||||||
MinecraftReflection.getIChatBaseComponentArrayClass(),
|
ComponentArrayConverter.getGenericType(),
|
||||||
BukkitConverters.getIgnoreNull(new WrappedChatComponentArrayConverter()));
|
BukkitConverters.getIgnoreNull(new ComponentArrayConverter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1076,7 +1082,7 @@ public class PacketContainer implements Serializable {
|
|||||||
* Construct a new packet data serializer.
|
* Construct a new packet data serializer.
|
||||||
* @return The packet data serializer.
|
* @return The packet data serializer.
|
||||||
*/
|
*/
|
||||||
private ByteBuf createPacketBuffer() {
|
public static ByteBuf createPacketBuffer() {
|
||||||
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
|
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
|
||||||
Class<?> packetSerializer = MinecraftReflection.getPacketDataSerializerClass();
|
Class<?> packetSerializer = MinecraftReflection.getPacketDataSerializerClass();
|
||||||
|
|
||||||
@ -1224,11 +1230,11 @@ public class PacketContainer implements Serializable {
|
|||||||
* Represents an equivalent converter for ChatComponent arrays.
|
* Represents an equivalent converter for ChatComponent arrays.
|
||||||
* @author dmulloy2
|
* @author dmulloy2
|
||||||
*/
|
*/
|
||||||
private static class WrappedChatComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
private static class LegacyComponentConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||||
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
|
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getGeneric(Class<?>genericType, WrappedChatComponent[] specific) {
|
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
|
||||||
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
|
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
|
||||||
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
|
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
|
||||||
|
|
||||||
@ -1257,6 +1263,94 @@ public class PacketContainer implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts from NBT to WrappedChatComponent arrays
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
|
private static class NBTComponentConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||||
|
private EquivalentConverter<NbtBase<?>> nbtConverter = BukkitConverters.getNbtConverter();
|
||||||
|
private final int lines = 4;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WrappedChatComponent[] getSpecific(Object generic) {
|
||||||
|
NbtBase<?> nbtBase = nbtConverter.getSpecific(generic);
|
||||||
|
NbtCompound compound = (NbtCompound) nbtBase;
|
||||||
|
|
||||||
|
WrappedChatComponent[] components = new WrappedChatComponent[lines];
|
||||||
|
for (int i = 0; i < lines; i++) {
|
||||||
|
if (compound.containsKey("Text" + (i + 1))) {
|
||||||
|
components[i] = WrappedChatComponent.fromJson(compound.getString("Text" + (i + 1)));
|
||||||
|
} else {
|
||||||
|
components[i] = WrappedChatComponent.fromText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
|
||||||
|
NbtCompound compound = NbtFactory.ofCompound("");
|
||||||
|
|
||||||
|
for (int i = 0; i < lines; i++) {
|
||||||
|
WrappedChatComponent component;
|
||||||
|
if (i < specific.length && specific[i] != null) {
|
||||||
|
component = specific[i];
|
||||||
|
} else {
|
||||||
|
component = WrappedChatComponent.fromText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
compound.put("Text" + (i + 1), component.getJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nbtConverter.getGeneric(genericType, compound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<WrappedChatComponent[]> getSpecificType() {
|
||||||
|
return WrappedChatComponent[].class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A delegated converter that supports NBT to Component Array and regular Component Array
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
|
private static class ComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||||
|
private static final EquivalentConverter<WrappedChatComponent[]> DELEGATE;
|
||||||
|
static {
|
||||||
|
Class<?> packetClass = PacketType.Play.Server.UPDATE_SIGN.getPacketClass();
|
||||||
|
if (packetClass.getName().contains("Sign")) {
|
||||||
|
DELEGATE = new LegacyComponentConverter();
|
||||||
|
} else {
|
||||||
|
DELEGATE = new NBTComponentConverter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WrappedChatComponent[] getSpecific(Object generic) {
|
||||||
|
return DELEGATE.getSpecific(generic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
|
||||||
|
return DELEGATE.getGeneric(genericType, specific);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<WrappedChatComponent[]> getSpecificType() {
|
||||||
|
return DELEGATE.getSpecificType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<?> getGenericType() {
|
||||||
|
if (DELEGATE instanceof NBTComponentConverter) {
|
||||||
|
return MinecraftReflection.getNBTCompoundClass();
|
||||||
|
} else {
|
||||||
|
return MinecraftReflection.getIChatBaseComponentArrayClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]";
|
return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]";
|
||||||
|
@ -520,6 +520,19 @@ public class PacketContainerTest {
|
|||||||
UPDATE_PROPERTIES;
|
UPDATE_PROPERTIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComponentArrays() {
|
||||||
|
PacketContainer signChange = new PacketContainer(PacketType.Play.Server.TILE_ENTITY_DATA);
|
||||||
|
WrappedChatComponent[] components = new WrappedChatComponent[] {
|
||||||
|
WrappedChatComponent.fromText("hello world"), WrappedChatComponent.fromText(""),
|
||||||
|
WrappedChatComponent.fromText(""), WrappedChatComponent.fromText("")
|
||||||
|
};
|
||||||
|
signChange.getChatComponentArrays().write(0, components);
|
||||||
|
|
||||||
|
WrappedChatComponent[] back = signChange.getChatComponentArrays().read(0);
|
||||||
|
assertArrayEquals(components, back);
|
||||||
|
}
|
||||||
|
|
||||||
private static final List<PacketType> BLACKLISTED = Util.asList(
|
private static final List<PacketType> BLACKLISTED = Util.asList(
|
||||||
PacketType.Play.Client.CUSTOM_PAYLOAD, PacketType.Play.Server.CUSTOM_PAYLOAD,
|
PacketType.Play.Client.CUSTOM_PAYLOAD, PacketType.Play.Server.CUSTOM_PAYLOAD,
|
||||||
PacketType.Play.Server.SET_COOLDOWN
|
PacketType.Play.Server.SET_COOLDOWN
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren