Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4649daef82 | ||
|
|
70d47ce622 | ||
|
|
46d40d752e | ||
|
|
a006b70c6f | ||
|
|
e726f6eb0d | ||
|
|
389233f599 | ||
|
|
4051caca0b | ||
|
|
914bc9aa7f | ||
|
|
8272ecb33d | ||
|
|
d13ce24507 | ||
|
|
b6a7d5f91d | ||
|
|
f6b3af4221 |
No files matched your search
+11
-3
@@ -11,7 +11,7 @@ description = 'Provides access to the Minecraft protocol'
|
||||
def isSnapshot = version.endsWith('-SNAPSHOT')
|
||||
|
||||
repositories {
|
||||
// mavenLocal() // can speed up build, but may fail in CI
|
||||
mavenLocal() // can speed up build, but may fail in CI
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
@@ -35,7 +35,7 @@ repositories {
|
||||
dependencies {
|
||||
implementation 'net.bytebuddy:byte-buddy:1.14.14'
|
||||
compileOnly 'org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT'
|
||||
compileOnly 'org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT'
|
||||
compileOnly 'org.spigotmc:spigot:1.21-R0.1-SNAPSHOT:remapped-mojang'
|
||||
compileOnly 'io.netty:netty-all:4.0.23.Final'
|
||||
compileOnly 'net.kyori:adventure-text-serializer-gson:4.14.0'
|
||||
compileOnly 'com.googlecode.json-simple:json-simple:1.1.1'
|
||||
@@ -46,7 +46,7 @@ dependencies {
|
||||
testImplementation 'org.mockito:mockito-core:5.6.0'
|
||||
testImplementation 'io.netty:netty-common:4.1.97.Final'
|
||||
testImplementation 'io.netty:netty-transport:4.1.97.Final'
|
||||
testImplementation 'org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT'
|
||||
testImplementation 'org.spigotmc:spigot:1.21-R0.1-SNAPSHOT:remapped-mojang'
|
||||
testImplementation 'net.kyori:adventure-text-serializer-gson:4.14.0'
|
||||
testImplementation 'net.kyori:adventure-text-serializer-plain:4.14.0'
|
||||
}
|
||||
@@ -59,6 +59,14 @@ java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes(
|
||||
'paperweight-mappings-namespace': 'mojang'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
dependencies {
|
||||
include(dependency('net.bytebuddy:byte-buddy:.*'))
|
||||
|
||||
@@ -14,18 +14,18 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
|
||||
import com.comphenix.protocol.events.ConnectionSide;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.scheduler.UniversalRunnable;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
/**
|
||||
* Represents the type of a packet in a specific protocol.
|
||||
* <p>
|
||||
@@ -229,6 +229,8 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x77, "UpdateRecipes", "RecipeUpdate");
|
||||
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x78, "UpdateTags", "Tags");
|
||||
public static final PacketType PROJECTILE_POWER = new PacketType(PROTOCOL, SENDER, 0x79, "ProjectilePower");
|
||||
public static final PacketType REPORT_DETAILS = new PacketType(PROTOCOL, SENDER, 0x7A, "CustomReportDetails");
|
||||
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x7B, "ServerLinks");
|
||||
|
||||
// ---- Removed in 1.9
|
||||
|
||||
@@ -477,8 +479,12 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x35, "SignUpdate", "UpdateSign", "CPacketUpdateSign");
|
||||
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x36, "Swing", "ArmAnimation", "CPacketAnimation");
|
||||
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x37, "TeleportToEntity", "Spectate", "CPacketSpectate");
|
||||
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x38, "UseItemOn", "UseItem", "CPacketPlayerTryUseItemOnBlock");
|
||||
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x39, "BlockPlace", "CPacketPlayerTryUseItem");
|
||||
|
||||
public static final PacketType USE_ITEM_ON = new PacketType(PROTOCOL, SENDER, 0x38, "UseItemOn");
|
||||
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x39, "UseItem");
|
||||
|
||||
// public static final PacketType USE_ITEM_ON = new PacketType(PROTOCOL, SENDER, 0x38, "UseItemOn", "BlockPlace", "CPacketPlayerTryUseItemOnBlock");
|
||||
// public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x39, "UseItem", "CPacketPlayerTryUseItem");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17
|
||||
@@ -498,6 +504,12 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
@Deprecated
|
||||
public static final PacketType CHAT_PREVIEW = new PacketType(PROTOCOL, SENDER, 253, "ChatPreview");
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to USE_ITEM_ON
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType BLOCK_PLACE = USE_ITEM_ON.clone();
|
||||
|
||||
private static final Client INSTANCE = new Client();
|
||||
|
||||
// Prevent accidental construction
|
||||
@@ -678,6 +690,8 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType UPDATE_ENABLED_FEATURES = new PacketType(PROTOCOL, SENDER, 0x0C, "UpdateEnabledFeatures");
|
||||
public static final PacketType UPDATE_TAGS = new PacketType(PROTOCOL, SENDER, 0x0D, "UpdateTags");
|
||||
public static final PacketType SELECT_KNOWN_PACKS = new PacketType(PROTOCOL, SENDER, 0x0E, "ClientboundSelectKnownPacks");
|
||||
public static final PacketType REPORT_DETAILS = new PacketType(PROTOCOL, SENDER, 0x0F, "CustomReportDetails");
|
||||
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x10, "ServerLinks");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.20.4: replaced with new packets for removing and sending resource packs
|
||||
@@ -731,12 +745,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
STATUS("Status", "status"),
|
||||
LOGIN("Login", "login"),
|
||||
CONFIGURATION("Configuration", "configuration"),
|
||||
TRANSFER("Transfer", "transfer"), // TODO are these the right names?
|
||||
|
||||
/**
|
||||
* Only for packets removed in Minecraft 1.7.2
|
||||
*/
|
||||
LEGACY("", "");
|
||||
UNKNOWN("", "");
|
||||
|
||||
private final String packetName;
|
||||
private final String mojangName;
|
||||
@@ -752,14 +761,17 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
* @return The corresponding protocol.
|
||||
*/
|
||||
public static Protocol fromVanilla(Enum<?> vanilla) {
|
||||
if (vanilla == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
switch (vanilla.name()) {
|
||||
case "HANDSHAKING": return HANDSHAKING;
|
||||
case "PLAY": return PLAY;
|
||||
case "STATUS": return STATUS;
|
||||
case "LOGIN": return LOGIN;
|
||||
case "CONFIGURATION": return CONFIGURATION;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized vanilla enum " + vanilla);
|
||||
default: return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
@@ -58,10 +59,10 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedStreamCodec;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft packet indirectly.
|
||||
@@ -80,7 +81,7 @@ public class PacketContainer extends AbstractStructure implements Serializable {
|
||||
// Used to clone packets
|
||||
private static final AggregateCloner DEEP_CLONER = AggregateCloner
|
||||
.newBuilder()
|
||||
.instanceProvider(StructureCache::newPacket)
|
||||
.instanceProvider(StructureCache::newInstance)
|
||||
.andThen(BukkitCloner.class)
|
||||
.andThen(ImmutableDetector.class)
|
||||
.andThen(JavaOptionalCloner.class)
|
||||
@@ -91,7 +92,7 @@ public class PacketContainer extends AbstractStructure implements Serializable {
|
||||
|
||||
private static final AggregateCloner SHALLOW_CLONER = AggregateCloner
|
||||
.newBuilder()
|
||||
.instanceProvider(StructureCache::newPacket)
|
||||
.instanceProvider(StructureCache::newInstance)
|
||||
.andThen(param -> {
|
||||
if (param == null)
|
||||
throw new IllegalArgumentException("Cannot be NULL.");
|
||||
|
||||
@@ -152,7 +152,6 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
return lastSeen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getRespawnLocation() {
|
||||
return null;
|
||||
}
|
||||
@@ -241,11 +240,21 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public @NotNull PlayerProfile getPlayerProfile() {
|
||||
public PlayerProfile getPlayerProfile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
@@ -288,6 +297,11 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
return online;
|
||||
}
|
||||
|
||||
// @Override
|
||||
public boolean isConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWhitelisted() {
|
||||
return whitelisted;
|
||||
|
||||
@@ -17,22 +17,28 @@
|
||||
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.PublicKey;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.injector.packet.KnownPacketData;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.PacketCreator;
|
||||
import com.comphenix.protocol.reflect.instances.InstanceCreator;
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
@@ -41,9 +47,10 @@ import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.ZeroBuffer;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedStreamCodec;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy.Default;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
@@ -57,38 +64,96 @@ import net.bytebuddy.matcher.ElementMatchers;
|
||||
public class StructureCache {
|
||||
|
||||
// Structure modifiers
|
||||
private static final Map<Class<?>, Supplier<Object>> PACKET_INSTANCE_CREATORS = new ConcurrentHashMap<>();
|
||||
private static final Map<Class<?>, Optional<Supplier<Object>>> CACHED_INSTANCE_CREATORS = new ConcurrentHashMap<>();
|
||||
private static final Map<PacketType, StructureModifier<Object>> STRUCTURE_MODIFIER_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
// packet data serializer which always returns an empty nbt tag compound
|
||||
private static final Object TRICK_INIT_LOCK = new Object();
|
||||
private static boolean TRICK_TRIED = false;
|
||||
|
||||
private static Supplier<Object> TRICKED_DATA_SERIALIZER_BASE;
|
||||
private static Function<ByteBuf, Object> TRICKED_DATA_SERIALIZER_BASE;
|
||||
private static Supplier<Object> TRICKED_DATA_SERIALIZER_JSON;
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link #newInstance(Class)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Object newPacket(Class<?> packetClass) {
|
||||
Supplier<Object> packetConstructor = PACKET_INSTANCE_CREATORS.computeIfAbsent(packetClass, packetClassKey -> {
|
||||
try {
|
||||
PacketCreator creator = PacketCreator.forPacket(packetClassKey);
|
||||
if (creator.get() != null) {
|
||||
return creator;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return newInstance(packetClass);
|
||||
}
|
||||
|
||||
WrappedStreamCodec streamCodec = PacketRegistry.getStreamCodec(packetClassKey);
|
||||
public static boolean canCreateInstance(Class<?> clazz) {
|
||||
Optional<Supplier<Object>> creator = CACHED_INSTANCE_CREATORS.computeIfAbsent(clazz, x ->
|
||||
Optional.ofNullable(determineBestCreator(clazz)));
|
||||
return creator.isPresent();
|
||||
}
|
||||
|
||||
// use the new stream codec for versions above 1.20.5 if possible
|
||||
if (streamCodec != null && tryInitTrickDataSerializer()) {
|
||||
public static Object newInstance(Class<?> clazz) {
|
||||
Optional<Supplier<Object>> creator = CACHED_INSTANCE_CREATORS.computeIfAbsent(clazz, x ->
|
||||
Optional.ofNullable(determineBestCreator(clazz)));
|
||||
if (!creator.isPresent()) {
|
||||
throw new IllegalArgumentException("Cannot create instance of " + clazz);
|
||||
}
|
||||
return creator.get().get();
|
||||
}
|
||||
|
||||
static Supplier<Object> determineBestCreator(Class<?> clazz) {
|
||||
// certain packets are singletons which can't really be created
|
||||
if (MinecraftReflection.isPacketClass(clazz)) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
|
||||
List<Field> singletons = fuzzy.getFieldList(FuzzyFieldContract.newBuilder()
|
||||
.typeExact(clazz)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.build());
|
||||
if (singletons.size() == 1) {
|
||||
FieldAccessor accessor = Accessors.getFieldAccessor(singletons.get(0));
|
||||
try {
|
||||
// first try with the base accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_BASE.get();
|
||||
streamCodec.decode(serializer); // throwaway instance, for testing
|
||||
|
||||
// method is working
|
||||
return () -> streamCodec.decode(serializer);
|
||||
accessor.get(null);
|
||||
return () -> accessor.get(null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
InstanceCreator creator = InstanceCreator.forClass(clazz);
|
||||
if (creator.get() != null) {
|
||||
return creator;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
WrappedStreamCodec streamCodec = PacketRegistry.getStreamCodec(clazz);
|
||||
|
||||
// use the new stream codec for versions above 1.20.5 if possible
|
||||
if (streamCodec != null && tryInitTrickDataSerializer()) {
|
||||
try {
|
||||
// first try with the base accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_BASE.apply(new ZeroBuffer());
|
||||
streamCodec.decode(serializer); // throwaway instance, for testing
|
||||
|
||||
// method is working
|
||||
return () -> streamCodec.decode(serializer);
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
byte[] data;
|
||||
if (clazz.equals(PacketType.Play.Server.MAP_CHUNK.getPacketClass())) {
|
||||
data = KnownPacketData.MAP_CHUNK;
|
||||
} else if (clazz.equals(PacketType.Play.Server.SCOREBOARD_OBJECTIVE.getPacketClass())) {
|
||||
data = KnownPacketData.SCOREBOARD_OBJECTIVE;
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_BASE.apply(Unpooled.copiedBuffer(data));
|
||||
streamCodec.decode(serializer);
|
||||
|
||||
return () -> {
|
||||
((ByteBuf) serializer).readerIndex(0);
|
||||
return streamCodec.decode(serializer);
|
||||
};
|
||||
} catch (Exception ignored1) {
|
||||
try {
|
||||
// try with the json accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_JSON.get();
|
||||
@@ -96,51 +161,50 @@ public class StructureCache {
|
||||
|
||||
// method is working
|
||||
return () -> streamCodec.decode(serializer);
|
||||
} catch (Exception ignored1) {
|
||||
} catch (Exception ignored2) {
|
||||
// shrug, fall back to default behaviour
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prefer construction via PacketDataSerializer constructor on 1.17 and above
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
ConstructorAccessor serializerAccessor = Accessors.getConstructorAccessorOrNull(
|
||||
packetClassKey,
|
||||
MinecraftReflection.getPacketDataSerializerClass());
|
||||
if (serializerAccessor != null) {
|
||||
// check if the method is possible
|
||||
if (tryInitTrickDataSerializer()) {
|
||||
// prefer construction via PacketDataSerializer constructor on 1.17 and above
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
ConstructorAccessor serializerAccessor = Accessors.getConstructorAccessorOrNull(
|
||||
clazz,
|
||||
MinecraftReflection.getPacketDataSerializerClass());
|
||||
if (serializerAccessor != null) {
|
||||
// check if the method is possible
|
||||
if (tryInitTrickDataSerializer()) {
|
||||
try {
|
||||
// first try with the base accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_BASE.apply(new ZeroBuffer());
|
||||
serializerAccessor.invoke(serializer); // throwaway instance, for testing
|
||||
|
||||
// method is working
|
||||
return () -> serializerAccessor.invoke(serializer);
|
||||
} catch (Exception ignored) {
|
||||
try {
|
||||
// first try with the base accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_BASE.get();
|
||||
// try with the json accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_JSON.get();
|
||||
serializerAccessor.invoke(serializer); // throwaway instance, for testing
|
||||
|
||||
// method is working
|
||||
return () -> serializerAccessor.invoke(serializer);
|
||||
} catch (Exception ignored) {
|
||||
try {
|
||||
// try with the json accessor
|
||||
Object serializer = TRICKED_DATA_SERIALIZER_JSON.get();
|
||||
serializerAccessor.invoke(serializer); // throwaway instance, for testing
|
||||
|
||||
// method is working
|
||||
return () -> serializerAccessor.invoke(serializer);
|
||||
} catch (Exception ignored1) {
|
||||
// shrug, fall back to default behaviour
|
||||
}
|
||||
} catch (Exception ignored1) {
|
||||
// shrug, fall back to default behaviour
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try via DefaultInstances as fallback
|
||||
return () -> {
|
||||
Object packetInstance = DefaultInstances.DEFAULT.create(packetClassKey);
|
||||
Objects.requireNonNull(packetInstance, "Unable to create packet instance for class " + packetClassKey + " - " + tryInitTrickDataSerializer() + " - " + streamCodec);
|
||||
return packetInstance;
|
||||
};
|
||||
});
|
||||
return packetConstructor.get();
|
||||
Object instance = DefaultInstances.DEFAULT.create(clazz);
|
||||
if (instance == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return () -> DefaultInstances.DEFAULT.create(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +260,7 @@ public class StructureCache {
|
||||
*/
|
||||
public static Object newNullDataSerializer() {
|
||||
tryInitTrickDataSerializer();
|
||||
return TRICKED_DATA_SERIALIZER_BASE.get();
|
||||
return TRICKED_DATA_SERIALIZER_BASE.apply(new ZeroBuffer());
|
||||
}
|
||||
|
||||
static void initTrickDataSerializer() {
|
||||
@@ -226,10 +290,10 @@ public class StructureCache {
|
||||
.parameterDerivedOf(ByteBuf.class)
|
||||
.parameterDerivedOf(MinecraftReflection.getRegistryAccessClass())
|
||||
.build()));
|
||||
TRICKED_DATA_SERIALIZER_BASE = () -> accessor.invoke(new ZeroBuffer(), MinecraftRegistryAccess.get());
|
||||
TRICKED_DATA_SERIALIZER_BASE = (buf) -> accessor.invoke(buf, MinecraftRegistryAccess.get());
|
||||
} else {
|
||||
ConstructorAccessor accessor = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
|
||||
TRICKED_DATA_SERIALIZER_BASE = () -> accessor.invoke(new ZeroBuffer());
|
||||
TRICKED_DATA_SERIALIZER_BASE = accessor::invoke;
|
||||
}
|
||||
|
||||
//xtended builder which intercepts the read string method as well
|
||||
|
||||
+7
-4
@@ -11,9 +11,6 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
@@ -46,6 +43,8 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.util.AttributeKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class NettyChannelInjector implements Injector {
|
||||
|
||||
@@ -583,8 +582,12 @@ public class NettyChannelInjector implements Injector {
|
||||
}
|
||||
|
||||
PacketType.Protocol protocol = this.getCurrentProtocol(PacketType.Sender.SERVER);
|
||||
if (protocol == Protocol.UNKNOWN) {
|
||||
ProtocolLogger.debug("skipping unknown protocol for {0}", packet.getClass());
|
||||
return action;
|
||||
}
|
||||
|
||||
PacketType packetType = PacketRegistry.getPacketType(protocol, packet.getClass());
|
||||
|
||||
if (packetType == null) {
|
||||
ProtocolLogger.debug("skipping unknown outbound packet type for {0}", packet.getClass());
|
||||
return action;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.comphenix.protocol.injector.packet;
|
||||
|
||||
public final class KnownPacketData {
|
||||
public static final byte[] SCOREBOARD_OBJECTIVE = {
|
||||
4, 84, 101, 115, 116, 1
|
||||
};
|
||||
|
||||
public static final byte[] MAP_CHUNK = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
}
|
||||
@@ -370,7 +370,7 @@ public class PacketRegistry {
|
||||
Class<?> idCodecEntryClass = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec$Entry", "network.codec.IdDispatchCodec$b");
|
||||
Class<?> protocolDirectionClass = MinecraftReflection.getPacketFlowClass();
|
||||
|
||||
Function<?, ?> emptyFunction = input -> null;
|
||||
Function<?, ?> emptyFunction = input -> input;
|
||||
|
||||
FuzzyReflection protocolInfoReflection = FuzzyReflection.fromClass(protocolInfoClass);
|
||||
|
||||
|
||||
@@ -17,15 +17,6 @@
|
||||
|
||||
package com.comphenix.protocol.reflect;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.instances.BannedGenerator;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.InstanceProvider;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -43,6 +34,17 @@ import java.util.Optional;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.instances.BannedGenerator;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.InstanceProvider;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
/**
|
||||
* Provides list-oriented access to the fields of a Minecraft packet.
|
||||
* <p>
|
||||
@@ -142,8 +144,9 @@ public class StructureModifier<T> {
|
||||
|
||||
for (FieldAccessor accessor : fields) {
|
||||
Field field = accessor.getField();
|
||||
if (!field.getType().isPrimitive() && !Modifier.isFinal(field.getModifiers())) {
|
||||
if (DEFAULT_GENERATOR.hasDefault(field.getType())) {
|
||||
if (!field.getType().isPrimitive()) {// && !Modifier.isFinal(field.getModifiers())) {
|
||||
// if (DEFAULT_GENERATOR.hasDefault(field.getType())) {
|
||||
if (StructureCache.canCreateInstance(field.getType())) {
|
||||
requireDefaults.put(accessor, currentFieldIndex);
|
||||
}
|
||||
}
|
||||
@@ -395,13 +398,12 @@ public class StructureModifier<T> {
|
||||
// They must be null or messages will be blank
|
||||
Field field = accessor.getField();
|
||||
if (field.getType().getCanonicalName().equals("net.md_5.bungee.api.chat.BaseComponent[]")) {
|
||||
accessor.set(this.target, null);
|
||||
accessor.set(target, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the default value and write the field
|
||||
Object defaultValue = DEFAULT_GENERATOR.getDefault(field.getType());
|
||||
accessor.set(this.target, defaultValue);
|
||||
Object value = StructureCache.newInstance(field.getType());
|
||||
accessor.set(target, value);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
@@ -82,6 +82,8 @@ public class BukkitCloner implements Cloner {
|
||||
fromWrapper(MinecraftReflection::getIChatBaseComponentClass, WrappedChatComponent::fromHandle);
|
||||
fromWrapper(WrappedVillagerData::getNmsClass, WrappedVillagerData::fromHandle);
|
||||
fromConverter(MinecraftReflection::getSectionPositionClass, BukkitConverters.getSectionPositionConverter());
|
||||
fromManual(MinecraftReflection::getAttributeSnapshotClass, source ->
|
||||
WrappedAttribute.fromHandle(source).shallowClone().getHandle());
|
||||
|
||||
try {
|
||||
fromManual(ComponentConverter::getBaseComponentArrayClass, source ->
|
||||
|
||||
@@ -62,12 +62,12 @@ public class ImmutableDetector implements Cloner {
|
||||
add(MinecraftReflection::getDataWatcherSerializerClass);
|
||||
add(MinecraftReflection::getBlockClass);
|
||||
add(MinecraftReflection::getItemClass);
|
||||
add("sounds.SoundEffect", "sounds.SoundEvents", "SoundEffect");
|
||||
add(MinecraftReflection::getSoundEffectClass);
|
||||
|
||||
if (MinecraftVersion.AQUATIC_UPDATE.atOrAbove()) {
|
||||
add(MinecraftReflection::getFluidTypeClass);
|
||||
add(MinecraftReflection::getParticleTypeClass);
|
||||
add("core.particles.Particle","core.particles.ParticleType", "Particle");
|
||||
add(MinecraftReflection::getParticleClass);
|
||||
}
|
||||
|
||||
if (MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) {
|
||||
|
||||
+55
-23
@@ -3,35 +3,44 @@ package com.comphenix.protocol.reflect.instances;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
public final class PacketCreator implements Supplier<Object> {
|
||||
public final class InstanceCreator implements Supplier<Object> {
|
||||
private static Map<Class<?>, Object> BANNED_PARAMETERS = new WeakHashMap<>();
|
||||
|
||||
static {
|
||||
try {
|
||||
BANNED_PARAMETERS.put(ByteBuffer.class, true);
|
||||
BANNED_PARAMETERS.put(FloatBuffer.class, true);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private ConstructorAccessor constructor = null;
|
||||
private MethodAccessor factoryMethod = null;
|
||||
private Object[] params = null;
|
||||
private Class<?>[] paramTypes = null;
|
||||
private boolean failed = false;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private PacketCreator(Class<?> type) {
|
||||
private InstanceCreator(Class<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static PacketCreator forPacket(Class<?> type) {
|
||||
public static InstanceCreator forClass(Class<?> type) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Type cannot be null.");
|
||||
}
|
||||
|
||||
if (!MinecraftReflection.getPacketClass().isAssignableFrom(type)) {
|
||||
throw new IllegalArgumentException("Type must be a subclass of Packet.");
|
||||
}
|
||||
|
||||
return new PacketCreator(type);
|
||||
return new InstanceCreator(type);
|
||||
}
|
||||
|
||||
private Object createInstance(Class<?> clazz) {
|
||||
@@ -42,8 +51,27 @@ public final class PacketCreator implements Supplier<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] createParams(Class<?>[] paramTypes) {
|
||||
Object[] params = new Object[paramTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
params[i] = createInstance(paramTypes[i]);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private boolean containsBannedParameter(Class<?>[] paramTypes) {
|
||||
for (Class<?> paramType : paramTypes) {
|
||||
if (BANNED_PARAMETERS.containsKey(paramType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get() {
|
||||
Object[] params = paramTypes != null ? createParams(paramTypes) : null;
|
||||
|
||||
if (constructor != null) {
|
||||
return constructor.invoke(params);
|
||||
}
|
||||
@@ -59,22 +87,24 @@ public final class PacketCreator implements Supplier<Object> {
|
||||
Object result = null;
|
||||
int minCount = Integer.MAX_VALUE;
|
||||
|
||||
for (Constructor<?> testCtor : type.getConstructors()) {
|
||||
for (Constructor<?> testCtor : type.getDeclaredConstructors()) {
|
||||
Class<?>[] paramTypes = testCtor.getParameterTypes();
|
||||
if (paramTypes.length > minCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object[] testParams = new Object[paramTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
testParams[i] = createInstance(paramTypes[i]);
|
||||
if (containsBannedParameter(paramTypes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object[] testParams = createParams(paramTypes);
|
||||
|
||||
try {
|
||||
result = testCtor.newInstance(testParams);
|
||||
ConstructorAccessor testAccessor = Accessors.getConstructorAccessor(testCtor);
|
||||
result = testAccessor.invoke(testParams);
|
||||
minCount = paramTypes.length;
|
||||
this.constructor = Accessors.getConstructorAccessor(testCtor);
|
||||
this.params = testParams;
|
||||
this.constructor = testAccessor;
|
||||
this.paramTypes = paramTypes;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
@@ -100,16 +130,18 @@ public final class PacketCreator implements Supplier<Object> {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object[] testParams = new Object[paramTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
testParams[i] = createInstance(paramTypes[i]);
|
||||
if (containsBannedParameter(paramTypes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object[] testParams = createParams(paramTypes);
|
||||
|
||||
try {
|
||||
result = testMethod.invoke(null, testParams);
|
||||
MethodAccessor testAccessor = Accessors.getMethodAccessor(testMethod);
|
||||
result = testAccessor.invoke(null, testParams);
|
||||
minCount = paramTypes.length;
|
||||
this.factoryMethod = Accessors.getMethodAccessor(testMethod);
|
||||
this.params = testParams;
|
||||
this.factoryMethod = testAccessor;
|
||||
this.paramTypes = paramTypes;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
@@ -64,11 +64,16 @@ final class CachedPackage {
|
||||
* @param clazz - type of class.
|
||||
*/
|
||||
public void setPackageClass(String className, Class<?> clazz) {
|
||||
if (clazz != null) {
|
||||
this.cache.put(className, Optional.of(clazz));
|
||||
} else {
|
||||
this.cache.remove(className);
|
||||
Optional<Class<?>> previous = cache.get(className);
|
||||
if (previous != null && previous.isPresent()) {
|
||||
throw new IllegalStateException("Tried to redefine class " + className);
|
||||
}
|
||||
|
||||
cache.put(className, Optional.ofNullable(clazz));
|
||||
}
|
||||
|
||||
public void removePackageClass(String className) {
|
||||
cache.remove(className);
|
||||
}
|
||||
|
||||
private Optional<Class<?>> resolveClass(String className) {
|
||||
|
||||
@@ -88,8 +88,11 @@ public final class MinecraftProtocolVersion {
|
||||
map.put(new MinecraftVersion(1, 19, 4), 762);
|
||||
|
||||
map.put(new MinecraftVersion(1, 20, 0), 763);
|
||||
map.put(new MinecraftVersion(1, 20, 1), 763);
|
||||
map.put(new MinecraftVersion(1, 20, 2), 764);
|
||||
map.put(new MinecraftVersion(1, 20, 3), 765);
|
||||
map.put(new MinecraftVersion(1, 20, 5), 766);
|
||||
|
||||
map.put(new MinecraftVersion(1, 21, 0), 767);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,6 @@ import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
@@ -54,6 +48,11 @@ import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Methods and constants specifically used in conjuction with reflecting Minecraft object.
|
||||
@@ -117,7 +116,7 @@ public final class MinecraftReflection {
|
||||
private static MethodAccessor asCraftMirror = null;
|
||||
private static MethodAccessor isEmpty = null;
|
||||
|
||||
private static boolean isMojangMapped = false;
|
||||
private static Boolean isMojangMapped = null;
|
||||
|
||||
private MinecraftReflection() {
|
||||
// No need to make this constructable.
|
||||
@@ -208,9 +207,6 @@ public final class MinecraftReflection {
|
||||
}
|
||||
}
|
||||
|
||||
// for now, we're going to say that it's Mojang mapped if the nms world was renamed to ServerLevel
|
||||
isMojangMapped = getNmsWorldClass().getName().contains("ServerLevel");
|
||||
|
||||
return MINECRAFT_FULL_PACKAGE;
|
||||
} catch (NoSuchMethodException exception) {
|
||||
throw new IllegalStateException("Cannot find getHandle() in CraftEntity", exception);
|
||||
@@ -422,6 +418,10 @@ public final class MinecraftReflection {
|
||||
return is(getPacketClass(), obj);
|
||||
}
|
||||
|
||||
public static boolean isPacketClass(Class<?> clazz) {
|
||||
return is(getPacketClass(), clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given object is assignable to a NetServerHandler (PlayerConnection)
|
||||
*
|
||||
@@ -518,7 +518,7 @@ public final class MinecraftReflection {
|
||||
.getMethodByName("getHandle");
|
||||
|
||||
// EntityPlayer is the return type
|
||||
return setMinecraftClass("EntityPlayer", getHandle.getReturnType());
|
||||
return setMinecraftClass("server.level.EntityPlayer", getHandle.getReturnType());
|
||||
} catch (IllegalArgumentException e1) {
|
||||
throw new RuntimeException("Could not find EntityPlayer class.", e1);
|
||||
}
|
||||
@@ -588,7 +588,7 @@ public final class MinecraftReflection {
|
||||
try {
|
||||
return getMinecraftClass("world.level.World", "world.level.Level", "World");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass("World", getWorldServerClass().getSuperclass());
|
||||
return setMinecraftClass("world.level.World", getWorldServerClass().getSuperclass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,7 +648,7 @@ public final class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static boolean isBundleDelimiter(Class<?> packetClass) {
|
||||
Class<?> bundleDelimiterClass = getBundleDelimiterClass().orElse(null);
|
||||
Class<?> bundleDelimiterClass = getBundleDelimiterClass().orElse(null);
|
||||
return bundleDelimiterClass != null && (packetClass.equals(bundleDelimiterClass) || bundleDelimiterClass.isAssignableFrom(packetClass));
|
||||
}
|
||||
|
||||
@@ -685,10 +685,12 @@ public final class MinecraftReflection {
|
||||
* @return The serializer class.
|
||||
*/
|
||||
public static Class<?> getStyleSerializerClass() {
|
||||
return getMinecraftClass("network.chat.ChatModifier$ChatModifierSerializer", "ChatModifier$ChatModifierSerializer");
|
||||
return getMinecraftClass(
|
||||
"network.chat.Style$Serializer",
|
||||
"network.chat.ChatModifier$ChatModifierSerializer",
|
||||
"ChatModifier$ChatModifierSerializer");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the ServerPing class.
|
||||
*
|
||||
@@ -729,10 +731,10 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("server.MinecraftServer", "MinecraftServer");
|
||||
} catch (RuntimeException e) {
|
||||
// Reset cache and try again
|
||||
setMinecraftClass("MinecraftServer", null);
|
||||
resetCacheForNMSClass("server.MinecraftServer");
|
||||
|
||||
useFallbackServer();
|
||||
return getMinecraftClass("MinecraftServer");
|
||||
return getMinecraftClass("server.MinecraftServer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,10 +766,10 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("server.players.PlayerList", "PlayerList");
|
||||
} catch (RuntimeException e) {
|
||||
// Reset cache and try again
|
||||
setMinecraftClass("PlayerList", null);
|
||||
resetCacheForNMSClass("server.players.PlayerList");
|
||||
|
||||
useFallbackServer();
|
||||
return getMinecraftClass("PlayerList");
|
||||
return getMinecraftClass("server.players.PlayerList");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,7 +801,7 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("world.item.ItemStack", "ItemStack");
|
||||
} catch (RuntimeException e) {
|
||||
// Use the handle reference
|
||||
return setMinecraftClass("ItemStack", FuzzyReflection.fromClass(getCraftItemStackClass(), true)
|
||||
return setMinecraftClass("world.item.ItemStack", FuzzyReflection.fromClass(getCraftItemStackClass(), true)
|
||||
.getFieldByName("handle")
|
||||
.getType());
|
||||
}
|
||||
@@ -1036,7 +1038,21 @@ public final class MinecraftReflection {
|
||||
* @return The team parameters class.
|
||||
*/
|
||||
public static Optional<Class<?>> getTeamParametersClass() {
|
||||
return getOptionalNMS("network.protocol.game.PacketPlayOutScoreboardTeam$b");
|
||||
Optional<Class<?>> clazz = getOptionalNMS(
|
||||
"network.protocol.game.ClientboundSetPlayerTeamPacket$Parameters",
|
||||
"network.protocol.game.PacketPlayOutScoreboardTeam$b"
|
||||
);
|
||||
|
||||
if (!clazz.isPresent()) {
|
||||
try {
|
||||
Class<?> clazz1 = PacketType.Play.Server.SCOREBOARD_TEAM.getPacketClass().getClasses()[0];
|
||||
setMinecraftClass("network.protocol.game.ClientboundSetPlayerTeamPacket$Parameters", clazz1);
|
||||
return Optional.of(clazz1);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1045,7 +1061,11 @@ public final class MinecraftReflection {
|
||||
* @return The component style class.
|
||||
*/
|
||||
public static Class<?> getComponentStyleClass() {
|
||||
return getMinecraftClass("network.chat.ChatModifier", "ChatModifier");
|
||||
return getMinecraftClass(
|
||||
"network.chat.Style",
|
||||
"network.chat.ChatModifier",
|
||||
"ChatModifier"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1169,19 +1189,21 @@ public final class MinecraftReflection {
|
||||
public static Class<?> getPlayerInfoDataClass() {
|
||||
try {
|
||||
return getMinecraftClass(
|
||||
"network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData",
|
||||
"network.protocol.game.ClientboundPlayerInfoPacket$PlayerUpdate",
|
||||
"PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
} catch (Exception ex) {
|
||||
// todo: ClientboundPlayerInfoUpdatePacket$b, maybe get this via field type
|
||||
"network.protocol.game.ClientboundPlayerInfoUpdatePacket$Entry",
|
||||
"network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData",
|
||||
"network.protocol.game.ClientboundPlayerInfoPacket$PlayerUpdate",
|
||||
"PacketPlayOutPlayerInfo$PlayerInfoData",
|
||||
"PlayerInfoData"
|
||||
);
|
||||
} catch (Exception ignored) {
|
||||
return setMinecraftClass(
|
||||
"network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData",
|
||||
"network.protocol.game.ClientboundPlayerInfoUpdatePacket$Entry",
|
||||
PacketType.Play.Server.PLAYER_INFO.getPacketClass().getClasses()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static Class<?> getOrInferMinecraftClass(String className, Supplier<Class<?>> supplier) {
|
||||
return getOptionalNMS(className).orElseGet(() -> {
|
||||
static Class<?> getOrInferMinecraftClass(String className, Supplier<Class<?>> supplier, String... aliases) {
|
||||
return getOptionalNMS(className, aliases).orElseGet(() -> {
|
||||
Class<?> clazz = supplier.get();
|
||||
return setMinecraftClass(className, clazz);
|
||||
});
|
||||
@@ -1496,16 +1518,22 @@ public final class MinecraftReflection {
|
||||
* Retrieves a nullable NMS (net.minecraft.server) class. We will attempt to
|
||||
* look up the class and its aliases, but will return null if none is found.
|
||||
*
|
||||
* @deprecated - Use getOptionalNMS where possible
|
||||
* @param className NMS class name
|
||||
* @param aliases Potential aliases
|
||||
* @return The class, or null if not found
|
||||
*/
|
||||
@Deprecated
|
||||
public static Class<?> getNullableNMS(String className, String... aliases) {
|
||||
return getOptionalNMS(className, aliases).orElse(null);
|
||||
}
|
||||
|
||||
private static void resetCacheForNMSClass(String className) {
|
||||
if (minecraftPackage == null) {
|
||||
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
|
||||
}
|
||||
|
||||
minecraftPackage.removePackageClass(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class object for the specific Minecraft class.
|
||||
*
|
||||
@@ -1822,7 +1850,7 @@ public final class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getCraftServer() {
|
||||
return getCraftBukkitClass("CraftServer");
|
||||
return getCraftBukkitClass("CraftServer");
|
||||
}
|
||||
|
||||
public static Class<?> getHolderLookupProviderClass() {
|
||||
@@ -1834,26 +1862,31 @@ public final class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getProtocolInfoClass() {
|
||||
return getMinecraftClass("network.ProtocolInfo");
|
||||
return getMinecraftClass("network.ProtocolInfo");
|
||||
}
|
||||
|
||||
public static Class<?> getProtocolInfoUnboundClass() {
|
||||
return getMinecraftClass("network.ProtocolInfo$a" /* Spigot Mappings */, "network.ProtocolInfo$Unbound" /* Mojang Mappings */);
|
||||
return getMinecraftClass("network.ProtocolInfo$a" /* Spigot Mappings */, "network.ProtocolInfo$Unbound" /* Mojang Mappings */);
|
||||
}
|
||||
|
||||
public static Class<?> getPacketFlowClass() {
|
||||
return getMinecraftClass("network.protocol.EnumProtocolDirection" /* Spigot Mappings */, "network.protocol.PacketFlow" /* Mojang Mappings */);
|
||||
return getMinecraftClass("network.protocol.EnumProtocolDirection" /* Spigot Mappings */, "network.protocol.PacketFlow" /* Mojang Mappings */);
|
||||
}
|
||||
|
||||
public static Class<?> getStreamCodecClass() {
|
||||
return getMinecraftClass("network.codec.StreamCodec");
|
||||
return getMinecraftClass("network.codec.StreamCodec");
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> getRegistryFriendlyByteBufClass() {
|
||||
return getOptionalNMS("network.RegistryFriendlyByteBuf");
|
||||
return getOptionalNMS("network.RegistryFriendlyByteBuf");
|
||||
}
|
||||
|
||||
public static boolean isMojangMapped() {
|
||||
if (isMojangMapped == null) {
|
||||
String nmsWorldName = getWorldServerClass().getName();
|
||||
isMojangMapped = nmsWorldName.contains("ServerLevel");
|
||||
}
|
||||
|
||||
return isMojangMapped;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,11 @@ import org.bukkit.Server;
|
||||
* @author Kristian
|
||||
*/
|
||||
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
||||
/**
|
||||
* Version 1.21.0 - the tricky trials update
|
||||
*/
|
||||
public static final MinecraftVersion v1_21_0 = new MinecraftVersion("1.21.0");
|
||||
|
||||
/**
|
||||
* Version 1.20.5 - the cookie and transfer packet update
|
||||
*/
|
||||
@@ -144,7 +149,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion>, Ser
|
||||
/**
|
||||
* The latest release version of minecraft.
|
||||
*/
|
||||
public static final MinecraftVersion LATEST = v1_20_5;
|
||||
public static final MinecraftVersion LATEST = v1_21_0;
|
||||
|
||||
// used when serializing
|
||||
private static final long serialVersionUID = -8695133558996459770L;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Base64;
|
||||
|
||||
import com.comphenix.protocol.injector.netty.NettyByteBufAdapter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
@@ -8,14 +15,10 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtType;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
@@ -148,9 +151,14 @@ public class StreamSerializer {
|
||||
*/
|
||||
public void serializeString(DataOutputStream output, String text) {
|
||||
if (WRITE_STRING_METHOD == null) {
|
||||
WRITE_STRING_METHOD = Accessors.getMethodAccessor(FuzzyReflection
|
||||
.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true)
|
||||
.getMethodByParameters("writeString", String.class));
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), false);
|
||||
WRITE_STRING_METHOD = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactType(String.class)
|
||||
.parameterCount(1)
|
||||
.returnDerivedOf(ByteBuf.class)
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.banModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
}
|
||||
|
||||
ByteBuf buf = NettyByteBufAdapter.packetWriter(output);
|
||||
@@ -223,15 +231,15 @@ public class StreamSerializer {
|
||||
* @return A deserialized item stack, or NULL if the serialized ItemStack was also NULL.
|
||||
*/
|
||||
public ItemStack deserializeItemStackFromByteArray(byte[] input) {
|
||||
if (READ_ITEM_METHOD == null) {
|
||||
READ_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
|
||||
.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true)
|
||||
.getMethodByReturnTypeAndParameters("readItemStack", MinecraftReflection.getItemStackClass()));
|
||||
}
|
||||
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(input);
|
||||
Object serializer = MinecraftReflection.getPacketDataSerializer(buf);
|
||||
|
||||
if (READ_ITEM_METHOD == null) {
|
||||
READ_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
|
||||
.fromClass(serializer.getClass(), false)
|
||||
.getMethodByReturnTypeAndParameters("readItemStack", MinecraftReflection.getItemStackClass()));
|
||||
}
|
||||
|
||||
try {
|
||||
// unwrap the item
|
||||
Object nmsItem = READ_ITEM_METHOD.invoke(serializer);
|
||||
@@ -254,6 +262,7 @@ public class StreamSerializer {
|
||||
* @throws IOException If the operation fails due to reflection problems.
|
||||
*/
|
||||
public void serializeItemStack(DataOutputStream output, ItemStack stack) throws IOException {
|
||||
// TODO this functionality was replaced by the CODEC field in the nms ItemStack
|
||||
if (WRITE_ITEM_METHOD == null) {
|
||||
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
|
||||
.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true)
|
||||
|
||||
@@ -16,14 +16,22 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
import com.comphenix.protocol.wrappers.Either.Right;
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -32,6 +40,7 @@ import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.injector.PacketConstructor;
|
||||
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
||||
@@ -47,8 +56,11 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
import com.comphenix.protocol.wrappers.Either.Right;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Dimension;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.FauxEnumConverter;
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
@@ -56,7 +68,6 @@ import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
@@ -1116,29 +1127,30 @@ public class BukkitConverters {
|
||||
static MethodAccessor getSoundEffect = null;
|
||||
static FieldAccessor soundKey = null;
|
||||
|
||||
static MethodAccessor getSoundEffectBySound = null;
|
||||
static MethodAccessor getSoundByEffect = null;
|
||||
static MethodAccessor bukkitToMinecraft = null;
|
||||
static MethodAccessor minecraftToBukkit = null;
|
||||
|
||||
static Map<String, Sound> soundIndex = null;
|
||||
|
||||
public static EquivalentConverter<Sound> getSoundConverter() {
|
||||
// Try to create sound converter for new versions greater 1.16.4
|
||||
if (MinecraftVersion.NETHER_UPDATE_4.atOrAbove()) {
|
||||
if (getSoundEffectBySound == null || getSoundByEffect == null) {
|
||||
if (bukkitToMinecraft == null && minecraftToBukkit == null) {
|
||||
Class<?> craftSound = MinecraftReflection.getCraftSoundClass();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(craftSound, true);
|
||||
Class<?> soundEvent = MinecraftReflection.getSoundEffectClass();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(craftSound, false);
|
||||
|
||||
getSoundEffectBySound = Accessors.getMethodAccessor(fuzzy.getMethodByReturnTypeAndParameters(
|
||||
"getSoundEffect",
|
||||
MinecraftReflection.getSoundEffectClass(),
|
||||
Sound.class
|
||||
));
|
||||
bukkitToMinecraft = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(soundEvent)
|
||||
.parameterExactArray(Sound.class)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
|
||||
getSoundByEffect = Accessors.getMethodAccessor(fuzzy.getMethodByReturnTypeAndParameters(
|
||||
"getBukkit",
|
||||
Sound.class,
|
||||
MinecraftReflection.getSoundEffectClass()
|
||||
));
|
||||
minecraftToBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(Sound.class)
|
||||
.parameterExactArray(soundEvent)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
}
|
||||
|
||||
return ignoreNull(new EquivalentConverter<Sound>() {
|
||||
@@ -1150,13 +1162,13 @@ public class BukkitConverters {
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Sound specific) {
|
||||
return getSoundEffectBySound.invoke(null, specific);
|
||||
return bukkitToMinecraft.invoke(null, specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sound getSpecific(Object generic) {
|
||||
try {
|
||||
return (Sound) getSoundByEffect.invoke(null, generic);
|
||||
return (Sound) minecraftToBukkit.invoke(null, generic);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (ex.getCause() instanceof NullPointerException || ex.getCause() instanceof NoSuchElementException) {
|
||||
// "null" sounds cause NPEs inside getSoundByEffect
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
@@ -11,21 +22,11 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Represents a generic enum converter.
|
||||
* @author Kristian
|
||||
@@ -661,7 +662,7 @@ public abstract class EnumWrappers {
|
||||
|
||||
INITIALIZED = true;
|
||||
|
||||
PROTOCOL_CLASS = getEnum(PacketType.Handshake.Client.SET_PROTOCOL.getPacketClass(), 0);
|
||||
PROTOCOL_CLASS = MinecraftReflection.getEnumProtocolClass();
|
||||
CLIENT_COMMAND_CLASS = getEnum(PacketType.Play.Client.CLIENT_COMMAND.getPacketClass(), 0);
|
||||
|
||||
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
|
||||
@@ -736,8 +737,12 @@ public abstract class EnumWrappers {
|
||||
CHAT_TYPE_CLASS = getEnum(PacketType.Play.Server.CHAT.getPacketClass(), 0);
|
||||
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("world.entity.EntityPose", "world.entity.Pose", "EntityPose");
|
||||
DISPLAY_SLOT_CLASS = MinecraftReflection.getNullableNMS("world.scores.DisplaySlot");
|
||||
RENDER_TYPE_CLASS = MinecraftReflection.getNullableNMS("world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay", "IScoreboardCriteria$EnumScoreboardHealthDisplay");
|
||||
CHAT_FORMATTING_CLASS = MinecraftReflection.getNullableNMS("EnumChatFormat");
|
||||
|
||||
RENDER_TYPE_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.scores.criteria.ObjectiveCriteria$RenderType",
|
||||
"world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay",
|
||||
"IScoreboardCriteria$EnumScoreboardHealthDisplay");
|
||||
CHAT_FORMATTING_CLASS = MinecraftReflection.getNullableNMS("ChatFormatting", "EnumChatFormat");
|
||||
|
||||
associate(PROTOCOL_CLASS, Protocol.class, getProtocolConverter());
|
||||
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class InMemoryDataWatcher implements IDataWatcher {
|
||||
private static FieldAccessor ARRAY_FIELD;
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
|
||||
private static boolean ARRAY_BACKED = MinecraftVersion.v1_20_4.atOrAbove();
|
||||
private static boolean ARRAY_BACKED = MinecraftVersion.v1_20_5.atOrAbove();
|
||||
|
||||
private static Class<?> SYNCED_DATA_HOLDER_CLASS = ARRAY_BACKED
|
||||
? MinecraftReflection.getMinecraftClass("network.syncher.SyncedDataHolder")
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
@@ -130,7 +131,7 @@ public class MinecraftKey {
|
||||
return Objects.hash(prefix, key);
|
||||
}
|
||||
|
||||
private static Constructor<?> constructor = null;
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
|
||||
public static EquivalentConverter<MinecraftKey> getConverter() {
|
||||
return new EquivalentConverter<MinecraftKey>() {
|
||||
@@ -141,19 +142,12 @@ public class MinecraftKey {
|
||||
|
||||
@Override
|
||||
public Object getGeneric(MinecraftKey specific) {
|
||||
if (constructor == null) {
|
||||
try {
|
||||
constructor = MinecraftReflection.getMinecraftKeyClass().getConstructor(String.class, String.class);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to obtain MinecraftKey constructor", e);
|
||||
}
|
||||
if (CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(MinecraftReflection.getMinecraftKeyClass(),
|
||||
String.class, String.class);
|
||||
}
|
||||
|
||||
try {
|
||||
return constructor.newInstance(specific.getPrefix(), specific.getKey());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to create new MinecraftKey", e);
|
||||
}
|
||||
return CONSTRUCTOR.invoke(specific.getPrefix(), specific.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
@@ -9,37 +18,33 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.collection.CachedSet;
|
||||
import com.comphenix.protocol.wrappers.collection.ConvertedSet;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a single attribute sent in packet 44.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class WrappedAttribute extends AbstractWrapper {
|
||||
public static boolean KEY_WRAPPED = MinecraftVersion.NETHER_UPDATE.atOrAbove();
|
||||
public static boolean IS_STATIC = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
|
||||
public static boolean IS_IN_HOLDER = MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove();
|
||||
public final class WrappedAttribute extends AbstractWrapper {
|
||||
static final boolean KEY_WRAPPED = MinecraftVersion.NETHER_UPDATE.atOrAbove();
|
||||
static final boolean IS_STATIC = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
|
||||
static final boolean IS_IN_HOLDER = MinecraftVersion.v1_20_5.atOrAbove();
|
||||
|
||||
// Shared structure modifier
|
||||
private static StructureModifier<Object> ATTRIBUTE_MODIFIER;
|
||||
static StructureModifier<Object> ATTRIBUTE_MODIFIER;
|
||||
|
||||
// The one constructor
|
||||
private static Constructor<?> ATTRIBUTE_CONSTRUCTOR;
|
||||
static Constructor<?> ATTRIBUTE_CONSTRUCTOR;
|
||||
|
||||
/**
|
||||
* Remaps attributes if needed.
|
||||
*
|
||||
* @return the remapped attribute or the attribute itself if no remapping was necessary.
|
||||
*/
|
||||
private static String remap(String string) {
|
||||
static String remap(String string) {
|
||||
switch (string) {
|
||||
case "generic.maxHealth": return "generic.max_health";
|
||||
case "generic.followRange": return "generic.follow_range";
|
||||
@@ -55,11 +60,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to the underlying attribute snapshot.
|
||||
*/
|
||||
protected Object handle;
|
||||
protected StructureModifier<Object> modifier;
|
||||
StructureModifier<Object> modifier;
|
||||
|
||||
// Cached computed value
|
||||
private double computedValue = Double.NaN;
|
||||
@@ -72,7 +73,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
*
|
||||
* @param handle - the NMS instance.
|
||||
*/
|
||||
private WrappedAttribute(@Nonnull Object handle) {
|
||||
WrappedAttribute(@Nonnull Object handle) {
|
||||
super(MinecraftReflection.getAttributeSnapshotClass());
|
||||
setHandle(handle);
|
||||
|
||||
@@ -83,7 +84,6 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new wrapped attribute around a specific NMS instance.
|
||||
*
|
||||
@@ -205,7 +205,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
* @return TRUE if it does, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasModifier(UUID id) {
|
||||
return getModifiers().contains(WrappedAttributeModifier.newBuilder(id).build());
|
||||
return getModifierByUUID(id) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,14 +214,14 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
* @param id - the id to look for.
|
||||
* @return The single attribute modifier with the given ID.
|
||||
*/
|
||||
@Nullable
|
||||
public WrappedAttributeModifier getModifierByUUID(UUID id) {
|
||||
if (hasModifier(id)) {
|
||||
for (WrappedAttributeModifier modifier : getModifiers()) {
|
||||
if (Objects.equal(modifier.getUUID(), id)) {
|
||||
return modifier;
|
||||
}
|
||||
for (WrappedAttributeModifier modifier : getModifiers()) {
|
||||
if (Objects.equal(modifier.getUUID(), id)) {
|
||||
return modifier;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -264,6 +264,10 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
return newBuilder(this).modifiers(modifiers).build();
|
||||
}
|
||||
|
||||
public WrappedAttribute shallowClone() {
|
||||
return newBuilder(this).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
@@ -283,7 +287,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
public int hashCode() {
|
||||
if (attributeModifiers == null)
|
||||
getModifiers();
|
||||
return Objects.hashCode(getAttributeKey(), getBaseValue(), attributeModifiers);
|
||||
return Objects.hashCode(getAttributeKey(), getBaseValue(), attributeModifiers.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,9 +367,9 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
private double baseValue = Double.NaN;
|
||||
private String attributeKey;
|
||||
private PacketContainer packet;
|
||||
private Collection<WrappedAttributeModifier> modifiers = Collections.emptyList();
|
||||
private Set<WrappedAttributeModifier> modifiers = new HashSet<>();
|
||||
|
||||
private Builder(WrappedAttribute template) {
|
||||
Builder(WrappedAttribute template) {
|
||||
if (template != null) {
|
||||
baseValue = template.getBaseValue();
|
||||
attributeKey = template.getAttributeKey();
|
||||
@@ -407,7 +411,14 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder modifiers(Collection<WrappedAttributeModifier> modifiers) {
|
||||
this.modifiers = Preconditions.checkNotNull(modifiers, "modifiers cannot be NULL - use an empty list instead.");
|
||||
Preconditions.checkNotNull(modifiers, "modifiers cannot be NULL - use an empty list instead.");
|
||||
this.modifiers.addAll(modifiers);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addModifier(WrappedAttributeModifier modifier) {
|
||||
Preconditions.checkNotNull(modifier, "modifier cannot be NULL.");
|
||||
this.modifiers.add(modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -416,7 +427,9 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
*
|
||||
* @param packet - the parent packet.
|
||||
* @return This builder, for chaining.
|
||||
* @deprecated Removed in 1.17
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder packet(PacketContainer packet) {
|
||||
if (Preconditions.checkNotNull(packet, "packet cannot be NULL").getType() != PacketType.Play.Server.UPDATE_ATTRIBUTES) {
|
||||
throw new IllegalArgumentException("Packet must be UPDATE_ATTRIBUTES (44)");
|
||||
@@ -431,7 +444,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
* @return Unwrapped modifiers.
|
||||
*/
|
||||
private Set<Object> getUnwrappedModifiers() {
|
||||
final Set<Object> output = new HashSet<>();
|
||||
Set<Object> output = new HashSet<>();
|
||||
|
||||
for (WrappedAttributeModifier modifier : modifiers) {
|
||||
output.add(modifier.getHandle());
|
||||
@@ -476,7 +489,9 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
throw new IllegalArgumentException("Invalid attribute name: " + this.attributeKey);
|
||||
}
|
||||
|
||||
attributeKey = registry.getHolder(attributeKey);
|
||||
if (IS_IN_HOLDER) {
|
||||
attributeKey = registry.getHolder(attributeKey);
|
||||
}
|
||||
} else {
|
||||
attributeKey = this.attributeKey;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.comphenix.protocol.events.InternalStructure;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Represents a wrapper around a AttributeModifier.
|
||||
@@ -23,6 +27,8 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
private static final boolean OPERATION_ENUM = MinecraftVersion.VILLAGE_UPDATE.atOrAbove();
|
||||
static final boolean USES_RESOURCE_LOCATION = MinecraftVersion.v1_21_0.atOrAbove();
|
||||
|
||||
private static final Class<?> OPERATION_CLASS;
|
||||
private static final EquivalentConverter<Operation> OPERATION_CONVERTER;
|
||||
|
||||
@@ -131,41 +137,24 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
throw new IllegalArgumentException("Corrupt operation ID " + id + " detected.");
|
||||
}
|
||||
}
|
||||
|
||||
// Shared structure modifier
|
||||
private static StructureModifier<Object> BASE_MODIFIER;
|
||||
|
||||
|
||||
// The constructor we are interested in
|
||||
private static Constructor<?> ATTRIBUTE_MODIFIER_CONSTRUCTOR;
|
||||
private static ConstructorAccessor ATTRIBUTE_MODIFIER_CONSTRUCTOR;
|
||||
|
||||
// A modifier for the wrapped handler
|
||||
protected StructureModifier<Object> modifier;
|
||||
protected InternalStructure modifier;
|
||||
|
||||
// Cached values
|
||||
@Nullable
|
||||
private final MinecraftKey key;
|
||||
|
||||
@Nullable
|
||||
private final UUID uuid;
|
||||
|
||||
private final Supplier<String> name;
|
||||
private final Operation operation;
|
||||
private final double amount;
|
||||
|
||||
/**
|
||||
* Construct a new wrapped attribute modifier with no associated handle.
|
||||
* <p>
|
||||
* Note that the handle object is not initialized after this constructor.
|
||||
* @param uuid - the UUID.
|
||||
* @param name - the human readable name.
|
||||
* @param amount - the amount.
|
||||
* @param operation - the operation.
|
||||
*/
|
||||
protected WrappedAttributeModifier(UUID uuid, String name, double amount, Operation operation) {
|
||||
super(MinecraftReflection.getAttributeModifierClass());
|
||||
|
||||
// Use the supplied values instead of reading from the NMS instance
|
||||
this.uuid = uuid;
|
||||
this.name = () -> name;
|
||||
this.amount = amount;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct an attribute modifier wrapper around a given NMS instance.
|
||||
* @param handle - the NMS instance.
|
||||
@@ -176,24 +165,29 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
super(MinecraftReflection.getAttributeModifierClass());
|
||||
setHandle(handle);
|
||||
initializeModifier(handle);
|
||||
|
||||
// Load final values, caching them
|
||||
this.uuid = (UUID) modifier.withType(UUID.class).read(0);
|
||||
|
||||
StructureModifier<String> stringMod = modifier.withType(String.class);
|
||||
if (stringMod.size() == 0) {
|
||||
Supplier<String> supplier = (Supplier<String>) modifier.withType(Supplier.class).read(0);
|
||||
this.name = supplier;
|
||||
if (USES_RESOURCE_LOCATION) {
|
||||
this.key = modifier.getMinecraftKeys().read(0);
|
||||
this.uuid = null;
|
||||
this.name = () -> null;
|
||||
} else {
|
||||
this.name = () -> stringMod.read(0);
|
||||
this.key = null;
|
||||
this.uuid = modifier.getUUIDs().read(0);
|
||||
|
||||
Optional<String> name = modifier.getStrings().optionRead(0);
|
||||
if (name.isPresent()) {
|
||||
this.name = name::get;
|
||||
} else {
|
||||
this.name = (Supplier<String>) modifier.getModifier().withType(Supplier.class).read(0);
|
||||
}
|
||||
}
|
||||
|
||||
this.amount = (Double) modifier.withType(double.class).read(0);
|
||||
this.amount = modifier.getDoubles().read(0);
|
||||
|
||||
if (OPERATION_ENUM) {
|
||||
this.operation = modifier.withType(OPERATION_CLASS, OPERATION_CONVERTER).readSafely(0);
|
||||
this.operation = modifier.getModifier().withType(OPERATION_CLASS, OPERATION_CONVERTER).readSafely(0);
|
||||
} else {
|
||||
this.operation = Operation.fromId((Integer) modifier.withType(int.class).readSafely(0));
|
||||
this.operation = Operation.fromId(modifier.getIntegers().readSafely(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,12 +200,31 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @param operation - the operation.
|
||||
*/
|
||||
protected WrappedAttributeModifier(@Nonnull Object handle, UUID uuid, String name, double amount, Operation operation) {
|
||||
this(uuid, name, amount, operation);
|
||||
super(MinecraftReflection.getAttributeModifierClass());
|
||||
|
||||
this.uuid = uuid;
|
||||
this.name = () -> name;
|
||||
this.amount = amount;
|
||||
this.operation = operation;
|
||||
this.key = null;
|
||||
|
||||
// Initialize handle and modifier
|
||||
setHandle(handle);
|
||||
initializeModifier(handle);
|
||||
}
|
||||
|
||||
protected WrappedAttributeModifier(Object handle, MinecraftKey key, double amount, Operation operation) {
|
||||
super(MinecraftReflection.getAttributeModifierClass());
|
||||
|
||||
this.uuid = null;
|
||||
this.key = key;
|
||||
this.amount = amount;
|
||||
this.name = key::toString;
|
||||
this.operation = operation;
|
||||
|
||||
setHandle(handle);
|
||||
initializeModifier(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new attribute modifier builder.
|
||||
@@ -256,11 +269,11 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @param handle - the handle.
|
||||
*/
|
||||
private void initializeModifier(@Nonnull Object handle) {
|
||||
// Initialize modifier
|
||||
if (BASE_MODIFIER == null) {
|
||||
BASE_MODIFIER = new StructureModifier<>(MinecraftReflection.getAttributeModifierClass());
|
||||
}
|
||||
this.modifier = BASE_MODIFIER.withTarget(handle);
|
||||
this.modifier = InternalStructure.getConverter().getSpecific(handle);
|
||||
}
|
||||
|
||||
public MinecraftKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,7 +325,7 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @param pending - TRUE if it is pending, FALSE otherwise.
|
||||
*/
|
||||
public void setPendingSynchronization(boolean pending) {
|
||||
modifier.withType(boolean.class).write(0, pending);
|
||||
modifier.getBooleans().write(0, pending);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +333,7 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean isPendingSynchronization() {
|
||||
return (Boolean) modifier.withType(boolean.class).optionRead(0).orElse(false);
|
||||
return modifier.getBooleans().optionRead(0).orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,25 +344,34 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @return TRUE if the given object is the same, FALSE otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj == this) return true;
|
||||
if (obj == null) return false;
|
||||
|
||||
if (obj instanceof WrappedAttributeModifier) {
|
||||
WrappedAttributeModifier other = (WrappedAttributeModifier) obj;
|
||||
|
||||
// Ensure they are equal
|
||||
return Objects.equal(uuid, other.getUUID());
|
||||
if (USES_RESOURCE_LOCATION) {
|
||||
return this.key.equals(other.key);
|
||||
} else {
|
||||
return this.uuid.equals(other.uuid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return uuid != null ? uuid.hashCode() : 0;
|
||||
if (USES_RESOURCE_LOCATION) {
|
||||
return key != null ? key.hashCode() : 0;
|
||||
} else {
|
||||
return uuid != null ? uuid.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[amount=" + amount + ", operation=" + operation + ", name='" + name + "', id=" + uuid + ", serialize=" + isPendingSynchronization() + "]";
|
||||
return "[key=" + key + ", amount=" + amount + ", operation=" + operation + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,13 +385,15 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
private String name = "Unknown";
|
||||
private double amount;
|
||||
private UUID uuid;
|
||||
private MinecraftKey key;
|
||||
|
||||
private Builder(WrappedAttributeModifier template) {
|
||||
if (template != null) {
|
||||
operation = template.getOperation();
|
||||
name = template.getName();
|
||||
amount = template.getAmount();
|
||||
uuid = template.getUUID();
|
||||
this.operation = template.getOperation();
|
||||
this.name = template.getName();
|
||||
this.amount = template.getAmount();
|
||||
this.uuid = template.getUUID();
|
||||
this.key = template.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +406,7 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @param uuid - the uuid to supply to the new object.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder uuid(@Nonnull UUID uuid) {
|
||||
this.uuid = Preconditions.checkNotNull(uuid, "uuid cannot be NULL.");
|
||||
return this;
|
||||
@@ -403,11 +428,21 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
* @param name - the name of the modifier.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder name(@Nonnull String name) {
|
||||
this.name = Preconditions.checkNotNull(name, "name cannot be NULL.");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder key(@Nonnull MinecraftKey key) {
|
||||
this.key = Preconditions.checkNotNull(key, "key cannot be NULL.");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder key(String prefix, String value) {
|
||||
return key(new MinecraftKey(prefix, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount to modify in the operation.
|
||||
*
|
||||
@@ -435,12 +470,28 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
|
||||
// Construct it
|
||||
try {
|
||||
// No need to read these values with a modifier
|
||||
return new WrappedAttributeModifier(
|
||||
ATTRIBUTE_MODIFIER_CONSTRUCTOR.newInstance(
|
||||
uuid, name, amount, getOperationParam(operation)),
|
||||
uuid, name, amount, operation
|
||||
);
|
||||
if (USES_RESOURCE_LOCATION) {
|
||||
if (key == null) {
|
||||
UUID uuid = this.uuid != null ? this.uuid : UUID.randomUUID();
|
||||
key = new MinecraftKey("protocollib", uuid.toString());
|
||||
}
|
||||
|
||||
Object handle = ATTRIBUTE_MODIFIER_CONSTRUCTOR.invoke(
|
||||
MinecraftKey.getConverter().getGeneric(key),
|
||||
amount,
|
||||
OPERATION_CONVERTER.getGeneric(operation)
|
||||
);
|
||||
|
||||
return new WrappedAttributeModifier(handle, key, amount, operation);
|
||||
} else {
|
||||
Object handle = ATTRIBUTE_MODIFIER_CONSTRUCTOR.invoke(
|
||||
uuid, name, amount, getOperationParam(operation));
|
||||
|
||||
return new WrappedAttributeModifier(
|
||||
handle,
|
||||
uuid, name, amount, operation
|
||||
);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot construct AttributeModifier.", e);
|
||||
}
|
||||
@@ -451,22 +502,30 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
return OPERATION_ENUM ? OPERATION_CONVERTER.getGeneric(operation) : operation.getId();
|
||||
}
|
||||
|
||||
private static Constructor<?> getConstructor() {
|
||||
FuzzyMethodContract.Builder builder = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(4)
|
||||
private static ConstructorAccessor getConstructor() {
|
||||
FuzzyMethodContract.Builder builder = FuzzyMethodContract.newBuilder();
|
||||
|
||||
if (USES_RESOURCE_LOCATION) {
|
||||
builder.parameterCount(3)
|
||||
.parameterDerivedOf(MinecraftReflection.getMinecraftKeyClass())
|
||||
.parameterExactType(double.class)
|
||||
.parameterExactType(OPERATION_CLASS);
|
||||
} else {
|
||||
builder.parameterCount(4)
|
||||
.parameterDerivedOf(UUID.class, 0)
|
||||
.parameterExactType(String.class, 1)
|
||||
.parameterExactType(double.class, 2);
|
||||
if (OPERATION_ENUM) {
|
||||
builder = builder.parameterExactType(OPERATION_CLASS, 3);
|
||||
} else {
|
||||
builder = builder.parameterExactType(int.class, 3);
|
||||
|
||||
if (OPERATION_ENUM) {
|
||||
builder.parameterExactType(OPERATION_CLASS, 3);
|
||||
} else {
|
||||
builder.parameterExactType(int.class, 3);
|
||||
}
|
||||
}
|
||||
|
||||
Constructor<?> ret = FuzzyReflection.fromClass(MinecraftReflection.getAttributeModifierClass(), true)
|
||||
.getConstructor(builder.build());
|
||||
ret.setAccessible(true);
|
||||
return ret;
|
||||
Constructor<?> ret = FuzzyReflection
|
||||
.fromClass(MinecraftReflection.getAttributeModifierClass(), true)
|
||||
.getConstructor(builder.build());
|
||||
return Accessors.getConstructorAccessor(ret);
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,11 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -33,9 +35,12 @@ import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityPose;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -200,7 +205,7 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
impl.clear();
|
||||
}
|
||||
|
||||
// ---- Object Getters
|
||||
// ---- 0: byte
|
||||
|
||||
/**
|
||||
* Get a watched byte.
|
||||
@@ -212,6 +217,12 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return (Byte) getObject(index);
|
||||
}
|
||||
|
||||
public void setByte(int index, byte value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Byte.class)), value, update);
|
||||
}
|
||||
|
||||
// ---- short (unused)
|
||||
|
||||
/**
|
||||
* Get a watched short.
|
||||
*
|
||||
@@ -222,6 +233,8 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return (Short) getObject(index);
|
||||
}
|
||||
|
||||
// ---- 1: varint (integer)
|
||||
|
||||
/**
|
||||
* Get a watched integer.
|
||||
*
|
||||
@@ -232,6 +245,22 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return (Integer) getObject(index);
|
||||
}
|
||||
|
||||
public void setInteger(int index, Integer value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Integer.class)), value, update);
|
||||
}
|
||||
|
||||
// ---- 2: varlong (long)
|
||||
|
||||
public Long getLong(int index) {
|
||||
return (Long) getObject(index);
|
||||
}
|
||||
|
||||
public void setLong(int index, Long value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Long.class)), value, update);
|
||||
}
|
||||
|
||||
// ---- 3: float
|
||||
|
||||
/**
|
||||
* Get a watched float.
|
||||
*
|
||||
@@ -242,6 +271,12 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return (Float) getObject(index);
|
||||
}
|
||||
|
||||
public void setFloat(int index, Float value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Float.class)), value, update);
|
||||
}
|
||||
|
||||
// ---- 4: string
|
||||
|
||||
/**
|
||||
* Get a watched string.
|
||||
*
|
||||
@@ -252,6 +287,32 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return (String) getObject(index);
|
||||
}
|
||||
|
||||
public void setString(int index, String value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(String.class)), value, update);
|
||||
}
|
||||
|
||||
// ---- 5: text component
|
||||
|
||||
public WrappedChatComponent getChatComponent(int index) {
|
||||
return (WrappedChatComponent) getObject(index);
|
||||
}
|
||||
|
||||
public void setChatComponent(int index, WrappedChatComponent value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getChatComponentSerializer()), value, update);
|
||||
}
|
||||
|
||||
// ---- 6: optional text component
|
||||
|
||||
public Optional<WrappedChatComponent> getOptionalChatComponent(int index) {
|
||||
return (Optional<WrappedChatComponent>) getObject(index);
|
||||
}
|
||||
|
||||
public void setOptionalChatComponent(int index, Optional<WrappedChatComponent> value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getChatComponentSerializer(true)), value, update);
|
||||
}
|
||||
|
||||
// ---- 7: slot (item stack)
|
||||
|
||||
/**
|
||||
* Get a watched string.
|
||||
*
|
||||
@@ -262,6 +323,158 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return (ItemStack) getObject(index);
|
||||
}
|
||||
|
||||
public void setItemStack(int index, ItemStack itemStack, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getItemStackSerializer(false)), itemStack, update);
|
||||
}
|
||||
|
||||
// ---- 8: boolean
|
||||
|
||||
public Boolean getBoolean(int index) {
|
||||
return (Boolean) getObject(index);
|
||||
}
|
||||
|
||||
public void setBoolean(int index, Boolean value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Boolean.class)), value, update);
|
||||
}
|
||||
|
||||
// ---- 9: rotations
|
||||
// TODO
|
||||
|
||||
// ---- 10: position
|
||||
|
||||
public BlockPosition getPosition(int index) {
|
||||
return (BlockPosition) getObject(index);
|
||||
}
|
||||
|
||||
public void setPosition(int index, BlockPosition position, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getBlockPositionSerializer(false)), position, update);
|
||||
}
|
||||
|
||||
// ---- 11: optional position
|
||||
|
||||
public Optional<BlockPosition> getOptionalPosition(int index) {
|
||||
return (Optional<BlockPosition>) getObject(index);
|
||||
}
|
||||
|
||||
public void setOptionalPosition(int index, java.util.Optional<BlockPosition> position, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getBlockPositionSerializer(true)), position, update);
|
||||
}
|
||||
|
||||
// ---- 12: direction
|
||||
|
||||
public Direction getDirection(int index) {
|
||||
return (Direction) getObject(index);
|
||||
}
|
||||
|
||||
public void setDirection(int index, Direction direction, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getDirectionSerializer()), direction, update);
|
||||
}
|
||||
|
||||
// ---- 13: optional uuid
|
||||
|
||||
public Optional<UUID> getOptionalUUID(int index) {
|
||||
return (Optional<UUID>) getObject(index);
|
||||
}
|
||||
|
||||
public void setOptionalUUID(int index, Optional<UUID> uuid, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getUUIDSerializer(true)), uuid, update);
|
||||
}
|
||||
|
||||
// ---- 14: block state
|
||||
|
||||
public WrappedBlockData getBlockState(int index) {
|
||||
return (WrappedBlockData) getObject(index);
|
||||
}
|
||||
|
||||
public void setBlockState(int index, WrappedBlockData blockData, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getBlockDataSerializer(false)), blockData, update);
|
||||
}
|
||||
|
||||
// ---- 15: optional block state
|
||||
|
||||
public Optional<WrappedBlockData> getOptionalBlockState(int index) {
|
||||
return (Optional<WrappedBlockData>) getObject(index);
|
||||
}
|
||||
|
||||
public void setOptionalBlockState(int index, Optional<WrappedBlockData> value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getBlockDataSerializer(true)), value, update);
|
||||
}
|
||||
|
||||
// ---- 16: NBT
|
||||
|
||||
public NbtCompound getNBTCompound(int index) {
|
||||
return (NbtCompound) getObject(index);
|
||||
}
|
||||
|
||||
public void setNBTCompound(int index, NbtCompound nbt, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.getNBTCompoundSerializer()), nbt, update);
|
||||
}
|
||||
|
||||
// ---- 17: particle
|
||||
|
||||
public WrappedParticle<?> getParticle(int index) {
|
||||
return (WrappedParticle<?>) getObject(index);
|
||||
}
|
||||
|
||||
public void setParticle(int index, WrappedParticle<?> particle, boolean update) {
|
||||
// TODO: is ParticleParam correct?
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(MinecraftReflection.getParticleParam(), false)), particle, update);
|
||||
}
|
||||
|
||||
// ---- 18: villager data
|
||||
|
||||
public WrappedVillagerData getVillagerData(int index) {
|
||||
return (WrappedVillagerData) getObject(index);
|
||||
}
|
||||
|
||||
public void setVillagerData(int index, WrappedVillagerData data, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(WrappedVillagerData.getNmsClass(), false)), data, update);
|
||||
}
|
||||
|
||||
// ---- 19: optional varint (int)
|
||||
|
||||
public Optional<Integer> getOptionalInteger(int index) {
|
||||
return (Optional<Integer>) getObject(index);
|
||||
}
|
||||
|
||||
public void setOptionalInteger(int index, Optional<Integer> value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Integer.class, true)), value, update);
|
||||
}
|
||||
|
||||
// ---- 20: pose
|
||||
|
||||
public EntityPose getPose(int index) {
|
||||
return (EntityPose) getObject(index);
|
||||
}
|
||||
|
||||
public void setPose(int index, EntityPose pose, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(EnumWrappers.getEntityPoseClass(), false)), pose, update);
|
||||
}
|
||||
|
||||
// TODO: 21-25, 27
|
||||
|
||||
// ---- 21: cat variant
|
||||
|
||||
// ---- 22: frog variant
|
||||
|
||||
// ---- 23: optional global position
|
||||
|
||||
// ---- 24: painting variant
|
||||
|
||||
// ---- 25: sniffer state
|
||||
|
||||
// ---- 26: vector3
|
||||
|
||||
public Vector3F getVector3F(int index) {
|
||||
return (Vector3F) getObject(index);
|
||||
}
|
||||
|
||||
public void setVector3F(int index, Vector3F vector, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, Registry.get(Vector3F.getMinecraftClass(), false)), vector, update);
|
||||
}
|
||||
|
||||
// ---- 27: quaternion
|
||||
|
||||
/**
|
||||
* Retrieve a watchable object by index.
|
||||
*
|
||||
@@ -439,6 +652,22 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
impl.setEntity(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the contents of this data watcher to a list of WrappedDataValues
|
||||
* for use in the ENTITY_METADATA packet
|
||||
* @return The data value collection
|
||||
*/
|
||||
public List<WrappedDataValue> toDataValueCollection() {
|
||||
List<WrappedWatchableObject> objects = impl.getWatchableObjects();
|
||||
List<WrappedDataValue> values = new ArrayList<>(objects.size());
|
||||
for (WrappedWatchableObject object : objects) {
|
||||
WrappedDataWatcherObject watcherObj = object.getWatcherObject();
|
||||
Object value = WrappedWatchableObject.getUnwrapped(object.getRawValue());
|
||||
values.add(new WrappedDataValue(watcherObj.getIndex(), watcherObj.getSerializer(), value));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private static final ImmutableBiMap<Class<?>, Integer> CLASS_TO_ID = new ImmutableBiMap.Builder<Class<?>, Integer>()
|
||||
.put(Byte.class, 0)
|
||||
.put(Short.class, 1)
|
||||
@@ -756,7 +985,9 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
*/
|
||||
public static class Registry {
|
||||
private static boolean INITIALIZED = false;
|
||||
private static List<Serializer> REGISTRY = new ArrayList<>();
|
||||
|
||||
private static Map<Class<?>, Serializer> RAW_REGISTRY = null;
|
||||
private static Map<Class<?>, Serializer> OPTIONAL_REGISTRY = null;
|
||||
|
||||
/**
|
||||
* Gets the first serializer associated with a given class.
|
||||
@@ -774,13 +1005,13 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
Validate.notNull(clazz,"Class cannot be null!");
|
||||
initialize();
|
||||
|
||||
for (Serializer serializer : REGISTRY) {
|
||||
if (serializer.getType().equals(clazz)) {
|
||||
return serializer;
|
||||
}
|
||||
Serializer serializer = RAW_REGISTRY.getOrDefault(clazz,
|
||||
OPTIONAL_REGISTRY.getOrDefault(clazz, null));
|
||||
if (serializer == null) {
|
||||
throw new IllegalArgumentException("No serializer found for " + clazz);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No serializer found for " + clazz);
|
||||
return serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -797,16 +1028,12 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
Validate.notNull(clazz, "Class cannot be null!");
|
||||
initialize();
|
||||
|
||||
Validate.notEmpty(REGISTRY, "Registry has no elements!");
|
||||
|
||||
for (Serializer serializer : REGISTRY) {
|
||||
if (serializer.getType().equals(clazz)
|
||||
&& serializer.isOptional() == optional) {
|
||||
return serializer;
|
||||
}
|
||||
Serializer serializer = optional ? OPTIONAL_REGISTRY.get(clazz) : RAW_REGISTRY.get(clazz);
|
||||
if (serializer == null) {
|
||||
throw new IllegalArgumentException("No serializer found for " + (optional ? "Optional<" + clazz + ">" : clazz));
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No serializer found for " + (optional ? "Optional<" + clazz + ">" : clazz));
|
||||
return serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -818,7 +1045,13 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
Validate.notNull(handle, "handle cannot be null!");
|
||||
initialize();
|
||||
|
||||
for (Serializer serializer : REGISTRY) {
|
||||
for (Serializer serializer : RAW_REGISTRY.values()) {
|
||||
if (serializer.getHandle().equals(handle)) {
|
||||
return serializer;
|
||||
}
|
||||
}
|
||||
|
||||
for (Serializer serializer : OPTIONAL_REGISTRY.values()) {
|
||||
if (serializer.getHandle().equals(handle)) {
|
||||
return serializer;
|
||||
}
|
||||
@@ -834,6 +1067,9 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Class<?>, Serializer> rawRegistry = new HashMap<>();
|
||||
Map<Class<?>, Serializer> optionalRegistry = new HashMap<>();
|
||||
|
||||
List<Field> candidates = FuzzyReflection.fromClass(MinecraftReflection.getDataWatcherRegistryClass(), true)
|
||||
.getFieldListByType(MinecraftReflection.getDataWatcherSerializerClass());
|
||||
for (Field candidate : candidates) {
|
||||
@@ -867,9 +1103,16 @@ public class WrappedDataWatcher implements IDataWatcher {
|
||||
throw new RuntimeException("Failed to read serializer: " + candidate.getName());
|
||||
}
|
||||
|
||||
REGISTRY.add(new Serializer(innerClass, serializer, optional));
|
||||
if (optional) {
|
||||
optionalRegistry.put(innerClass, new Serializer(innerClass, serializer, true));
|
||||
} else {
|
||||
rawRegistry.put(innerClass, new Serializer(innerClass, serializer, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RAW_REGISTRY = ImmutableMap.copyOf(rawRegistry);
|
||||
OPTIONAL_REGISTRY = ImmutableMap.copyOf(optionalRegistry);
|
||||
}
|
||||
|
||||
// ---- Helper methods
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -30,22 +32,26 @@ public class WrappedParticle<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> particleType = MinecraftReflection.isMojangMapped()
|
||||
? MinecraftReflection.getParticleTypeClass()
|
||||
: MinecraftReflection.getParticleClass();
|
||||
|
||||
Preconditions.checkNotNull(particleType, "Cannot find ParticleType class (MojMap: " + MinecraftReflection.isMojangMapped() + ")");
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("CraftParticle"));
|
||||
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
|
||||
FuzzyMethodContract contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(Particle.class)
|
||||
.parameterExactArray(MinecraftReflection.isMojangMapped()
|
||||
? MinecraftReflection.getParticleTypeClass()
|
||||
: MinecraftReflection.getParticleClass())
|
||||
.parameterExactArray(particleType)
|
||||
.build();
|
||||
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
FuzzyReflection particleParam = FuzzyReflection.fromClass(MinecraftReflection.getParticleParam(), false);
|
||||
contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.returnTypeExact(MinecraftReflection.getParticleClass())
|
||||
.returnTypeExact(particleType)
|
||||
.parameterCount(0)
|
||||
.build();
|
||||
getType = Accessors.getMethodAccessor(particleParam.getMethod(contract));
|
||||
|
||||
@@ -154,8 +154,7 @@ public class WrappedTeamParameters extends AbstractWrapper {
|
||||
Preconditions.checkNotNull(collisionRule, "Collision rule not set");
|
||||
Preconditions.checkNotNull(color, "Color not set");
|
||||
|
||||
// Not technically a packet, but it has a PacketDataSerializer constructor, so it works fine
|
||||
Object handle = StructureCache.newPacket(getNmsClassOrThrow());
|
||||
Object handle = StructureCache.newInstance(getNmsClassOrThrow());
|
||||
|
||||
WrappedTeamParameters wrapped = new WrappedTeamParameters(handle);
|
||||
wrapped.writeComponent(0, displayName);
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
@@ -23,9 +25,8 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import static com.comphenix.protocol.utility.MinecraftReflection.is;
|
||||
|
||||
@@ -80,11 +81,13 @@ public final class WrappedWatchableObject extends AbstractWrapper {
|
||||
constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]);
|
||||
}
|
||||
|
||||
Object nmsValue = getUnwrapped(value);
|
||||
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
return constructor.invoke(watcherObject.getHandle(), value);
|
||||
return constructor.invoke(watcherObject.getHandle(), nmsValue);
|
||||
} else {
|
||||
// new WatchableObject(classId, index, value)
|
||||
return constructor.invoke(WrappedDataWatcher.getTypeID(value.getClass()), watcherObject.getIndex(), value);
|
||||
return constructor.invoke(WrappedDataWatcher.getTypeID(value.getClass()), watcherObject.getIndex(), nmsValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,22 +17,6 @@
|
||||
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
@@ -47,6 +31,23 @@ import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Factory methods for creating NBT elements, lists and compounds.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.comphenix.protocol.wrappers.nbt.io;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
@@ -12,9 +16,6 @@ import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtList;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtWrapper;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class NbtBinarySerializer {
|
||||
|
||||
@@ -153,15 +154,23 @@ public class NbtBinarySerializer {
|
||||
public LoadMethodConfigPhaseUpdate() {
|
||||
// there are now two methods with the same signature: readAnyTag/readUnnamedTag & writeAnyTag/writeUnnamedTag
|
||||
// we can only find the correct method here by using the method name... thanks Mojang
|
||||
String readNbtMethodName = MinecraftReflection.isMojangMapped()
|
||||
? "readAnyTag"
|
||||
: "b";
|
||||
|
||||
String writeNbtMethodName = MinecraftReflection.isMojangMapped()
|
||||
? "writeAnyTag"
|
||||
: "a";
|
||||
|
||||
Method readNbtMethod = getUtilityClass().getMethod(FuzzyMethodContract.newBuilder()
|
||||
.nameExact("b")
|
||||
.nameExact(readNbtMethodName)
|
||||
.returnTypeExact(MinecraftReflection.getNBTBaseClass())
|
||||
.parameterExactArray(DataInput.class, this.readLimitClass)
|
||||
.build());
|
||||
this.readNbt = Accessors.getMethodAccessor(readNbtMethod);
|
||||
|
||||
Method writeNbtMethod = getUtilityClass().getMethod(FuzzyMethodContract.newBuilder()
|
||||
.nameExact("a")
|
||||
.nameExact(writeNbtMethodName)
|
||||
.parameterExactArray(MinecraftReflection.getNBTBaseClass(), DataOutput.class)
|
||||
.build());
|
||||
this.writeNbt = Accessors.getMethodAccessor(writeNbtMethod);
|
||||
|
||||
@@ -10,42 +10,36 @@ import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.commands.CommandDispatcher;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.core.IRegistryCustom;
|
||||
import net.minecraft.commands.Commands.CommandSelection;
|
||||
import net.minecraft.core.LayeredRegistryAccess;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.RegistryDataLoader;
|
||||
import net.minecraft.server.DataPackResources;
|
||||
import net.minecraft.server.DispenserRegistry;
|
||||
import net.minecraft.server.Main;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.server.RegistryLayer;
|
||||
import net.minecraft.server.ReloadableServerResources;
|
||||
import net.minecraft.server.WorldLoader;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServerProperties;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import net.minecraft.server.packs.EnumResourcePackType;
|
||||
import net.minecraft.server.packs.repository.ResourcePackLoader;
|
||||
import net.minecraft.server.packs.repository.ResourcePackRepository;
|
||||
import net.minecraft.server.packs.repository.ResourcePackSourceVanilla;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.server.packs.repository.Pack;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.server.packs.repository.ServerPacksSource;
|
||||
import net.minecraft.server.packs.resources.CloseableResourceManager;
|
||||
import net.minecraft.server.packs.resources.MultiPackResourceManager;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import net.minecraft.world.item.enchantment.Enchantments;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.CraftLootTable;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.util.CraftMagicNumbers;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.util.Versioning;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.CraftLootTable;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.util.CraftMagicNumbers;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.util.Versioning;
|
||||
import org.spigotmc.SpigotWorldConfig;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -87,6 +81,8 @@ public class BukkitInitialization {
|
||||
synchronized (initLock) {
|
||||
if (initialized) {
|
||||
return;
|
||||
} else {
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -99,33 +95,33 @@ public class BukkitInitialization {
|
||||
instance.setPackage();
|
||||
|
||||
// Minecraft Data Init
|
||||
SharedConstants.a(); // .tryDetectVersion()
|
||||
DispenserRegistry.a(); // .bootStrap()
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
|
||||
ResourcePackRepository resourcePackRepository = ResourcePackSourceVanilla.c(); // .createVanillaTrustedRepository()
|
||||
resourcePackRepository.a(); // .reload()
|
||||
PackRepository resourcePackRepository = ServerPacksSource.createVanillaTrustedRepository();
|
||||
resourcePackRepository.reload();
|
||||
|
||||
ResourceManager resourceManager = new ResourceManager(
|
||||
EnumResourcePackType.b /* SERVER_DATA */,
|
||||
resourcePackRepository.c() /* getAvailablePacks() */ .stream().map(ResourcePackLoader::f /* openFull() */).collect(Collectors.toList()));
|
||||
LayeredRegistryAccess<RegistryLayer> layeredRegistryAccess = RegistryLayer.a(); // .createRegistryAccess()
|
||||
layeredRegistryAccess = WorldLoader.b(resourceManager, layeredRegistryAccess, RegistryLayer.b /* WORLDGEN */, RegistryDataLoader.a /* WORLDGEN_REGISTRIES */); // .loadAndReplaceLayer()
|
||||
IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().d(); // .compositeAccess().freeze()
|
||||
// IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().c(); // .compositeAccess().freeze()
|
||||
CloseableResourceManager resourceManager = new MultiPackResourceManager(
|
||||
PackType.SERVER_DATA,
|
||||
resourcePackRepository.getAvailablePacks().stream().map(Pack::open).collect(Collectors.toList())
|
||||
);
|
||||
LayeredRegistryAccess<RegistryLayer> layeredRegistryAccess = RegistryLayer.createRegistryAccess();
|
||||
layeredRegistryAccess = WorldLoader.loadAndReplaceLayer(resourceManager, layeredRegistryAccess, RegistryLayer.WORLDGEN, RegistryDataLoader.WORLDGEN_REGISTRIES);
|
||||
RegistryAccess.Frozen registryCustom = layeredRegistryAccess.compositeAccess().freeze();
|
||||
|
||||
DataPackResources dataPackResources = DataPackResources.a(
|
||||
resourceManager,
|
||||
layeredRegistryAccess,
|
||||
FeatureFlagSet.a() /* REGISTRY.allFlags() */,
|
||||
CommandDispatcher.ServerType.b /* DEDICATED */,
|
||||
0,
|
||||
MoreExecutors.directExecutor(),
|
||||
MoreExecutors.directExecutor()
|
||||
ReloadableServerResources dataPackResources = ReloadableServerResources.loadResources(
|
||||
resourceManager,
|
||||
layeredRegistryAccess,
|
||||
FeatureFlags.REGISTRY.allFlags(),
|
||||
CommandSelection.DEDICATED,
|
||||
0,
|
||||
MoreExecutors.directExecutor(),
|
||||
MoreExecutors.directExecutor()
|
||||
).join();
|
||||
// dataPackResources.a(registryCustom); // .updateRegistryTags()
|
||||
dataPackResources.updateRegistryTags();
|
||||
|
||||
try {
|
||||
IRegistry.class.getName();
|
||||
RegistryAccess.class.getName();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@@ -137,7 +133,7 @@ public class BukkitInitialization {
|
||||
CraftServer mockedServer = mock(CraftServer.class);
|
||||
DedicatedServer mockedGameServer = mock(DedicatedServer.class);
|
||||
|
||||
when(mockedGameServer.bc()/*registryAccess*/).thenReturn(registryCustom);
|
||||
when(mockedGameServer.registryAccess()).thenReturn(registryCustom);
|
||||
|
||||
when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
|
||||
when(mockedServer.getName()).thenReturn("Mock Server");
|
||||
@@ -148,16 +144,22 @@ public class BukkitInitialization {
|
||||
when(mockedServer.isPrimaryThread()).thenReturn(true);
|
||||
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
|
||||
when(mockedServer.getUnsafe()).thenReturn(CraftMagicNumbers.INSTANCE);
|
||||
/*when(mockedServer.getLootTable(any())).thenAnswer(invocation -> {
|
||||
when(mockedServer.getLootTable(any())).thenAnswer(invocation -> {
|
||||
NamespacedKey key = invocation.getArgument(0);
|
||||
return new CraftLootTable(key, dataPackResources.b().b(CraftNamespacedKey.toMinecraft(key)));
|
||||
});*/
|
||||
when(mockedServer.getRegistry(any())).thenAnswer(invocation -> {
|
||||
Class<Keyed> registryType = invocation.getArgument(0);
|
||||
return CraftRegistry.createRegistry(registryType, registryCustom);
|
||||
return new CraftLootTable(key, dataPackResources.fullRegistries().getLootTable(CraftLootTable.bukkitKeyToMinecraft(key)));
|
||||
});
|
||||
|
||||
WorldServer nmsWorld = mock(WorldServer.class);
|
||||
when(mockedServer.getRegistry(any())).thenAnswer(invocation -> {
|
||||
Class<? extends Keyed> registryType = invocation.getArgument(0);
|
||||
|
||||
try {
|
||||
return CraftRegistry.createRegistry(registryType, registryCustom);
|
||||
} catch (Exception ignored) {
|
||||
return mock(org.bukkit.Registry.class);
|
||||
}
|
||||
});
|
||||
|
||||
ServerLevel nmsWorld = mock(ServerLevel.class);
|
||||
SpigotWorldConfig mockWorldConfig = mock(SpigotWorldConfig.class);
|
||||
|
||||
try {
|
||||
@@ -178,10 +180,8 @@ public class BukkitInitialization {
|
||||
CraftRegistry.setMinecraftRegistry(registryCustom);
|
||||
|
||||
// Init Enchantments
|
||||
Enchantments.A.getClass();
|
||||
Enchantments.AQUA_AFFINITY.getClass();
|
||||
// Enchantment.stopAcceptingRegistrations();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,29 +14,22 @@
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Play.Server;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
|
||||
import net.minecraft.network.protocol.login.PacketLoginInStart;
|
||||
import net.minecraft.network.protocol.login.ServerboundHelloPacket;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
@@ -260,7 +253,7 @@ public class PacketTypeTest {
|
||||
@Test
|
||||
public void testLoginStart() {
|
||||
// This packet is critical for handleLoin
|
||||
assertEquals(PacketLoginInStart.class, PacketType.Login.Client.START.getPacketClass());
|
||||
assertEquals(ServerboundHelloPacket.class, PacketType.Login.Client.START.getPacketClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -287,24 +280,6 @@ public class PacketTypeTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- lots of constructor parameters :(
|
||||
public void testCreateMapChunk() {
|
||||
new PacketContainer(PacketType.Play.Server.MAP_CHUNK);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- ScoreboardObjective parameter in constructor is causing this to fail
|
||||
public void testCreateScoreboardObjective() {
|
||||
new PacketContainer(PacketType.Play.Server.SCOREBOARD_OBJECTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- Entity parameter in constructor is causing this to fail
|
||||
public void testCreateEntitySound() {
|
||||
new PacketContainer(PacketType.Play.Server.ENTITY_SOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPacketCreation() {
|
||||
List<PacketType> failed = new ArrayList<>();
|
||||
@@ -313,12 +288,6 @@ public class PacketTypeTest {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == PacketType.Play.Server.ENTITY_SOUND
|
||||
|| type == PacketType.Play.Server.SCOREBOARD_OBJECTIVE
|
||||
|| type == PacketType.Play.Server.MAP_CHUNK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
new PacketContainer(type);
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -15,16 +15,14 @@
|
||||
*/
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -41,39 +39,56 @@ import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.*;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.ComponentConverter;
|
||||
import com.comphenix.protocol.wrappers.CustomPacketPayloadWrapper;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.MovingObjectPositionBlock;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
||||
import com.comphenix.protocol.wrappers.WrappedAttribute;
|
||||
import com.comphenix.protocol.wrappers.WrappedAttributeModifier;
|
||||
import com.comphenix.protocol.wrappers.WrappedBlockData;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataValue;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedMessageSignature;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
||||
import com.comphenix.protocol.wrappers.WrappedRemoteChatSessionData;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.PacketDataSerializer;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.custom.BrandPayload;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.resources.MinecraftKey;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket.AttributeSnapshot;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectList;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.animal.CatVariant;
|
||||
import net.minecraft.world.entity.animal.FrogVariant;
|
||||
import org.apache.commons.lang.SerializationUtils;
|
||||
@@ -91,17 +106,9 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemCollectionsEqual;
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static com.comphenix.protocol.utility.TestUtils.equivalentItem;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static com.comphenix.protocol.utility.TestUtils.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class PacketContainerTest {
|
||||
|
||||
@@ -199,6 +206,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO ???
|
||||
public void testGetStringArrays() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Client.UPDATE_SIGN);
|
||||
this.testObjectArray(packet.getStringArrays(), 0,
|
||||
@@ -334,7 +342,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Disabled // TODO -- handle type is null
|
||||
// // @Disabled // TODO -- handle type is null
|
||||
public void testGetDataValueCollectionModifier() {
|
||||
PacketContainer entityMetadata = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
|
||||
StructureModifier<List<WrappedDataValue>> watchableAccessor = entityMetadata.getDataValueCollectionModifier();
|
||||
@@ -342,8 +350,8 @@ public class PacketContainerTest {
|
||||
assertEquals(0, watchableAccessor.read(0).size());
|
||||
|
||||
List<WrappedDataValue> values = Lists.newArrayList(
|
||||
new WrappedDataValue(0, Registry.get(Byte.class), (byte) 21),
|
||||
new WrappedDataValue(1, Registry.get(String.class), "World"));
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 21),
|
||||
new WrappedDataValue(1, WrappedDataWatcher.Registry.get(String.class), "World"));
|
||||
|
||||
// Insert and read back
|
||||
watchableAccessor.write(0, values);
|
||||
@@ -371,9 +379,9 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO
|
||||
// @Disabled // TODO
|
||||
public void testSerialization() {
|
||||
PacketContainer useItem = new PacketContainer(PacketType.Play.Client.USE_ITEM);
|
||||
PacketContainer useItem = new PacketContainer(PacketType.Play.Client.USE_ITEM_ON);
|
||||
useItem.getMovingBlockPositions().write(0, new MovingObjectPositionBlock(
|
||||
new BlockPosition(0, 1, 0),
|
||||
new Vector(0, 1, 0),
|
||||
@@ -385,7 +393,7 @@ public class PacketContainerTest {
|
||||
|
||||
PacketContainer copy = (PacketContainer) SerializationUtils.clone(useItem);
|
||||
|
||||
assertEquals(PacketType.Play.Client.USE_ITEM, copy.getType());
|
||||
assertEquals(PacketType.Play.Client.USE_ITEM_ON, copy.getType());
|
||||
assertEquals(Hand.MAIN_HAND, copy.getHands().read(0));
|
||||
assertEquals(5, copy.getIntegers().read(0));
|
||||
|
||||
@@ -501,45 +509,66 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- cloning fails
|
||||
public void testAttributeList() {
|
||||
PacketContainer attribute = new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES);
|
||||
attribute.getIntegers().write(0, 123); // Entity ID
|
||||
public void testAttributeCloning() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES);
|
||||
|
||||
// Initialize some test data
|
||||
List<AttributeModifier> modifiers = Lists.newArrayList(
|
||||
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10,
|
||||
AttributeModifier.Operation.a));
|
||||
WrappedAttribute attribute = WrappedAttribute.newBuilder()
|
||||
.attributeKey("generic.max_health")
|
||||
.baseValue(20.0D)
|
||||
.modifiers(Lists.newArrayList(
|
||||
WrappedAttributeModifier.newBuilder()
|
||||
.name("Test")
|
||||
.amount(1.0D)
|
||||
.operation(WrappedAttributeModifier.Operation.ADD_NUMBER)
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
// Obtain an AttributeSnapshot instance. This is complicated by the fact that AttributeSnapshots
|
||||
// are inner classes (which is ultimately pointless because AttributeSnapshots don't access any
|
||||
// members of the packet itself)
|
||||
PacketPlayOutUpdateAttributes packet = (PacketPlayOutUpdateAttributes) attribute.getHandle();
|
||||
IRegistry<AttributeBase> registry = BuiltInRegistries.u;
|
||||
AttributeBase base = registry.a(MinecraftKey.a("generic.max_health"));
|
||||
AttributeSnapshot snapshot = new AttributeSnapshot(Holder.a(base), 20.0D, modifiers);
|
||||
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
|
||||
container.getAttributeCollectionModifier().write(0, List.of(attribute));
|
||||
|
||||
PacketContainer cloned = attribute.deepClone();
|
||||
AttributeSnapshot
|
||||
clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
|
||||
ClientboundUpdateAttributesPacket packet = (ClientboundUpdateAttributesPacket) container.getHandle();
|
||||
|
||||
// Compare the fields, because apparently the packet is a field in AttributeSnapshot
|
||||
for (Field field : AttributeSnapshot.class.getDeclaredFields()) {
|
||||
try {
|
||||
// Skip the packet
|
||||
if (field.getType().equals(packet.getClass())) {
|
||||
continue;
|
||||
}
|
||||
PacketContainer cloned = container.deepClone();
|
||||
ClientboundUpdateAttributesPacket clonedPacket = (ClientboundUpdateAttributesPacket) cloned.getHandle();
|
||||
|
||||
field.setAccessible(true);
|
||||
this.testEquality(field.get(snapshot), field.get(clonedSnapshot));
|
||||
} catch (AssertionError e) {
|
||||
throw e;
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
assertNotSame(packet, clonedPacket);
|
||||
assertNotSame(packet.getValues(), clonedPacket.getValues());
|
||||
|
||||
List<AttributeSnapshot> values = packet.getValues();
|
||||
List<AttributeSnapshot> clonedValues = clonedPacket.getValues();
|
||||
|
||||
assertEquals(values.size(), clonedValues.size());
|
||||
assertNotSame(values.get(0), clonedValues.get(0));
|
||||
|
||||
AttributeSnapshot snapshot = values.get(0);
|
||||
AttributeSnapshot clonedSnapshot = clonedValues.get(0);
|
||||
|
||||
assertEquals(Attributes.MAX_HEALTH, clonedSnapshot.attribute());
|
||||
assertEquals(20.0D, clonedSnapshot.base());
|
||||
|
||||
assertNotSame(snapshot.modifiers(), clonedSnapshot.modifiers());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAttributeList() {
|
||||
AttributeInstance instance = new AttributeInstance(Attributes.MAX_HEALTH, (__) -> {});
|
||||
instance.setBaseValue(20.0D);
|
||||
instance.addTransientModifier(new AttributeModifier(ResourceLocation.parse("protocollib:test"), 1.0,
|
||||
Operation.ADD_VALUE));
|
||||
|
||||
ClientboundUpdateAttributesPacket packet = new ClientboundUpdateAttributesPacket(1234, List.of(instance));
|
||||
PacketContainer container = PacketContainer.fromPacket(packet);
|
||||
|
||||
List<WrappedAttribute> attributes = container.getAttributeCollectionModifier().read(0);
|
||||
WrappedAttribute attribute = attributes.get(0);
|
||||
|
||||
assertEquals("generic.max_health", attribute.getAttributeKey());
|
||||
assertEquals(20.0D, attribute.getBaseValue());
|
||||
|
||||
WrappedAttributeModifier modifier = attribute.getModifiers().iterator().next();
|
||||
assertEquals(1.0D, modifier.getAmount());
|
||||
assertEquals("protocollib:test", modifier.getKey().getFullKey());
|
||||
assertEquals(WrappedAttributeModifier.Operation.ADD_NUMBER, modifier.getOperation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -566,28 +595,30 @@ public class PacketContainerTest {
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testPotionEffect() {
|
||||
PotionEffect effect = new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 20 * 60, 1);
|
||||
MobEffect mobEffect = new MobEffect(MobEffects.l, effect.getDuration(),
|
||||
MobEffectInstance mobEffect = new MobEffectInstance(MobEffects.FIRE_RESISTANCE, effect.getDuration(),
|
||||
effect.getAmplifier(), effect.isAmbient(),
|
||||
effect.hasParticles());
|
||||
int entityId = 42;
|
||||
|
||||
ClientboundUpdateMobEffectPacket packet;
|
||||
|
||||
// The constructor we want to call
|
||||
PacketConstructor creator = PacketConstructor.DEFAULT.withPacket(
|
||||
PacketType.Play.Server.ENTITY_EFFECT, new Class<?>[] { int.class, MobEffect.class, boolean.class });
|
||||
PacketContainer packet = creator.createPacket(entityId, mobEffect, true);
|
||||
PacketType.Play.Server.ENTITY_EFFECT, new Class<?>[] { int.class, MobEffectInstance.class, boolean.class });
|
||||
PacketContainer container = creator.createPacket(entityId, mobEffect, true);
|
||||
|
||||
assertEquals(entityId, packet.getIntegers().read(0));
|
||||
assertEquals(effect.getAmplifier(), packet.getIntegers().read(1));
|
||||
assertEquals(effect.getDuration(), packet.getIntegers().read(2));
|
||||
assertEquals(entityId, container.getIntegers().read(0));
|
||||
assertEquals(effect.getAmplifier(), container.getIntegers().read(1));
|
||||
assertEquals(effect.getDuration(), container.getIntegers().read(2));
|
||||
|
||||
WrappedRegistry registry = WrappedRegistry.getRegistry(MinecraftReflection.getMobEffectListClass());
|
||||
|
||||
Object effectList = assertInstanceOf(
|
||||
MobEffectList.class,
|
||||
packet.getHolders(MobEffectList.class, InternalStructure.CONVERTER).read(0).getHandle()
|
||||
MobEffect effectList = assertInstanceOf(
|
||||
MobEffect.class,
|
||||
container.getHolders(MobEffect.class, InternalStructure.CONVERTER).read(0).getHandle()
|
||||
);
|
||||
|
||||
assertEquals(effect.getType().getId(), registry.getId(effectList) + 1); // +1 is correct, see CraftPotionEffectType
|
||||
assertTrue(effectList.getDescriptionId().contains("fire_resistance"));
|
||||
|
||||
byte b = 0;
|
||||
if (effect.isAmbient()) {
|
||||
@@ -602,7 +633,7 @@ public class PacketContainerTest {
|
||||
|
||||
b |= 8;
|
||||
|
||||
assertEquals(b, (byte) packet.getBytes().read(0));
|
||||
assertEquals(b, (byte) container.getBytes().read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -656,6 +687,8 @@ public class PacketContainerTest {
|
||||
@Disabled // TODO -- need a way to create a structure
|
||||
public void testInternalStructures() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM);
|
||||
container.getModifier().writeDefaults();
|
||||
|
||||
Optional<InternalStructure> optStruct = container.getOptionalStructures().read(0);
|
||||
assertTrue(optStruct.isPresent());
|
||||
InternalStructure struct = optStruct.get();
|
||||
@@ -695,7 +728,7 @@ public class PacketContainerTest {
|
||||
|
||||
@Test
|
||||
public void testMovingBlockPos() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Client.USE_ITEM);
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Client.USE_ITEM_ON);
|
||||
|
||||
Vector vector = new Vector(0, 1, 2);
|
||||
BlockPosition position = new BlockPosition(3, 4, 5);
|
||||
@@ -798,7 +831,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- can't create MAP_CHUNK packet
|
||||
// @Disabled // TODO -- can't create MAP_CHUNK packet
|
||||
public void testMapChunk() {
|
||||
// this is a special case as we are generating a data serializer class (we only need to construct the packet)
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.MAP_CHUNK);
|
||||
@@ -886,17 +919,25 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
Object buffer = MinecraftReflection.createPacketDataSerializer(0);
|
||||
MinecraftMethods.getPacketWriteByteBufMethod().invoke(cloned.getHandle(), buffer);
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(constructed.getType().getPacketClass(), false);
|
||||
FieldAccessor accessor = Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.typeDerivedOf(StreamCodec.class)
|
||||
.build()));
|
||||
StreamCodec codec = (StreamCodec) accessor.get(cloned.getHandle());
|
||||
codec.encode(buffer, cloned.getHandle());
|
||||
}
|
||||
|
||||
private static final Set<PacketType> CLONE_EXPECTED_FAILURES = Set.of();
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- cloning is borked
|
||||
public void testCloning() {
|
||||
// Try constructing all the packets
|
||||
Set<PacketType> failures = new HashSet<>();
|
||||
for (PacketType type : PacketType.values()) {
|
||||
// TODO: try to support chat - for now chat contains to many sub classes to properly clone it
|
||||
if (type.isDeprecated() || !type.isSupported() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("CHAT")
|
||||
|| type.name().contains("BUNDLE")) {
|
||||
if (type.isDeprecated() || !type.isSupported()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -908,22 +949,22 @@ public class PacketContainerTest {
|
||||
|
||||
// Make sure watchable collections can be cloned
|
||||
if (type == PacketType.Play.Server.ENTITY_METADATA) {
|
||||
IRegistry<CatVariant> catVariantRegistry = BuiltInRegistries.ak;
|
||||
Registry<CatVariant> catVariantRegistry = BuiltInRegistries.CAT_VARIANT;
|
||||
constructed.getDataValueCollectionModifier().write(0, Lists.newArrayList(
|
||||
new WrappedDataValue(0, Registry.get(Byte.class), (byte) 1),
|
||||
new WrappedDataValue(0, Registry.get(Float.class), 5F),
|
||||
new WrappedDataValue(0, Registry.get(String.class), "String"),
|
||||
new WrappedDataValue(0, Registry.get(Boolean.class), true),
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 1),
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Float.class), 5F),
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(String.class), "String"),
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Boolean.class), true),
|
||||
new WrappedDataValue(
|
||||
0,
|
||||
Registry.getChatComponentSerializer(true),
|
||||
0,
|
||||
WrappedDataWatcher.Registry.getChatComponentSerializer(true),
|
||||
Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
|
||||
new WrappedDataValue(
|
||||
0,
|
||||
Registry.getItemStackSerializer(false),
|
||||
WrappedDataWatcher.Registry.getItemStackSerializer(false),
|
||||
BukkitConverters.getItemStackConverter().getGeneric(new ItemStack(Material.WOODEN_AXE))),
|
||||
new WrappedDataValue(0, Registry.get(CatVariant.class), catVariantRegistry.e(CatVariant.e)),
|
||||
new WrappedDataValue(0, Registry.get(FrogVariant.class), FrogVariant.a)
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(CatVariant.class), catVariantRegistry.get(CatVariant.ALL_BLACK)),
|
||||
new WrappedDataValue(0, WrappedDataWatcher.Registry.get(FrogVariant.class), FrogVariant.COLD)
|
||||
));
|
||||
} else if (type == PacketType.Play.Server.CHAT || type == PacketType.Login.Server.DISCONNECT) {
|
||||
constructed.getChatComponents().write(0, ComponentConverter.fromBaseComponent(TEST_COMPONENT));
|
||||
@@ -932,7 +973,7 @@ public class PacketContainerTest {
|
||||
} else if (type == PacketType.Play.Server.GAME_STATE_CHANGE) {
|
||||
constructed.getStructures().write(
|
||||
0,
|
||||
InternalStructure.getConverter().getSpecific(PacketPlayOutGameStateChange.a));
|
||||
InternalStructure.getConverter().getSpecific(ClientboundGameEventPacket.ARROW_HIT_PLAYER));
|
||||
} else if (type == PacketType.Play.Client.USE_ITEM || type == PacketType.Play.Client.BLOCK_PLACE) {
|
||||
constructed.getLongs().write(0, 0L); // timestamp of the packet, not sent over the network
|
||||
}
|
||||
@@ -952,10 +993,13 @@ public class PacketContainerTest {
|
||||
serializedCloned.getLongs().write(0, 0L);
|
||||
}
|
||||
this.assertPacketsEqualAndSerializable(constructed, serializedCloned);
|
||||
} catch (Throwable t) {
|
||||
Assertions.fail("Unable to clone " + type, t);
|
||||
} catch (Throwable ex) {
|
||||
failures.add(type);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(CLONE_EXPECTED_FAILURES, failures);
|
||||
}
|
||||
|
||||
// Convert to objects that support equals()
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.minecraft.server.level.ChunkProviderServer;
|
||||
import net.minecraft.server.level.PlayerChunkMap;
|
||||
import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftEntity;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.setFinalField;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
public class EntityUtilitiesTest {
|
||||
|
||||
@@ -28,10 +11,11 @@ public class EntityUtilitiesTest {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testReflection() {
|
||||
CraftWorld bukkit = mock(CraftWorld.class);
|
||||
WorldServer world = mock(WorldServer.class);
|
||||
ServerLevel world = mock(ServerLevel.class);
|
||||
when(bukkit.getHandle()).thenReturn(world);
|
||||
|
||||
ChunkProviderServer provider = mock(ChunkProviderServer.class);
|
||||
@@ -57,4 +41,5 @@ public class EntityUtilitiesTest {
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
|
||||
setFinalField(chunkMap, trackedEntitiesField, trackerMap);
|
||||
}
|
||||
*/
|
||||
}
|
||||
-8
@@ -1,15 +1,7 @@
|
||||
package com.comphenix.protocol.injector.netty.channel;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.local.LocalServerChannel;
|
||||
import net.minecraft.network.EnumProtocol;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ChannelProtocolUtilTest {
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import java.util.List;
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
|
||||
import net.minecraft.network.protocol.game.ServerboundUseItemPacket;
|
||||
import net.minecraft.network.protocol.login.LoginPacketTypes;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.nbt.NBTCompressedStreamTools;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.status.ServerPing;
|
||||
import net.minecraft.network.syncher.DataWatcher;
|
||||
import net.minecraft.server.network.PlayerConnection;
|
||||
import net.minecraft.util.MinecraftEncryption;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
@@ -21,13 +13,9 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class MinecraftReflectionTest {
|
||||
|
||||
@@ -64,6 +52,7 @@ public class MinecraftReflectionTest {
|
||||
assertNull(MinecraftReflection.getNullableNMS("ProtocolLib"));
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testAttributeSnapshot() {
|
||||
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class,
|
||||
@@ -124,7 +113,7 @@ public class MinecraftReflectionTest {
|
||||
public void testLoginSignature() {
|
||||
assertEquals(MinecraftEncryption.b.class, MinecraftReflection.getSaltedSignatureClass());
|
||||
}
|
||||
|
||||
*/
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack stack = new ItemStack(Material.GOLDEN_SWORD);
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.comphenix.protocol.utility;
|
||||
|
||||
public class MinecraftReflectionTestUtil {
|
||||
|
||||
public static final String RELEASE_TARGET = "1.20.6";
|
||||
public static final String PACKAGE_VERSION = "v1_20_R4";
|
||||
public static final String RELEASE_TARGET = "1.21.0";
|
||||
public static final String PACKAGE_VERSION = "v1_21_R1";
|
||||
public static final String NMS = "net.minecraft";
|
||||
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -48,7 +48,7 @@ class MinecraftVersionTest {
|
||||
|
||||
@Test
|
||||
void testCurrent() {
|
||||
assertEquals(MinecraftVersion.v1_20_5, MinecraftVersion.getCurrentVersion());
|
||||
assertEquals(MinecraftVersion.v1_21_0, MinecraftVersion.getCurrentVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -19,6 +18,11 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class StreamSerializerTest {
|
||||
|
||||
@BeforeAll
|
||||
@@ -35,7 +39,10 @@ public class StreamSerializerTest {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
serializer.serializeString(new DataOutputStream(buffer), initial);
|
||||
|
||||
DataInputStream input = new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()));
|
||||
byte[] bytes = buffer.toByteArray();
|
||||
assertTrue(bytes.length >= initial.length());
|
||||
|
||||
DataInputStream input = new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
String deserialized = serializer.deserializeString(input, 50);
|
||||
|
||||
assertEquals(initial, deserialized);
|
||||
@@ -60,7 +67,7 @@ public class StreamSerializerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- replaced with registry friendly bytebuf
|
||||
@Disabled // TODO -- replaced with stream codecs
|
||||
public void testItems() throws IOException {
|
||||
StreamSerializer serializer = new StreamSerializer();
|
||||
ItemStack initial = new ItemStack(Material.STRING);
|
||||
@@ -72,7 +79,7 @@ public class StreamSerializerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- replaced with registry friendly bytebuf
|
||||
@Disabled // TODO -- replaced with stream codecs
|
||||
public void testItemMeta() throws IOException {
|
||||
StreamSerializer serializer = new StreamSerializer();
|
||||
ItemStack initial = new ItemStack(Material.BLUE_WOOL, 2);
|
||||
|
||||
@@ -12,11 +12,6 @@ import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import net.minecraft.advancements.AdvancementDisplay;
|
||||
import net.minecraft.advancements.AdvancementFrameType;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.chat.contents.LiteralContents;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -24,6 +19,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AutoWrapperTest {
|
||||
|
||||
/*
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
@@ -121,5 +117,5 @@ public class AutoWrapperTest {
|
||||
public boolean hidden;
|
||||
public float x;
|
||||
public float y;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.utility.TestUtils;
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -17,8 +20,6 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class BukkitConvertersTest {
|
||||
@@ -29,7 +30,7 @@ public class BukkitConvertersTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- enchantment cannot be applied to this itemstack(???)
|
||||
// @Disabled // TODO -- enchantment cannot be applied to this itemstack(???)
|
||||
public void testItemStacks() {
|
||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
||||
item.addEnchantment(Enchantment.SHARPNESS, 4);
|
||||
|
||||
@@ -15,17 +15,17 @@ public class ChunkCoordIntPairTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2);
|
||||
net.minecraft.world.level.ChunkPos pair = new net.minecraft.world.level.ChunkPos(1, 2);
|
||||
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
|
||||
|
||||
assertEquals(1, specific.getChunkX());
|
||||
assertEquals(2, specific.getChunkZ());
|
||||
|
||||
net.minecraft.world.level.ChunkCoordIntPair roundtrip =
|
||||
(net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
|
||||
net.minecraft.world.level.ChunkPos roundtrip =
|
||||
(net.minecraft.world.level.ChunkPos) ChunkCoordIntPair.getConverter().
|
||||
getGeneric(specific);
|
||||
|
||||
assertEquals(1, roundtrip.e);
|
||||
assertEquals(2, roundtrip.f);
|
||||
assertEquals(1, roundtrip.x);
|
||||
assertEquals(2, roundtrip.z);
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@ public class EnumWrappersTest {
|
||||
public void validateAllEnumFieldsAreWrapped() {
|
||||
Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap();
|
||||
for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) {
|
||||
for (Object nativeConstant : entry.getKey().getEnumConstants()) {
|
||||
try {
|
||||
try {
|
||||
for (Object nativeConstant : entry.getKey().getEnumConstants()) {
|
||||
// yay, generics
|
||||
EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue();
|
||||
|
||||
@@ -44,16 +44,15 @@ public class EnumWrappersTest {
|
||||
assertNotNull(unwrappedValue);
|
||||
|
||||
assertEquals(nativeConstant, unwrappedValue);
|
||||
} catch (Exception ex) {
|
||||
fail(ex);
|
||||
// ex.printStackTrace();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
fail(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidity() {
|
||||
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID);
|
||||
assertEquals(KNOWN_INVALID, EnumWrappers.INVALID);
|
||||
}
|
||||
}
|
||||
@@ -2,27 +2,27 @@ package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.cloning.BukkitCloner;
|
||||
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.resources.MinecraftKey;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
||||
import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket.AttributeSnapshot;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class WrappedAttributeTest {
|
||||
|
||||
@@ -37,27 +37,94 @@ public class WrappedAttributeTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Create a couple of modifiers
|
||||
this.doubleModifier =
|
||||
WrappedAttributeModifier.newBuilder().
|
||||
name("Double Damage").
|
||||
amount(1).
|
||||
operation(Operation.ADD_PERCENTAGE).
|
||||
build();
|
||||
this.constantModifier =
|
||||
WrappedAttributeModifier.newBuilder().
|
||||
name("Damage Bonus").
|
||||
amount(5).
|
||||
operation(Operation.ADD_NUMBER).
|
||||
build();
|
||||
this.doubleModifier = WrappedAttributeModifier.newBuilder()
|
||||
.key("protocollib", "double_damage")
|
||||
.amount(1.0D)
|
||||
.operation(Operation.ADD_PERCENTAGE)
|
||||
.build();
|
||||
|
||||
// Create attribute
|
||||
this.attribute = WrappedAttribute.newBuilder().
|
||||
attributeKey("generic.attackDamage").
|
||||
baseValue(2).
|
||||
packet(new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES)).
|
||||
modifiers(Lists.newArrayList(this.constantModifier, this.doubleModifier)).
|
||||
build();
|
||||
this.constantModifier = WrappedAttributeModifier.newBuilder()
|
||||
.key("protocollib", "damage_bonus")
|
||||
.amount(5.0D)
|
||||
.operation(Operation.ADD_NUMBER)
|
||||
.build();
|
||||
|
||||
this.attribute = WrappedAttribute.newBuilder()
|
||||
.attributeKey("generic.attackDamage")
|
||||
.baseValue(2.0D)
|
||||
.modifiers(Lists.newArrayList(this.constantModifier, this.doubleModifier))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateHandle() {
|
||||
WrappedAttribute wrapper = WrappedAttribute.newBuilder()
|
||||
.baseValue(2.0)
|
||||
.attributeKey("generic.attackDamage")
|
||||
.modifiers(List.of(constantModifier, doubleModifier))
|
||||
.build();
|
||||
|
||||
AttributeSnapshot handle = (AttributeSnapshot) wrapper.getHandle();
|
||||
assertNotNull(handle);
|
||||
assertEquals(2.0D, handle.base());
|
||||
|
||||
Attribute attribute = handle.attribute().value();
|
||||
assertEquals("attribute.name.generic.attack_damage", attribute.getDescriptionId());
|
||||
|
||||
Map<ResourceLocation, AttributeModifier> modifiers = handle.modifiers().stream().collect(Collectors.toMap(m -> m.id(), m -> m));
|
||||
AttributeModifier modifier1 = modifiers.get(ResourceLocation.parse("protocollib:double_damage"));
|
||||
AttributeModifier modifier2 = modifiers.get(ResourceLocation.parse("protocollib:damage_bonus"));
|
||||
|
||||
assertEquals(1.0D, modifier1.amount());
|
||||
assertEquals(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL, modifier1.operation());
|
||||
|
||||
assertEquals(5.0D, modifier2.amount());
|
||||
assertEquals(AttributeModifier.Operation.ADD_VALUE, modifier2.operation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromHandle() {
|
||||
AttributeSnapshot handle = new AttributeSnapshot(
|
||||
Attributes.ATTACK_SPEED,
|
||||
5.0D,
|
||||
List.of(new AttributeModifier(ResourceLocation.parse("protocollib:test"),
|
||||
1.0D, AttributeModifier.Operation.ADD_VALUE))
|
||||
);
|
||||
WrappedAttribute wrapper = WrappedAttribute.fromHandle(handle);
|
||||
assertEquals("generic.attack_speed", wrapper.getAttributeKey());
|
||||
assertEquals(5.0D, wrapper.getBaseValue());
|
||||
WrappedAttributeModifier modifier = wrapper.getModifiers().iterator().next();
|
||||
assertEquals(1.0D, modifier.getAmount());
|
||||
assertEquals("protocollib:test", modifier.getKey().getFullKey());
|
||||
assertEquals(Operation.ADD_NUMBER, modifier.getOperation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloning() {
|
||||
AttributeModifier modifier = new AttributeModifier(
|
||||
ResourceLocation.parse("protocollib:test"),
|
||||
1.0D,
|
||||
AttributeModifier.Operation.ADD_VALUE
|
||||
);
|
||||
|
||||
AttributeSnapshot handle = new AttributeSnapshot(
|
||||
Attributes.ATTACK_SPEED,
|
||||
5.0D,
|
||||
List.of(modifier)
|
||||
);
|
||||
|
||||
AttributeSnapshot clone = (AttributeSnapshot) new BukkitCloner().clone(handle);
|
||||
assertNotSame(handle, clone);
|
||||
|
||||
assertEquals(handle.base(), clone.base());
|
||||
assertEquals(handle.attribute(), clone.attribute());
|
||||
|
||||
assertNotSame(handle.modifiers(), clone.modifiers());
|
||||
|
||||
assertEquals(1, clone.modifiers().size());
|
||||
|
||||
AttributeModifier cloneModifier = clone.modifiers().iterator().next();
|
||||
assertSame(modifier, cloneModifier);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -71,7 +138,6 @@ public class WrappedAttributeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO -- modifiers are missing (or the hasModifier check is wrong)
|
||||
public void testAttribute() {
|
||||
assertEquals(this.attribute, WrappedAttribute.fromHandle(this.getAttributeCopy(this.attribute)));
|
||||
|
||||
@@ -97,16 +163,17 @@ public class WrappedAttributeTest {
|
||||
modifiers.add((AttributeModifier) wrapper.getHandle());
|
||||
}
|
||||
|
||||
IRegistry<AttributeBase> registry = BuiltInRegistries.u;
|
||||
Registry<Attribute> registry = BuiltInRegistries.ATTRIBUTE;
|
||||
String attributeKey = attribute.getAttributeKey();
|
||||
MinecraftKey key = MinecraftKey.a(attributeKey);
|
||||
AttributeBase base = registry.a(key);
|
||||
Holder<AttributeBase> holder = registry.e(base);
|
||||
ResourceLocation key = ResourceLocation.tryParse(attributeKey);
|
||||
Attribute base = registry.get(key);
|
||||
Holder<Attribute> holder = registry.wrapAsHolder(base);
|
||||
return new AttributeSnapshot(holder, attribute.getBaseValue(), modifiers);
|
||||
}
|
||||
|
||||
private AttributeModifier getModifierCopy(WrappedAttributeModifier modifier) {
|
||||
AttributeModifier.Operation operation = AttributeModifier.Operation.values()[modifier.getOperation().getId()];
|
||||
return new AttributeModifier(modifier.getUUID(), modifier.getName(), modifier.getAmount(), operation);
|
||||
return new AttributeModifier(ResourceLocation.parse(modifier.getKey().getFullKey()),
|
||||
modifier.getAmount(), operation);
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,14 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.type.GlassPane;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.block.impl.CraftStainedGlassPane;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.util.CraftMagicNumbers;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.block.impl.CraftStainedGlassPane;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.util.CraftMagicNumbers;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -56,14 +57,14 @@ public class WrappedBlockDataTest {
|
||||
|
||||
@Test
|
||||
public void testDataCreation() {
|
||||
IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).o();
|
||||
BlockState nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).defaultBlockState();
|
||||
GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData);
|
||||
data.setFace(BlockFace.EAST, true);
|
||||
|
||||
WrappedBlockData wrapper = WrappedBlockData.createData(data);
|
||||
assertEquals(wrapper.getType(), Material.CYAN_STAINED_GLASS_PANE);
|
||||
|
||||
GlassPane back = new CraftStainedGlassPane((IBlockData) wrapper.getHandle());
|
||||
GlassPane back = new CraftStainedGlassPane((BlockState) wrapper.getHandle());
|
||||
assertEquals(back.hasFace(BlockFace.EAST), data.hasFace(BlockFace.EAST));
|
||||
assertEquals(back.hasFace(BlockFace.SOUTH), data.hasFace(BlockFace.SOUTH));
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.minecraft.EnumChatFormat;
|
||||
import net.minecraft.network.chat.ChatModifier;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class WrappedComponentStyleTest {
|
||||
|
||||
@Test
|
||||
public void testComponentStyle() {
|
||||
ChatModifier style = ChatModifier.a.b(EnumChatFormat.m).a(true);
|
||||
Object style = net.minecraft.network.chat.Style.EMPTY.applyFormat(ChatFormatting.RED).withBold(true);
|
||||
WrappedComponentStyle wrapped = new WrappedComponentStyle(style);
|
||||
JsonElement json = wrapped.getJson();
|
||||
assertEquals("{\"color\":\"red\",\"bold\":true}", json.toString());
|
||||
|
||||
@@ -14,16 +14,23 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
import net.minecraft.world.entity.projectile.EntityEgg;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftEgg;
|
||||
import net.minecraft.world.entity.projectile.ThrownEgg;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftEgg;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -39,12 +46,12 @@ public class WrappedDataWatcherTest {
|
||||
public static void prepare() {
|
||||
BukkitInitialization.initializeAll();
|
||||
|
||||
EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0);
|
||||
ThrownEgg nmsEgg = new ThrownEgg(null, 0, 0, 0);
|
||||
mockEntity = new CraftEgg(null, nmsEgg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBytes() {
|
||||
public void testFromEntity() {
|
||||
WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(mockEntity);
|
||||
|
||||
WrappedWatchableObject watchable = watcher.getWatchableObject(0);
|
||||
@@ -54,49 +61,160 @@ public class WrappedDataWatcherTest {
|
||||
assertEquals(object.getSerializer(), Registry.get(Byte.class));
|
||||
|
||||
// Make sure we can set existing objects
|
||||
watcher.setObject(0, (byte) 21);
|
||||
assertEquals(21, (byte) watcher.getByte(0));
|
||||
watcher.setByte(0, (byte) 21, false);
|
||||
assertEquals((byte) 21, watcher.getByte(0));
|
||||
|
||||
assertTrue(watcher.hasIndex(1));
|
||||
assertFalse(watcher.hasIndex(9999));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimitives() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
|
||||
watcher.setByte(0, (byte) 21, false);
|
||||
assertEquals((byte) 21, watcher.getByte(0));
|
||||
|
||||
watcher.setInteger(1, 37, false);
|
||||
assertEquals(37, watcher.getInteger(1));
|
||||
|
||||
watcher.setFloat(2, 42.1F, false);
|
||||
assertEquals(42.1F, watcher.getFloat(2));
|
||||
|
||||
watcher.setLong(3, 69L, false);
|
||||
assertEquals(69L, watcher.getLong(3));
|
||||
|
||||
watcher.setBoolean(4, true, false);
|
||||
assertTrue(watcher.getBoolean(4));
|
||||
|
||||
assertTrue(watcher.hasIndex(4));
|
||||
assertFalse(watcher.hasIndex(5));
|
||||
assertEquals(5, watcher.size());
|
||||
|
||||
List<WrappedDataValue> dataValues = watcher.toDataValueCollection();
|
||||
assertEquals(5, dataValues.size());
|
||||
|
||||
assertEquals((byte) 21, dataValues.get(0).getValue());
|
||||
assertEquals((byte) 21, dataValues.get(0).getRawValue());
|
||||
|
||||
assertEquals(37, dataValues.get(1).getValue());
|
||||
assertEquals(37, dataValues.get(1).getRawValue());
|
||||
|
||||
assertEquals(42.1F, dataValues.get(2).getValue());
|
||||
assertEquals(42.1F, dataValues.get(2).getRawValue());
|
||||
|
||||
assertEquals(69L, dataValues.get(3).getValue());
|
||||
assertEquals(69L, dataValues.get(3).getRawValue());
|
||||
|
||||
assertEquals(true, dataValues.get(4).getValue());
|
||||
assertEquals(true, dataValues.get(4).getRawValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrings() {
|
||||
WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(mockEntity);
|
||||
|
||||
// Make sure we can create watcher objects
|
||||
Serializer serializer = Registry.get(String.class);
|
||||
WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer);
|
||||
watcher.setObject(object, "Test");
|
||||
watcher.setString(0, "Test", false);
|
||||
|
||||
assertEquals(watcher.getString(3), "Test");
|
||||
assertEquals("Test", watcher.getString(0));
|
||||
|
||||
WrappedDataValue wdv = watcher.toDataValueCollection().get(0);
|
||||
assertEquals("Test", wdv.getValue());
|
||||
assertEquals("Test", wdv.getRawValue());
|
||||
|
||||
assertEquals(0, wdv.getIndex());
|
||||
assertNotNull(wdv.getSerializer());
|
||||
assertFalse(wdv.getSerializer().isOptional());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloats() {
|
||||
public void testChatComponent() {
|
||||
WrappedDataWatcher wrapper = new WrappedDataWatcher();
|
||||
wrapper.setChatComponent(0, WrappedChatComponent.fromText("Test"), false);
|
||||
wrapper.setOptionalChatComponent(1, Optional.of(WrappedChatComponent.fromText("Test")), false);
|
||||
|
||||
// Make sure we can add new entries
|
||||
Serializer serializer = Registry.get(Float.class);
|
||||
WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer);
|
||||
wrapper.setObject(object, 21.0F);
|
||||
WrappedChatComponent expected = WrappedChatComponent.fromText("Test");
|
||||
assertEquals(expected, wrapper.getChatComponent(0));
|
||||
assertTrue(wrapper.getOptionalChatComponent(1).isPresent());
|
||||
assertEquals(expected, wrapper.getOptionalChatComponent(1).get());
|
||||
|
||||
assertTrue(wrapper.hasIndex(10));
|
||||
List<WrappedDataValue> wdvs = wrapper.toDataValueCollection();
|
||||
WrappedDataValue wdv1 = wdvs.get(0);
|
||||
assertEquals(expected, wdv1.getValue());
|
||||
|
||||
WrappedDataValue wdv2 = wdvs.get(1);
|
||||
assertEquals(expected, ((Optional) wdv2.getValue()).get());
|
||||
|
||||
assertEquals("literal{Test}", wdv1.getRawValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializers() {
|
||||
Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false);
|
||||
Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true);
|
||||
assertNotSame(blockPos, optionalBlockPos);
|
||||
public void testItemStacks() {
|
||||
WrappedDataWatcher wrapper = new WrappedDataWatcher();
|
||||
wrapper.setItemStack(0, new ItemStack(Material.ACACIA_FENCE), false);
|
||||
assertEquals(Material.ACACIA_FENCE, wrapper.getItemStack(0).getType());
|
||||
|
||||
// assertNull(Registry.get(ItemStack.class, false)); // TODO
|
||||
assertNotNull(Registry.get(UUID.class, true));
|
||||
assertEquals(MinecraftReflection.getItemStackClass(),
|
||||
wrapper.getWatchableObject(0).getRawValue().getClass());
|
||||
|
||||
WrappedDataValue wdv = wrapper.toDataValueCollection().get(0);
|
||||
assertEquals(Material.ACACIA_FENCE, ((ItemStack) wdv.getValue()).getType());
|
||||
|
||||
Object raw = wdv.getRawValue();
|
||||
assertEquals(MinecraftReflection.getItemStackClass(), raw.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasIndex() {
|
||||
WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(mockEntity);
|
||||
assertTrue(watcher.hasIndex(1));
|
||||
assertFalse(watcher.hasIndex(9999));
|
||||
public void testMinecraftObjects() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
|
||||
watcher.setPosition(0, new BlockPosition(1, 2, 3), false);
|
||||
assertEquals(new BlockPosition(1, 2, 3), watcher.getPosition(0));
|
||||
|
||||
watcher.setOptionalPosition(1, Optional.of(new BlockPosition(4, 5, 6)), false);
|
||||
assertEquals(Optional.of(new BlockPosition(4, 5, 6)), watcher.getOptionalPosition(1));
|
||||
|
||||
watcher.setDirection(2, EnumWrappers.Direction.EAST, false);
|
||||
assertEquals(EnumWrappers.Direction.EAST, watcher.getDirection(2));
|
||||
|
||||
watcher.setBlockState(3, WrappedBlockData.createData(Material.ACACIA_FENCE), false);
|
||||
assertEquals(Material.ACACIA_FENCE, watcher.getBlockState(3).getType());
|
||||
|
||||
watcher.setOptionalBlockState(4, Optional.of(WrappedBlockData.createData(Material.ACACIA_FENCE)), false);
|
||||
assertEquals(Optional.of(WrappedBlockData.createData(Material.ACACIA_FENCE)), watcher.getOptionalBlockState(4));
|
||||
|
||||
watcher.setParticle(5, WrappedParticle.create(Particle.CAMPFIRE_COSY_SMOKE, null), false);
|
||||
assertEquals(Particle.CAMPFIRE_COSY_SMOKE, watcher.getParticle(5).getParticle());
|
||||
|
||||
watcher.setParticle(6, WrappedParticle.create(Particle.BLOCK, WrappedBlockData.createData(Material.AZALEA)), false);
|
||||
assertEquals(Material.AZALEA, ((WrappedParticle<WrappedBlockData>) watcher.getParticle(6)).getData().getType());
|
||||
|
||||
assertEquals(7, watcher.size());
|
||||
|
||||
List<WrappedDataValue> wdvs = watcher.toDataValueCollection();
|
||||
assertEquals(7, wdvs.size());
|
||||
|
||||
assertEquals(new BlockPosition(1, 2, 3), wdvs.get(0).getValue());
|
||||
assertEquals(Optional.of(new BlockPosition(4, 5, 6)), wdvs.get(1).getValue());
|
||||
assertEquals(EnumWrappers.Direction.EAST, wdvs.get(2).getValue());
|
||||
assertEquals(Material.ACACIA_FENCE, ((WrappedBlockData) wdvs.get(3).getValue()).getType());
|
||||
assertEquals(Particle.CAMPFIRE_COSY_SMOKE, ((WrappedParticle) wdvs.get(5).getValue()).getParticle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNBT() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
|
||||
NbtBase<Integer> nbt = NbtFactory.of("testTag", 17);
|
||||
NbtCompound compound = NbtFactory.ofCompound("testCompound", List.of(nbt));
|
||||
watcher.setNBTCompound(0, compound, false);
|
||||
|
||||
NbtCompound roundTrip = watcher.getNBTCompound(0);
|
||||
assertEquals(17, roundTrip.getInteger("testTag"));
|
||||
|
||||
List<WrappedDataValue> wdvs = watcher.toDataValueCollection();
|
||||
Object rawValue = wdvs.get(0).getRawValue();
|
||||
assertEquals(MinecraftReflection.getNBTCompoundClass(), rawValue.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,6 +223,10 @@ public class WrappedDataWatcherTest {
|
||||
WrappedDataWatcher cloned = watcher.deepClone();
|
||||
|
||||
assertEquals(watcher.size(), cloned.size());
|
||||
assertEquals(watcher.getObject(1), cloned.getObject(1));
|
||||
|
||||
int size = watcher.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
assertEquals(watcher.getObject(i), cloned.getObject(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
/**
|
||||
* @author Etrayed
|
||||
*/
|
||||
@Disabled // todo: figure this registry update out
|
||||
// @Disabled // todo: figure this registry update out
|
||||
public class WrappedLevelChunkDataTest {
|
||||
|
||||
@BeforeAll
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.EnumChatFormat;
|
||||
import net.minecraft.network.chat.ChatModifier;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.chat.numbers.BlankFormat;
|
||||
import net.minecraft.network.chat.numbers.FixedFormat;
|
||||
import net.minecraft.network.chat.numbers.StyledFormat;
|
||||
@@ -22,13 +23,13 @@ public class WrappedNumberFormatTest {
|
||||
|
||||
@Test
|
||||
void testBlankFormat() {
|
||||
assertInstanceOf(WrappedNumberFormat.Blank.class, WrappedNumberFormat.fromHandle(BlankFormat.a));
|
||||
assertEquals(BlankFormat.a, WrappedNumberFormat.blank().getHandle());
|
||||
assertInstanceOf(WrappedNumberFormat.Blank.class, WrappedNumberFormat.fromHandle(BlankFormat.INSTANCE));
|
||||
assertEquals(BlankFormat.INSTANCE, WrappedNumberFormat.blank().getHandle());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFixedFormat() {
|
||||
IChatBaseComponent content = IChatBaseComponent.a("Fixed");
|
||||
Component content = Component.literal("Fixed");
|
||||
WrappedNumberFormat wrappedHandle = WrappedNumberFormat.fromHandle(new FixedFormat(content));
|
||||
assertInstanceOf(WrappedNumberFormat.Fixed.class, wrappedHandle);
|
||||
assertEquals(content, ((WrappedNumberFormat.Fixed) wrappedHandle).getContent().getHandle());
|
||||
@@ -39,7 +40,8 @@ public class WrappedNumberFormatTest {
|
||||
|
||||
@Test
|
||||
void testStyledFormat() {
|
||||
ChatModifier style = ChatModifier.a.b(EnumChatFormat.g);
|
||||
Style style = Style.EMPTY.applyFormat(ChatFormatting.AQUA);
|
||||
// ChatModifier style = ChatModifier.a.b(EnumChatFormat.g);
|
||||
WrappedNumberFormat wrappedHandle = WrappedNumberFormat.fromHandle(new StyledFormat(style));
|
||||
assertInstanceOf(WrappedNumberFormat.Styled.class, wrappedHandle);
|
||||
assertEquals(style, ((WrappedNumberFormat.Styled) wrappedHandle).getStyle().getHandle());
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WrappedProfilePublicKeyTest {
|
||||
|
||||
/*
|
||||
private static KeyPair generateKeyPair() throws Exception {
|
||||
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
|
||||
generator.initialize(2048);
|
||||
@@ -79,5 +80,5 @@ public class WrappedProfilePublicKeyTest {
|
||||
assertEquals(keyData.getKey(), wrappedKeyData.getKey());
|
||||
assertEquals(keyData.getExpireTime(), wrappedKeyData.getExpireTime());
|
||||
assertArrayEquals(keyData.getSignature(), wrappedKeyData.getSignature());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import net.minecraft.util.MinecraftEncryption;
|
||||
import net.minecraft.util.Crypt;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -28,11 +28,11 @@ class WrappedSaltedSignatureTest {
|
||||
WrappedSaltedSignature loginSignature = new WrappedSaltedSignature(salt, signature);
|
||||
|
||||
Object handle = loginSignature.getHandle();
|
||||
MinecraftEncryption.b data = assertInstanceOf(MinecraftEncryption.b.class, handle);
|
||||
Crypt.SaltSignaturePair data = assertInstanceOf(Crypt.SaltSignaturePair.class, handle);
|
||||
|
||||
assertTrue(data.a());
|
||||
assertArrayEquals(signature, data.d());
|
||||
assertEquals(salt, data.c());
|
||||
assertTrue(data.isValid());
|
||||
assertArrayEquals(signature, data.signature());
|
||||
assertEquals(salt, data.salt());
|
||||
|
||||
// test key data unwrapping
|
||||
WrappedSaltedSignature unwrapped = BukkitConverters.getWrappedSignatureConverter().getSpecific(data);
|
||||
@@ -44,14 +44,15 @@ class WrappedSaltedSignatureTest {
|
||||
|
||||
// test key data wrapping
|
||||
Object wrappedData = BukkitConverters.getWrappedSignatureConverter().getGeneric(loginSignature);
|
||||
MinecraftEncryption.b wrapped = assertInstanceOf(MinecraftEncryption.b.class, wrappedData);
|
||||
Crypt.SaltSignaturePair wrapped = assertInstanceOf(Crypt.SaltSignaturePair.class, wrappedData);
|
||||
|
||||
assertTrue(wrapped.a());
|
||||
assertEquals(loginSignature.getSalt(), wrapped.c());
|
||||
assertArrayEquals(loginSignature.getSignature(), wrapped.d());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), wrapped.b());
|
||||
assertTrue(wrapped.isValid());
|
||||
assertEquals(loginSignature.getSalt(), wrapped.salt());
|
||||
assertArrayEquals(loginSignature.getSignature(), wrapped.signature());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), wrapped.saltAsBytes());
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
void testSignedMessageWithoutSignature() {
|
||||
long salt = ThreadLocalRandom.current().nextLong();
|
||||
@@ -83,5 +84,5 @@ class WrappedSaltedSignatureTest {
|
||||
assertEquals(loginSignature.getSalt(), wrapped.c());
|
||||
assertArrayEquals(loginSignature.getSignature(), wrapped.d());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), wrapped.b());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
|
||||
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
|
||||
|
||||
import com.google.common.io.Resources;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||
|
||||
@@ -25,21 +24,13 @@ public class WrappedServerPingTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO MotD is null
|
||||
public void fullTest() throws IOException {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Status.Server.SERVER_INFO);
|
||||
Optional<WrappedServerPing> optionalPing = packet.getServerPings().optionRead(0);
|
||||
assertTrue(optionalPing.isPresent());
|
||||
|
||||
WrappedServerPing serverPing = optionalPing.get();
|
||||
assertNotNull(serverPing.getMotD());
|
||||
assertNotNull(serverPing.getFavicon());
|
||||
assertNotNull(serverPing.getPlayers());
|
||||
assertNotNull(serverPing.getVersionName());
|
||||
|
||||
CompressedImage tux = CompressedImage.fromPng(Resources.getResource("tux.png").openStream());
|
||||
byte[] original = tux.getDataCopy();
|
||||
|
||||
WrappedServerPing serverPing = new WrappedServerPing();
|
||||
serverPing.setMotD("Hello, this is a test.");
|
||||
serverPing.setPlayersOnline(5);
|
||||
serverPing.setPlayersMaximum(10);
|
||||
|
||||
@@ -3,15 +3,15 @@ package com.comphenix.protocol.wrappers;
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.PacketDataSerializer;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutOpenBook;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
|
||||
import net.minecraft.world.EnumHand;
|
||||
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundOpenBookPacket;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -26,29 +26,29 @@ public class WrappedStreamCodecTests {
|
||||
|
||||
@Test
|
||||
public void testWithItemStack() {
|
||||
StreamCodec<RegistryFriendlyByteBuf, PacketPlayOutSetSlot> nmsCodec = PacketPlayOutSetSlot.a;
|
||||
StreamCodec<RegistryFriendlyByteBuf, ClientboundContainerSetSlotPacket> nmsCodec = ClientboundContainerSetSlotPacket.STREAM_CODEC;
|
||||
WrappedStreamCodec codec = new WrappedStreamCodec(nmsCodec);
|
||||
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), CraftRegistry.getMinecraftRegistry());
|
||||
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(1, 2, 3, CraftItemStack.asNMSCopy(new ItemStack(Material.GOLDEN_SHOVEL)));
|
||||
ClientboundContainerSetSlotPacket packet = new ClientboundContainerSetSlotPacket(1, 2, 3, CraftItemStack.asNMSCopy(new ItemStack(Material.GOLDEN_SHOVEL)));
|
||||
|
||||
codec.encode(buf, packet);
|
||||
PacketPlayOutSetSlot roundTrip = (PacketPlayOutSetSlot) codec.decode(buf);
|
||||
ClientboundContainerSetSlotPacket roundTrip = (ClientboundContainerSetSlotPacket) codec.decode(buf);
|
||||
|
||||
assertEquals(Material.GOLDEN_SHOVEL, CraftItemStack.asBukkitCopy(roundTrip.f()).getType());
|
||||
assertEquals(Material.GOLDEN_SHOVEL, CraftItemStack.asBukkitCopy(roundTrip.getItem()).getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithStandardSerializer() {
|
||||
StreamCodec<PacketDataSerializer, PacketPlayOutOpenBook> nmsCodec = PacketPlayOutOpenBook.a;
|
||||
StreamCodec<FriendlyByteBuf, ClientboundOpenBookPacket> nmsCodec = ClientboundOpenBookPacket.STREAM_CODEC;
|
||||
WrappedStreamCodec codec = new WrappedStreamCodec(nmsCodec);
|
||||
|
||||
PacketDataSerializer buf = new PacketDataSerializer(Unpooled.buffer());
|
||||
PacketPlayOutOpenBook packet = new PacketPlayOutOpenBook(EnumHand.a);
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
ClientboundOpenBookPacket packet = new ClientboundOpenBookPacket(InteractionHand.OFF_HAND);
|
||||
|
||||
codec.encode(buf, packet);
|
||||
PacketPlayOutOpenBook roundTrip = (PacketPlayOutOpenBook) codec.decode(buf);
|
||||
ClientboundOpenBookPacket roundTrip = (ClientboundOpenBookPacket) codec.decode(buf);
|
||||
|
||||
assertEquals(EnumHand.a, roundTrip.b());
|
||||
assertEquals(InteractionHand.OFF_HAND, roundTrip.getHand());
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.EnumChatFormat;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -17,9 +18,9 @@ public class WrappedTeamParametersTest {
|
||||
|
||||
@Test
|
||||
void testTeamParameters() {
|
||||
IChatBaseComponent displayName = IChatBaseComponent.b("display name");
|
||||
IChatBaseComponent prefix = IChatBaseComponent.b("prefix");
|
||||
IChatBaseComponent suffix = IChatBaseComponent.b("suffix");
|
||||
Component displayName = Component.literal("display name");
|
||||
Component prefix = Component.literal("prefix");
|
||||
Component suffix = Component.literal("suffix");
|
||||
String nametagVisibility = "always";
|
||||
String collisionRule = "never";
|
||||
|
||||
@@ -41,13 +42,13 @@ public class WrappedTeamParametersTest {
|
||||
assertEquals(EnumWrappers.ChatFormatting.RED, wrapped.getColor());
|
||||
assertEquals(1, wrapped.getOptions());
|
||||
|
||||
PacketPlayOutScoreboardTeam.b handle = (PacketPlayOutScoreboardTeam.b) wrapped.getHandle();
|
||||
assertEquals(handle.a(), displayName);
|
||||
assertEquals(handle.f(), prefix);
|
||||
assertEquals(handle.g(), suffix);
|
||||
assertEquals(handle.d(), nametagVisibility);
|
||||
assertEquals(handle.e(), collisionRule);
|
||||
assertEquals(handle.c(), EnumChatFormat.m);
|
||||
assertEquals(handle.b(), 1);
|
||||
ClientboundSetPlayerTeamPacket.Parameters handle = (ClientboundSetPlayerTeamPacket.Parameters) wrapped.getHandle();
|
||||
assertEquals(handle.getDisplayName(), displayName);
|
||||
assertEquals(handle.getPlayerPrefix(), prefix);
|
||||
assertEquals(handle.getPlayerSuffix(), suffix);
|
||||
assertEquals(handle.getNametagVisibility(), nametagVisibility);
|
||||
assertEquals(handle.getCollisionRule(), collisionRule);
|
||||
assertEquals(handle.getColor(), ChatFormatting.RED);
|
||||
assertEquals(handle.getOptions(), 1);
|
||||
}
|
||||
}
|
||||
@@ -17,23 +17,25 @@
|
||||
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class NbtFactoryTest {
|
||||
|
||||
@BeforeAll
|
||||
@@ -64,9 +66,9 @@ public class NbtFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO
|
||||
@Disabled // TODO -- item stacks don't have tags anymore
|
||||
public void testItemTag() {
|
||||
ItemStack test = new ItemStack(Items.L);
|
||||
ItemStack test = new ItemStack(Items.ACACIA_DOOR);
|
||||
org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
|
||||
|
||||
NbtCompound compound = NbtFactory.ofCompound("tag");
|
||||
|
||||
Reference in new issue
Block a user