Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
456430f055 | ||
|
|
71af32aa68 | ||
|
|
24204e7515 | ||
|
|
098b3957c0 | ||
|
|
99f480765c | ||
|
|
327a17ba50 | ||
|
|
3991ad0e8d | ||
|
|
1ca55a3c83 | ||
|
|
76991b85c3 | ||
|
|
b6f74a8adb | ||
|
|
952aabe7b0 | ||
|
|
01d77b7d0e |
No files matched your search
@@ -10,6 +10,8 @@ Critically, different plugins that use this approach may _hook_ into the same cl
|
||||
with unpredictable outcomes. More than often this causes plugins to crash, but it may also
|
||||
lead to more subtle bugs.
|
||||
|
||||
Currently maintained by dmulloy2 on behalf of [Spigot](https://www.spigotmc.org/).
|
||||
|
||||
### Resources
|
||||
|
||||
* [Resource Page](https://www.spigotmc.org/resources/protocollib.1997/)
|
||||
@@ -53,7 +55,7 @@ You can also add ProtocolLib as a Maven dependency:
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -67,7 +69,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'com.comphenix.protocol:ProtocolLib:5.0.0'
|
||||
compileOnly 'com.comphenix.protocol:ProtocolLib:5.0.0-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.comphenix.tinyprotocol;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -179,31 +177,6 @@ public final class Reflection {
|
||||
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field with a given type and parameters. This is most useful
|
||||
* when dealing with Collections.
|
||||
*
|
||||
* @param target the target class.
|
||||
* @param fieldType Type of the field
|
||||
* @param params Variable length array of type parameters
|
||||
* @return The field
|
||||
*
|
||||
* @throws IllegalArgumentException If the field cannot be found
|
||||
*/
|
||||
public static Field getParameterizedField(Class<?> target, Class<?> fieldType, Class<?>... params) {
|
||||
for (Field field : target.getDeclaredFields()) {
|
||||
if (field.getType().equals(fieldType)) {
|
||||
Type type = field.getGenericType();
|
||||
if (type instanceof ParameterizedType) {
|
||||
if (Arrays.equals(((ParameterizedType) type).getActualTypeArguments(), params))
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unable to find a field with type " + fieldType + " and params " + Arrays.toString(params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first publicly and privately defined method of the given name and parameter count.
|
||||
*
|
||||
@@ -328,23 +301,6 @@ public final class Reflection {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class from its full name with alternatives, without knowing its type on compile time.
|
||||
* <p>
|
||||
* This is useful when looking up fields by a NMS or OBC type.
|
||||
* <p>
|
||||
*
|
||||
* @see {@link #getClass()} for more information.
|
||||
* @param lookupName - the class name with variables.
|
||||
* @param aliases - alternative names for this class.
|
||||
* @return The class.
|
||||
*/
|
||||
public static Class<Object> getUntypedClass(String lookupName, String... aliases) {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
Class<Object> clazz = (Class) getClass(lookupName, aliases);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class from its full name.
|
||||
* <p>
|
||||
@@ -377,61 +333,6 @@ public final class Reflection {
|
||||
return getCanonicalClass(expandVariables(lookupName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first class that matches the full class name.
|
||||
* <p>
|
||||
* Strings enclosed with curly brackets - such as {TEXT} - will be replaced according to the following table:
|
||||
* <p>
|
||||
* <table border="1">
|
||||
* <tr>
|
||||
* <th>Variable</th>
|
||||
* <th>Content</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{nms}</td>
|
||||
* <td>Actual package name of net.minecraft.server.VERSION</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{obc}</td>
|
||||
* <td>Actual pacakge name of org.bukkit.craftbukkit.VERSION</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{version}</td>
|
||||
* <td>The current Minecraft package VERSION, if any.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param lookupName - the class name with variables.
|
||||
* @param aliases - alternative names for this class.
|
||||
* @return Class object.
|
||||
* @throws RuntimeException If we are unable to find any of the given classes.
|
||||
*/
|
||||
public static Class<?> getClass(String lookupName, String... aliases) {
|
||||
try {
|
||||
// Try the main class first
|
||||
return getClass(lookupName);
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> success = null;
|
||||
|
||||
// Try every alias too
|
||||
for (String alias : aliases) {
|
||||
try {
|
||||
success = getClass(alias);
|
||||
break;
|
||||
} catch (RuntimeException e1) {
|
||||
// e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (success != null) {
|
||||
return success;
|
||||
} else {
|
||||
// Hack failed
|
||||
throw new RuntimeException(String.format("Unable to find %s (%s)", lookupName, String.join(",", aliases)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class in the net.minecraft.server.VERSION.* package.
|
||||
*
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,25 +44,21 @@ import com.mojang.authlib.GameProfile;
|
||||
public abstract class TinyProtocol {
|
||||
private static final AtomicInteger ID = new AtomicInteger(0);
|
||||
|
||||
// Required Minecraft classes
|
||||
private static final Class<?> entityPlayerClass = Reflection.getClass("{nms}.EntityPlayer", "net.minecraft.server.level.EntityPlayer");
|
||||
private static final Class<?> playerConnectionClass = Reflection.getClass("{nms}.PlayerConnection", "net.minecraft.server.network.PlayerConnection");
|
||||
private static final Class<?> networkManagerClass = Reflection.getClass("{nms}.NetworkManager", "net.minecraft.network.NetworkManager");
|
||||
|
||||
// Used in order to lookup a channel
|
||||
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
|
||||
private static final FieldAccessor<?> getConnection = Reflection.getField(entityPlayerClass, null, playerConnectionClass);
|
||||
private static final FieldAccessor<?> getManager = Reflection.getField(playerConnectionClass, null, networkManagerClass);
|
||||
private static final FieldAccessor<Channel> getChannel = Reflection.getField(networkManagerClass, Channel.class, 0);
|
||||
private static final FieldAccessor<Object> getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class);
|
||||
private static final FieldAccessor<Object> getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class);
|
||||
private static final FieldAccessor<Channel> getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0);
|
||||
|
||||
// Looking up ServerConnection
|
||||
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer", "net.minecraft.server.MinecraftServer");
|
||||
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection", "net.minecraft.server.network.ServerConnection");
|
||||
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer");
|
||||
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection");
|
||||
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
|
||||
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
|
||||
private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
|
||||
|
||||
// Packets we have to intercept
|
||||
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getClass("{nms}.PacketLoginInStart", "net.minecraft.network.protocol.login.PacketLoginInStart");
|
||||
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
|
||||
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
|
||||
|
||||
// Speedup channel lookup
|
||||
@@ -204,22 +199,8 @@ public abstract class TinyProtocol {
|
||||
Object serverConnection = getServerConnection.get(mcServer);
|
||||
boolean looking = true;
|
||||
|
||||
try {
|
||||
Field field = Reflection.getParameterizedField(serverConnectionClass, List.class, networkManagerClass);
|
||||
field.setAccessible(true);
|
||||
|
||||
networkManagers = (List<Object>) field.get(serverConnection);
|
||||
} catch (Exception ex) {
|
||||
plugin.getLogger().info("Encountered an exception checking list fields" + ex);
|
||||
MethodInvoker method = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
|
||||
|
||||
networkManagers = (List<Object>) method.invoke(null, serverConnection);
|
||||
}
|
||||
|
||||
if (networkManagers == null) {
|
||||
throw new IllegalArgumentException("Failed to obtain list of network managers");
|
||||
}
|
||||
// We need to synchronize against this list
|
||||
networkManagers = (List<Object>) getNetworkMarkers.invoke(null, serverConnection);
|
||||
createServerChannelHandler();
|
||||
|
||||
// Find the correct list, or implicitly throw an exception
|
||||
|
||||
+1
-3
@@ -5,7 +5,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = 'com.comphenix.protocol'
|
||||
version = '5.0.0'
|
||||
version = '5.0.0-SNAPSHOT'
|
||||
description = 'Provides access to the Minecraft protocol'
|
||||
|
||||
def isSnapshot = version.endsWith('-SNAPSHOT')
|
||||
@@ -47,8 +47,6 @@ dependencies {
|
||||
testImplementation 'io.netty:netty-common:4.1.77.Final'
|
||||
testImplementation 'io.netty:netty-transport:4.1.77.Final'
|
||||
testImplementation 'org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT'
|
||||
testImplementation 'net.kyori:adventure-text-serializer-gson:4.13.0'
|
||||
testImplementation 'net.kyori:adventure-text-serializer-plain:4.13.1'
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<name>ProtocolLib</name>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
|
||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||
<url>https://github.com/dmulloy2/ProtocolLib</url>
|
||||
<packaging>jar</packaging>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.number></project.build.number>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
|
||||
<junit.version>5.9.2</junit.version>
|
||||
<mockito.version>4.11.0</mockito.version>
|
||||
<netty.version>4.1.77.Final</netty.version>
|
||||
<spigot.version>1.19.4-R0.1-SNAPSHOT</spigot.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean install</defaultGoal>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<testSourceDirectory>src/test/java</testSourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>net.bytebuddy</pattern>
|
||||
<shadedPattern>com.comphenix.net.bytebuddy</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>org.spigotmc:spigot</exclude>
|
||||
<exclude>org.spigotmc:spigot-api</exclude>
|
||||
<exclude>junit:junit</exclude>
|
||||
<exclude>io.netty:*</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Main-Class>com.comphenix.protocol.Application</Main-Class>
|
||||
<Implementation-Title>ProtocolLib</Implementation-Title>
|
||||
<Implementation-Version>${project.fullVersion}</Implementation-Version>
|
||||
<Implementation-Vendor>dmulloy2</Implementation-Vendor>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<finalName>${project.name}</finalName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
<useFile>false</useFile>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>projectVersion</name>
|
||||
<value>${project.version}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<!-- We need this as we use reflection in tests to ensure equality -->
|
||||
<argLine>--add-opens java.base/java.util=ALL-UNNAMED</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<failOnError>false</failOnError>
|
||||
<encoding>ISO-8859-1</encoding>
|
||||
<doctitle>ProtocolLib JavaDocs</doctitle>
|
||||
<windowtitle>ProtocolLib JavaDocs</windowtitle>
|
||||
<bottom>Copyright © {inceptionYear}–{currentYear}
|
||||
Comphenix and dmulloy2. Licensed under the GNU GPL v2.
|
||||
</bottom>
|
||||
<additionalOptions>
|
||||
<additionalOption>-Xdoclint:none</additionalOption>
|
||||
</additionalOptions>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>aggregate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jenkins</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env.BUILD_NUMBER</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
|
||||
<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>
|
||||
<!--<project.fullVersion>${project.version}</project.fullVersion>-->
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>release-sign-artifacts</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>performRelease</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- TODO: Look into signing releases
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/dmulloy2/ProtocolLib.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:dmulloy2/ProtocolLib.git</developerConnection>
|
||||
<url>https://github.com/dmulloy2/ProtocolLib</url>
|
||||
</scm>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GNU GENERAL PUBLIC LICENSE - Version 2, June 1991</name>
|
||||
<url>https://www.gnu.org/licenses/gpl-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dmulloy2</id>
|
||||
<name>Dan Mulloy</name>
|
||||
<url>https://dmulloy2.net/</url>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
<role>maintainer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>aadnk</id>
|
||||
<name>Kristian S. Stangeland</name>
|
||||
<email>kr_stang@hotmail.com</email>
|
||||
<url>https://comphenix.net/</url>
|
||||
<roles>
|
||||
<role>former author</role>
|
||||
</roles>
|
||||
<timezone>1</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>dmulloy2-releases</id>
|
||||
<url>https://repo.dmulloy2.net/repository/releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>dmulloy2-snapshots</id>
|
||||
<url>https://repo.dmulloy2.net/repository/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- core minecraft dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>${spigot.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>${spigot.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Compile with the old version of Netty for backwards compat -->
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.0.23.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/net.kyori/adventure-text-serializer-gson -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-gson</artifactId>
|
||||
<version>4.13.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy -->
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing dependencies -->
|
||||
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-inline</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-common -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-common</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-transport -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -29,7 +29,6 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractStructure {
|
||||
protected transient Object handle;
|
||||
@@ -309,31 +308,6 @@ public abstract class AbstractStructure {
|
||||
BlockPosition.getConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for registrable objects.
|
||||
*
|
||||
* @param registrableClass The registrable object's class.
|
||||
* @return A modifier for a registrable objects.
|
||||
* @see MinecraftReflection#getBlockEntityTypeClass()
|
||||
*/
|
||||
public StructureModifier<WrappedRegistrable> getRegistrableModifier(
|
||||
@NotNull final Class<?> registrableClass
|
||||
) {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.withType(
|
||||
registrableClass,
|
||||
BukkitConverters.getWrappedRegistrable(registrableClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for BlockEntityType.
|
||||
* @return A modifier for a BlockEntityType.
|
||||
*/
|
||||
public StructureModifier<WrappedRegistrable> getBlockEntityTypeModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return getRegistrableModifier(MinecraftReflection.getBlockEntityTypeClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for wrapped ChunkCoordIntPairs.
|
||||
* @return A modifier for ChunkCoordIntPair.
|
||||
@@ -987,7 +961,7 @@ public abstract class AbstractStructure {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for profile public keys in 1.19
|
||||
* Retrieve a read/write structure for profile public keys in 1.9
|
||||
* @return The Structure Modifier
|
||||
*/
|
||||
public StructureModifier<WrappedProfilePublicKey> getProfilePublicKeys() {
|
||||
@@ -997,24 +971,13 @@ public abstract class AbstractStructure {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for profile public key data in 1.19
|
||||
* Retrieve a read/write structure for profile public key data in 1.9
|
||||
* @return The Structure Modifier
|
||||
*/
|
||||
public StructureModifier<WrappedProfileKeyData> getProfilePublicKeyData() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getProfilePublicKeyDataClass(),
|
||||
BukkitConverters.getWrappedPublicKeyDataConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves read/write structure for remote chat session data in 1.19.3
|
||||
* @return The Structure Modifier
|
||||
*/
|
||||
public StructureModifier<WrappedRemoteChatSessionData> getRemoteChatSessionData() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getRemoteChatSessionDataClass(),
|
||||
BukkitConverters.getWrappedRemoteChatSessionDataConverter()
|
||||
);
|
||||
MinecraftReflection.getProfilePublicKeyDataClass(),
|
||||
BukkitConverters.getWrappedPublicKeyDataConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1043,7 +1006,7 @@ public abstract class AbstractStructure {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return read/writer structure direct access to salted signature data like chat messages
|
||||
* @return read/writer structure direct access to signature data like chat messages
|
||||
*/
|
||||
public StructureModifier<WrappedSaltedSignature> getSignatures() {
|
||||
return structureModifier.withType(
|
||||
@@ -1052,16 +1015,6 @@ public abstract class AbstractStructure {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return read/writer structure direct access to unsalted signature data for example in chat message (since 1.19.3)
|
||||
*/
|
||||
public StructureModifier<WrappedMessageSignature> getMessageSignatures() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getMessageSignatureClass(),
|
||||
BukkitConverters.getWrappedMessageSignatureConverter()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftConverter converter for left values
|
||||
* @param rightConverter converter for right values
|
||||
|
||||
@@ -92,9 +92,6 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket,
|
||||
boolean filtered, @Nullable PacketEvent bundleEvent) {
|
||||
super(source);
|
||||
if(packet == null) {
|
||||
throw new IllegalArgumentException("packet cannot be null");
|
||||
}
|
||||
this.packet = packet;
|
||||
this.playerReference = new WeakReference<>(player);
|
||||
this.networkMarker = marker;
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.comphenix.protocol.injector;
|
||||
import com.comphenix.protocol.AsynchronousManager;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
@@ -33,8 +32,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
@@ -544,29 +541,25 @@ public class PacketFilterManager implements ListenerInvoker, InternalManager {
|
||||
}
|
||||
|
||||
private void postPacketToListeners(SortedPacketListenerList listeners, PacketEvent event, boolean outbound) {
|
||||
try {
|
||||
// append async marker if any async listener for the packet was registered
|
||||
if (this.asyncFilterManager.hasAsynchronousListeners(event)) {
|
||||
event.setAsyncMarker(this.asyncFilterManager.createAsyncMarker());
|
||||
}
|
||||
// append async marker if any async listener for the packet was registered
|
||||
if (this.asyncFilterManager.hasAsynchronousListeners(event)) {
|
||||
event.setAsyncMarker(this.asyncFilterManager.createAsyncMarker());
|
||||
}
|
||||
|
||||
// post to sync listeners
|
||||
if (outbound) {
|
||||
listeners.invokePacketSending(this.reporter, event);
|
||||
} else {
|
||||
listeners.invokePacketRecieving(this.reporter, event);
|
||||
}
|
||||
// post to sync listeners
|
||||
if (outbound) {
|
||||
listeners.invokePacketSending(this.reporter, event);
|
||||
} else {
|
||||
listeners.invokePacketRecieving(this.reporter, event);
|
||||
}
|
||||
|
||||
// check if we need to post the packet to the async handler
|
||||
if (!event.isCancelled() && event.getAsyncMarker() != null && !event.getAsyncMarker().isAsyncCancelled()) {
|
||||
this.asyncFilterManager.enqueueSyncPacket(event, event.getAsyncMarker());
|
||||
// check if we need to post the packet to the async handler
|
||||
if (!event.isCancelled() && event.getAsyncMarker() != null && !event.getAsyncMarker().isAsyncCancelled()) {
|
||||
this.asyncFilterManager.enqueueSyncPacket(event, event.getAsyncMarker());
|
||||
|
||||
// cancel the packet here for async processing (enqueueSyncPacket will create a copy of the event)
|
||||
event.setReadOnly(false);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to process " + (outbound ? "outbound" : "inbound") + " packet event: " + event, t);
|
||||
// cancel the packet here for async processing (enqueueSyncPacket will create a copy of the event)
|
||||
event.setReadOnly(false);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,16 @@ package com.comphenix.protocol.injector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.concurrency.AbstractConcurrentListenerMultimap;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.timing.TimedListenerManager;
|
||||
import com.comphenix.protocol.timing.TimedListenerManager.ListenerType;
|
||||
import com.comphenix.protocol.timing.TimedTracker;
|
||||
@@ -152,23 +152,12 @@ public final class SortedPacketListenerList extends AbstractConcurrentListenerMu
|
||||
Iterable<PacketContainer> packets = event.getPacket().getPacketBundles().read(0);
|
||||
List<PacketContainer> outPackets = new ArrayList<>();
|
||||
for (PacketContainer subPacket : packets) {
|
||||
if(subPacket == null) {
|
||||
ProtocolLibrary.getPlugin().getLogger().log(Level.WARNING, "Failed to invoke packet event " + (priorityFilter == null ? "" : ("with priority " + priorityFilter)) + " in bundle because bundle contains null packet: " + packets, new Throwable());
|
||||
continue;
|
||||
}
|
||||
PacketEvent subPacketEvent = PacketEvent.fromServer(this, subPacket, event.getNetworkMarker(), event.getPlayer());
|
||||
invokeUnpackedPacketSending(reporter, subPacketEvent, priorityFilter);
|
||||
|
||||
if (!subPacketEvent.isCancelled()) {
|
||||
// if the packet event has been cancelled, the packet will be removed from the bundle
|
||||
PacketContainer packet = subPacketEvent.getPacket();
|
||||
if(packet == null) {
|
||||
ProtocolLibrary.getPlugin().getLogger().log(Level.WARNING, "null packet container returned for " + subPacketEvent, new Throwable());
|
||||
} else if(packet.getHandle() == null) {
|
||||
ProtocolLibrary.getPlugin().getLogger().log(Level.WARNING, "null packet handle returned for " + subPacketEvent, new Throwable());
|
||||
} else {
|
||||
outPackets.add(packet);
|
||||
}
|
||||
outPackets.add(subPacketEvent.getPacket());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
|
||||
/**
|
||||
* Static packet registry in Minecraft.
|
||||
@@ -254,6 +255,10 @@ public class PacketRegistry {
|
||||
int packetId = entry.getKey();
|
||||
Class<?> packetClass = entry.getValue();
|
||||
|
||||
if (MinecraftReflection.isBundleDelimiter(packetClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PacketType type = PacketType.fromCurrent(protocol, sender, packetId, packetClass);
|
||||
|
||||
try {
|
||||
@@ -363,9 +368,6 @@ public class PacketRegistry {
|
||||
// Try the lookup first (may be null, so check contains)
|
||||
Optional<Class<?>> res = REGISTER.typeToClass.get(type);
|
||||
if (res != null) {
|
||||
if(res.isPresent() && MinecraftReflection.isBundleDelimiter(res.get())) {
|
||||
return MinecraftReflection.getPackedBundlePacketClass();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -378,9 +380,6 @@ public class PacketRegistry {
|
||||
|
||||
// cache it for next time
|
||||
associate(type, clazz);
|
||||
if(clazz != null && MinecraftReflection.isBundleDelimiter(clazz)) {
|
||||
clazz = MinecraftReflection.getPackedBundlePacketClass().orElseThrow(() -> new IllegalStateException("Packet bundle class not found."));
|
||||
}
|
||||
return Optional.ofNullable(clazz);
|
||||
}
|
||||
|
||||
|
||||
@@ -1573,10 +1573,6 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("world.entity.player.ProfilePublicKey");
|
||||
}
|
||||
|
||||
public static Class<?> getMessageSignatureClass() {
|
||||
return getMinecraftClass("network.chat.MessageSignature");
|
||||
}
|
||||
|
||||
public static Class<?> getSaltedSignatureClass() {
|
||||
try {
|
||||
return getMinecraftClass("SaltedSignature");
|
||||
@@ -1625,10 +1621,6 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("network.chat.RemoteChatSession");
|
||||
}
|
||||
|
||||
public static Class<?> getRemoteChatSessionDataClass() {
|
||||
return getRemoteChatSessionClass().getClasses()[0];
|
||||
}
|
||||
|
||||
public static Class<?> getFastUtilClass(String className) {
|
||||
return getLibraryClass("it.unimi.dsi.fastutil." + className);
|
||||
}
|
||||
@@ -1693,22 +1685,6 @@ public final class MinecraftReflection {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getDynamicOpsClass() {
|
||||
return getLibraryClass("com.mojang.serialization.DynamicOps");
|
||||
}
|
||||
|
||||
public static Class<?> getJsonOpsClass() {
|
||||
return getLibraryClass("com.mojang.serialization.JsonOps");
|
||||
}
|
||||
|
||||
public static Class<?> getNbtOpsClass() {
|
||||
return getMinecraftClass("nbt.DynamicOpsNBT" /* Spigot Mappings */, "nbt.NbtOps" /* Mojang Mappings */);
|
||||
}
|
||||
|
||||
public static Class<?> getCodecClass() {
|
||||
return getLibraryClass("com.mojang.serialization.Codec");
|
||||
}
|
||||
|
||||
public static Class<?> getHolderClass() {
|
||||
return getMinecraftClass("core.Holder");
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ import org.bukkit.inventory.MerchantRecipe;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.comphenix.protocol.utility.MinecraftReflection.getCraftBukkitClass;
|
||||
import static com.comphenix.protocol.utility.MinecraftReflection.getMinecraftClass;
|
||||
@@ -588,23 +587,7 @@ public class BukkitConverters {
|
||||
public static EquivalentConverter<WrappedBlockData> getWrappedBlockDataConverter() {
|
||||
return ignoreNull(handle(WrappedBlockData::getHandle, WrappedBlockData::fromHandle, WrappedBlockData.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a converter for wrapped block entity type.
|
||||
* @return Wrapped block entity type.
|
||||
*/
|
||||
public static EquivalentConverter<WrappedRegistrable> getWrappedRegistrable(
|
||||
@NotNull final Class<?> registrableClass
|
||||
) {
|
||||
return ignoreNull(
|
||||
handle(
|
||||
WrappedRegistrable::getHandle,
|
||||
handle -> WrappedRegistrable.fromHandle(registrableClass, handle),
|
||||
WrappedRegistrable.class
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a converter for wrapped attribute snapshots.
|
||||
* @return Wrapped attribute snapshot converter.
|
||||
@@ -621,10 +604,6 @@ public class BukkitConverters {
|
||||
return ignoreNull(handle(WrappedProfileKeyData::getHandle, WrappedProfileKeyData::new, WrappedProfileKeyData.class));
|
||||
}
|
||||
|
||||
public static EquivalentConverter<WrappedRemoteChatSessionData> getWrappedRemoteChatSessionDataConverter() {
|
||||
return ignoreNull(handle(WrappedRemoteChatSessionData::getHandle, WrappedRemoteChatSessionData::new, WrappedRemoteChatSessionData.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return converter for cryptographic signature data that are used in login and chat packets
|
||||
*/
|
||||
@@ -632,13 +611,6 @@ public class BukkitConverters {
|
||||
return ignoreNull(handle(WrappedSaltedSignature::getHandle, WrappedSaltedSignature::new, WrappedSaltedSignature.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return converter for an encoded cryptographic message signature
|
||||
*/
|
||||
public static EquivalentConverter<WrappedMessageSignature> getWrappedMessageSignatureConverter() {
|
||||
return ignoreNull(handle(WrappedMessageSignature::getHandle, WrappedMessageSignature::new, WrappedMessageSignature.class));
|
||||
}
|
||||
|
||||
public static EquivalentConverter<WrappedLevelChunkData.ChunkData> getWrappedChunkDataConverter() {
|
||||
return ignoreNull(handle(WrappedLevelChunkData.ChunkData::getHandle, WrappedLevelChunkData.ChunkData::new, WrappedLevelChunkData.ChunkData.class));
|
||||
}
|
||||
@@ -648,7 +620,7 @@ public class BukkitConverters {
|
||||
}
|
||||
|
||||
public static EquivalentConverter<PacketContainer> getPacketContainerConverter() {
|
||||
return ignoreNull(handle(PacketContainer::getHandle, PacketContainer::fromPacket, PacketContainer.class));
|
||||
return handle(PacketContainer::getHandle, PacketContainer::fromPacket, PacketContainer.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,21 +14,25 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
|
||||
/**
|
||||
* Utility class for converters
|
||||
|
||||
@@ -30,8 +30,6 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an immutable PlayerInfoData in the PLAYER_INFO packet.
|
||||
* @author dmulloy2
|
||||
@@ -45,9 +43,6 @@ public class PlayerInfoData {
|
||||
private final NativeGameMode gameMode;
|
||||
private final WrappedGameProfile profile;
|
||||
private final WrappedChatComponent displayName;
|
||||
@Nullable
|
||||
private final WrappedRemoteChatSessionData remoteChatSessionData;
|
||||
@Nullable
|
||||
private final WrappedProfileKeyData profileKeyData;
|
||||
|
||||
// This is the same order as the NMS class, minus the packet (which isn't a field)
|
||||
@@ -59,35 +54,7 @@ public class PlayerInfoData {
|
||||
this(profile.getUUID(), latency, true, gameMode, profile, displayName, keyData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new PlayerInfoData for Minecraft 1.19 or later without signature data
|
||||
* @see PlayerInfoData#PlayerInfoData(UUID, int, boolean, NativeGameMode, WrappedGameProfile, WrappedChatComponent, WrappedRemoteChatSessionData)
|
||||
*
|
||||
* @param profileId the id of the profile (has to be non-null)
|
||||
* @param latency the latency in milliseconds
|
||||
* @param listed whether the player is listed in the tab list
|
||||
* @param gameMode the game mode
|
||||
* @param profile the game profile
|
||||
* @param displayName display name in tab list (optional)
|
||||
*/
|
||||
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName) {
|
||||
this(profileId, latency, listed, gameMode, profile, displayName, (WrappedRemoteChatSessionData) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new PlayerInfoData for Minecraft 1.19. This is incompatible on 1.19.3.
|
||||
* @see PlayerInfoData#PlayerInfoData(UUID, int, boolean, NativeGameMode, WrappedGameProfile, WrappedChatComponent, WrappedRemoteChatSessionData)
|
||||
*
|
||||
* @param profileId the id of the profile (has to be non-null)
|
||||
* @param latency the latency in milliseconds
|
||||
* @param listed whether the player is listed in the tab list
|
||||
* @param gameMode the game mode
|
||||
* @param profile the game profile
|
||||
* @param displayName display name in tab list (optional)
|
||||
* @param profileKeyData the public key for the profile or null
|
||||
*/
|
||||
@Deprecated
|
||||
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName, @Nullable WrappedProfileKeyData profileKeyData) {
|
||||
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName, WrappedProfileKeyData profileKeyData) {
|
||||
this.profileId = profileId;
|
||||
this.latency = latency;
|
||||
this.listed = listed;
|
||||
@@ -95,29 +62,6 @@ public class PlayerInfoData {
|
||||
this.profile = profile;
|
||||
this.displayName = displayName;
|
||||
this.profileKeyData = profileKeyData;
|
||||
this.remoteChatSessionData = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new PlayerInfoData for Minecraft 1.19.3 or later.
|
||||
*
|
||||
* @param profileId the id of the profile (has to be non-null)
|
||||
* @param latency the latency in milliseconds
|
||||
* @param listed whether the player is listed in the tab list
|
||||
* @param gameMode the game mode
|
||||
* @param profile the game profile
|
||||
* @param displayName display name in tab list (optional)
|
||||
* @param remoteChatSession the remote chat session for this profile or null
|
||||
*/
|
||||
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName, @Nullable WrappedRemoteChatSessionData remoteChatSession) {
|
||||
this.profileId = profileId;
|
||||
this.latency = latency;
|
||||
this.listed = listed;
|
||||
this.gameMode = gameMode;
|
||||
this.profile = profile;
|
||||
this.displayName = displayName;
|
||||
this.profileKeyData = null;
|
||||
this.remoteChatSessionData = remoteChatSession;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,9 +69,6 @@ public class PlayerInfoData {
|
||||
* @return the id of the profile
|
||||
*/
|
||||
public UUID getProfileId() {
|
||||
if(profileId == null && profile != null) {
|
||||
return profile.getUUID(); // Ensure forward compatability
|
||||
}
|
||||
return profileId;
|
||||
}
|
||||
|
||||
@@ -156,7 +97,7 @@ public class PlayerInfoData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if the player is listed on the client (since 1.19.3)
|
||||
* Gets if the player is listed on the client.
|
||||
* @return if the player is listed
|
||||
*/
|
||||
public boolean isListed() {
|
||||
@@ -180,21 +121,11 @@ public class PlayerInfoData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key of the profile (since 1.19). Returns the public key of the remote chat session since 1.19.3
|
||||
* @return The public key of the profile.
|
||||
* Gets the profile key data of the player represented by this data, null if not present.
|
||||
* @return The profile key data
|
||||
*/
|
||||
@Nullable
|
||||
public WrappedProfileKeyData getProfileKeyData() {
|
||||
return this.profileKeyData != null ? this.profileKeyData : (this.remoteChatSessionData != null ? this.remoteChatSessionData.getProfilePublicKey() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remoteChatSessionData (since 1.19.3)
|
||||
* @return The remote chat sesion data or null
|
||||
*/
|
||||
@Nullable
|
||||
public WrappedRemoteChatSessionData getRemoteChatSessionData() {
|
||||
return this.remoteChatSessionData;
|
||||
return this.profileKeyData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,7 +157,8 @@ public class PlayerInfoData {
|
||||
args.add(MinecraftReflection.getIChatBaseComponentClass());
|
||||
|
||||
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
args.add(MinecraftReflection.getRemoteChatSessionDataClass());
|
||||
// RemoteChatSession$a...
|
||||
args.add(MinecraftReflection.getRemoteChatSessionClass().getClasses()[0]);
|
||||
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||
args.add(MinecraftReflection.getProfilePublicKeyDataClass());
|
||||
}
|
||||
@@ -243,28 +175,26 @@ public class PlayerInfoData {
|
||||
Object gameMode = EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode);
|
||||
Object displayName = specific.displayName != null ? specific.displayName.handle : null;
|
||||
|
||||
Object profile = specific.profile != null ? specific.profile.handle : null;
|
||||
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
return constructor.newInstance(
|
||||
specific.profileId,
|
||||
profile,
|
||||
specific.profile.handle,
|
||||
specific.listed,
|
||||
specific.latency,
|
||||
gameMode,
|
||||
displayName,
|
||||
specific.remoteChatSessionData != null ? BukkitConverters.getWrappedRemoteChatSessionDataConverter().getGeneric(specific.remoteChatSessionData) : null
|
||||
);
|
||||
null); // TODO: do we want to support this?
|
||||
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||
return constructor.newInstance(
|
||||
profile,
|
||||
specific.profile.handle,
|
||||
specific.latency,
|
||||
gameMode,
|
||||
displayName,
|
||||
specific.profileKeyData == null ? null : specific.profileKeyData.handle);
|
||||
} else if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
return constructor.newInstance(profile, specific.latency, gameMode, displayName);
|
||||
return constructor.newInstance(specific.profile.handle, specific.latency, gameMode, displayName);
|
||||
} else {
|
||||
return constructor.newInstance(null, profile, specific.latency, gameMode, displayName);
|
||||
return constructor.newInstance(null, specific.profile.handle, specific.latency, gameMode, displayName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to construct PlayerInfoData.", e);
|
||||
@@ -292,18 +222,8 @@ public class PlayerInfoData {
|
||||
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
|
||||
WrappedChatComponent displayName = displayNames.read(0);
|
||||
|
||||
if(MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
return new PlayerInfoData(modifier.<UUID>withType(UUID.class).read(0),
|
||||
latency,
|
||||
modifier.<Boolean>withType(boolean.class).read(0),
|
||||
gameMode,
|
||||
gameProfile,
|
||||
displayName,
|
||||
modifier.withType(MinecraftReflection.getRemoteChatSessionDataClass(), BukkitConverters.getWrappedRemoteChatSessionDataConverter()).read(0)
|
||||
);
|
||||
}
|
||||
WrappedProfileKeyData key = null;
|
||||
if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||
if (MinecraftVersion.WILD_UPDATE.atOrAbove() && !MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
StructureModifier<WrappedProfileKeyData> keyData = modifier.withType(
|
||||
MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter());
|
||||
key = keyData.read(0);
|
||||
@@ -333,34 +253,20 @@ public class PlayerInfoData {
|
||||
// Only compare objects of similar type
|
||||
if (obj instanceof PlayerInfoData) {
|
||||
PlayerInfoData other = (PlayerInfoData) obj;
|
||||
return Objects.equals(profile, other.profile)
|
||||
&& Objects.equals(profileId, other.profileId)
|
||||
&& latency == other.latency
|
||||
&& gameMode == other.gameMode
|
||||
&& Objects.equals(displayName, other.displayName)
|
||||
&& listed == other.listed
|
||||
&& Objects.equals(remoteChatSessionData, other.remoteChatSessionData)
|
||||
&& Objects.equals(profileKeyData, other.profileKeyData);
|
||||
return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode
|
||||
&& Objects.equals(displayName, other.displayName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(latency, gameMode, profile, displayName, profileKeyData, remoteChatSessionData, listed);
|
||||
return Objects.hash(latency, gameMode, profile, displayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if(MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
return String.format("PlayerInfoData[latency=%s, listed=%b, gameMode=%s, profile=%s, displayName=%s, remoteChatSession=%s]",
|
||||
latency, listed, gameMode, profile, displayName, remoteChatSessionData);
|
||||
}
|
||||
if(MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||
return String.format("PlayerInfoData[latency=%s, listed=%b, gameMode=%s, profile=%s, displayName=%s, profilePublicKey=%s]",
|
||||
latency, listed, gameMode, profile, displayName, profileKeyData);
|
||||
}
|
||||
return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s]",
|
||||
latency, gameMode, profile, displayName);
|
||||
latency, gameMode, profile, displayName);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Lukas Alt
|
||||
* @since 24.04.2023
|
||||
*/
|
||||
public class WrappedMessageSignature extends AbstractWrapper {
|
||||
private final static Class<?> HANDLE_TYPE = MinecraftReflection.getMessageSignatureClass();
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
private StructureModifier<Object> modifier;
|
||||
|
||||
/**
|
||||
* Construct a new NMS wrapper.
|
||||
*
|
||||
* @param handle - the NMS handle
|
||||
*/
|
||||
public WrappedMessageSignature(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
this.setHandle(handle);
|
||||
}
|
||||
|
||||
public WrappedMessageSignature(byte[] bytes) {
|
||||
super(HANDLE_TYPE);
|
||||
if(CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(HANDLE_TYPE, byte[].class);
|
||||
}
|
||||
this.setHandle(CONSTRUCTOR.invoke(bytes));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHandle(Object handle) {
|
||||
super.setHandle(handle);
|
||||
this.modifier = new StructureModifier<>(HANDLE_TYPE).withTarget(handle);
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return modifier.<byte[]>withType(byte[].class).read(0);
|
||||
}
|
||||
|
||||
public void setBytes(byte[] bytes) {
|
||||
modifier.<byte[]>withType(byte[].class).write(0, bytes);
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2015 dmulloy2
|
||||
* <p>
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Represents a wrapper around registrable objects.
|
||||
*
|
||||
* @author portlek
|
||||
*/
|
||||
public final class WrappedRegistrable extends AbstractWrapper implements ClonableWrapper {
|
||||
|
||||
@NotNull
|
||||
private final Factory factory;
|
||||
|
||||
private WrappedRegistrable(
|
||||
@NotNull final Factory factory,
|
||||
@NotNull final Object handle
|
||||
) {
|
||||
super(factory.registrableClass);
|
||||
this.factory = factory;
|
||||
setHandle(handle);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrappedRegistrable fromHandle(
|
||||
@NotNull final Factory factory,
|
||||
@NotNull final Object handle
|
||||
) {
|
||||
return new WrappedRegistrable(factory, handle);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrappedRegistrable fromHandle(
|
||||
@NotNull final Class<?> registrableClass,
|
||||
@NotNull final Object handle
|
||||
) {
|
||||
return fromHandle(Factory.getOrCreate(registrableClass), handle);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrappedRegistrable fromClassAndKey(
|
||||
@NotNull final Class<?> registrableClass,
|
||||
@NotNull final MinecraftKey key
|
||||
) {
|
||||
final Factory factory = Factory.getOrCreate(registrableClass);
|
||||
return fromHandle(factory, factory.getHandle(key));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrappedRegistrable fromClassAndKey(
|
||||
@NotNull final Class<?> registrableClass,
|
||||
@NotNull final String key
|
||||
) {
|
||||
return fromClassAndKey(registrableClass, new MinecraftKey(key));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrappedRegistrable blockEntityType(
|
||||
@NotNull final MinecraftKey key
|
||||
) {
|
||||
return fromClassAndKey(MinecraftReflection.getBlockEntityTypeClass(), key);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrappedRegistrable blockEntityType(
|
||||
@NotNull final String key
|
||||
) {
|
||||
return blockEntityType(new MinecraftKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this registrable object's Minecraft key
|
||||
*
|
||||
* @return The Minecraft key
|
||||
*/
|
||||
public MinecraftKey getKey() {
|
||||
return factory.getKey(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this registrable object's Minecraft key
|
||||
*
|
||||
* @param key Minecraft key
|
||||
*/
|
||||
public void setKey(MinecraftKey key) {
|
||||
setHandle(factory.getHandle(key));
|
||||
}
|
||||
|
||||
public WrappedRegistrable deepClone() {
|
||||
return fromHandle(factory, handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedRegistrable[handle=" + handle + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getKey().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedRegistrable)) {
|
||||
return false;
|
||||
}
|
||||
final WrappedRegistrable that = (WrappedRegistrable) o;
|
||||
return handle.equals(that.handle) || (getKey() == that.getKey());
|
||||
}
|
||||
|
||||
private static final class Factory {
|
||||
|
||||
private static final Map<Class<?>, Factory> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
@NotNull
|
||||
private final Class<?> registrableClass;
|
||||
|
||||
@NotNull
|
||||
private final WrappedRegistry registry;
|
||||
|
||||
@NotNull
|
||||
private final FieldAccessor fieldAccessor;
|
||||
|
||||
private Factory(@NotNull final Class<?> registrableClass) {
|
||||
this.registrableClass = registrableClass;
|
||||
this.registry = WrappedRegistry.getRegistry(registrableClass);
|
||||
this.fieldAccessor = Accessors.getFieldAccessor(
|
||||
FuzzyReflection.fromClass(registrableClass, true)
|
||||
.getField(
|
||||
FuzzyFieldContract.newBuilder()
|
||||
.typeExact(registrableClass)
|
||||
.build()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Factory getOrCreate(
|
||||
@NotNull final Class<?> registrableClass
|
||||
) {
|
||||
return CACHE.computeIfAbsent(registrableClass, Factory::new);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MinecraftKey getKey(@NotNull final Object handle) {
|
||||
return registry.getKey(fieldAccessor.get(handle));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Object getHandle(MinecraftKey key) {
|
||||
return registry.get(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
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;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A wrapper around the remote chat session.
|
||||
*
|
||||
* @since 1.19.3
|
||||
*/
|
||||
public class WrappedRemoteChatSessionData extends AbstractWrapper {
|
||||
private final static Class<?> HANDLE_TYPE = MinecraftReflection.getRemoteChatSessionDataClass();
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
private StructureModifier<Object> modifier;
|
||||
|
||||
/**
|
||||
* Constructs a new profile public key wrapper directly from a nms RemoteChatSession.Data/RemoteChatSession.a object.
|
||||
*
|
||||
* @param handle the handle to create the wrapper from.
|
||||
*/
|
||||
public WrappedRemoteChatSessionData(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
this.setHandle(handle);
|
||||
}
|
||||
|
||||
public WrappedRemoteChatSessionData(UUID sessionId, WrappedProfilePublicKey.WrappedProfileKeyData profilePublicKey) {
|
||||
super(HANDLE_TYPE);
|
||||
if (CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
this.getHandleType(),
|
||||
UUID.class, MinecraftReflection.getProfilePublicKeyDataClass());
|
||||
}
|
||||
|
||||
this.setHandle(CONSTRUCTOR.invoke(sessionId, profilePublicKey.getHandle()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the id of the current session
|
||||
* @return session id
|
||||
*/
|
||||
public UUID getSessionID() {
|
||||
return this.modifier.<UUID>withType(UUID.class).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id for this session
|
||||
* @param sessionId new session id
|
||||
*/
|
||||
public void setSessionID(UUID sessionId) {
|
||||
this.modifier.<UUID>withType(UUID.class).write(0, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ProfileKeyData
|
||||
* @return the public key data for this session
|
||||
*/
|
||||
public WrappedProfilePublicKey.WrappedProfileKeyData getProfilePublicKey() {
|
||||
return this.modifier.withType(MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter()).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the profile key data for this session
|
||||
* @param data ProfileKeyData
|
||||
*/
|
||||
public void setProfilePublicKey(WrappedProfilePublicKey.WrappedProfileKeyData data) {
|
||||
this.modifier.withType(MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter()).write(0, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHandle(Object handle) {
|
||||
super.setHandle(handle);
|
||||
this.modifier = new StructureModifier<>(HANDLE_TYPE).withTarget(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(obj instanceof WrappedRemoteChatSessionData) {
|
||||
return handle.equals(((WrappedRemoteChatSessionData) obj).getHandle());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return handle.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return handle.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.ping.LegacyServerPing;
|
||||
@@ -12,6 +15,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
@@ -99,10 +103,8 @@ public class WrappedServerPing implements ClonableWrapper {
|
||||
* @return The wrapped server ping.
|
||||
*/
|
||||
public static WrappedServerPing fromJson(String json) {
|
||||
if(MinecraftVersion.FEATURE_PREVIEW_2.atOrAbove()) {
|
||||
return new WrappedServerPing(ServerPingRecord.fromJson(json).getHandle());
|
||||
}
|
||||
return new WrappedServerPing(LegacyServerPing.fromJson(json));
|
||||
// return fromHandle(GSON_FROM_JSON.invoke(PING_GSON.get(null), json, SERVER_PING));
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,7 +350,8 @@ public class WrappedServerPing implements ClonableWrapper {
|
||||
* @return The JSON representation.
|
||||
*/
|
||||
public String toJson() {
|
||||
return impl.getJson();
|
||||
return null;
|
||||
// return (String) GSON_TO_JSON.invoke(PING_GSON.get(null), getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -543,17 +546,4 @@ public class WrappedServerPing implements ClonableWrapper {
|
||||
return encoded;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof WrappedServerPing)) {
|
||||
return false;
|
||||
}
|
||||
return getHandle().equals(((WrappedServerPing) obj).getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getHandle().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.comphenix.protocol.wrappers.codecs;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.AbstractWrapper;
|
||||
|
||||
public class WrappedCodec extends AbstractWrapper {
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getCodecClass();
|
||||
private static final Class<?> ENCODER_CLASS = MinecraftReflection.getLibraryClass("com.mojang.serialization.Encoder");
|
||||
private static final Class<?> DECODER_CLASS = MinecraftReflection.getLibraryClass("com.mojang.serialization.Decoder");
|
||||
private static final MethodAccessor ENCODE_START_ACCESSOR = Accessors.getMethodAccessor(ENCODER_CLASS, "encodeStart", MinecraftReflection.getDynamicOpsClass(), Object.class);
|
||||
private static final MethodAccessor PARSE_ACCESSOR = Accessors.getMethodAccessor(DECODER_CLASS, "parse", MinecraftReflection.getDynamicOpsClass(), Object.class);
|
||||
|
||||
private WrappedCodec(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
this.setHandle(handle);
|
||||
}
|
||||
|
||||
public static WrappedCodec fromHandle(Object handle) {
|
||||
return new WrappedCodec(handle);
|
||||
}
|
||||
|
||||
public WrappedDataResult encode(Object object, WrappedDynamicOps ops) {
|
||||
return WrappedDataResult.fromHandle(ENCODE_START_ACCESSOR.invoke(handle, ops.getHandle(), object));
|
||||
}
|
||||
|
||||
public WrappedDataResult parse(Object value, WrappedDynamicOps ops) {
|
||||
return WrappedDataResult.fromHandle(PARSE_ACCESSOR.invoke(handle, ops.getHandle(), value));
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.comphenix.protocol.wrappers.codecs;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.AbstractWrapper;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class WrappedDataResult extends AbstractWrapper {
|
||||
private final static Class<?> HANDLE_TYPE = MinecraftReflection.getLibraryClass("com.mojang.serialization.DataResult");
|
||||
private final static Class<?> PARTIAL_DATA_RESULT_CLASS = MinecraftReflection.getLibraryClass("com.mojang.serialization.DataResult$PartialResult");
|
||||
private final static MethodAccessor ERROR_ACCESSOR = Accessors.getMethodAccessor(HANDLE_TYPE, "error");
|
||||
private final static MethodAccessor RESULT_ACCESSOR = Accessors.getMethodAccessor(HANDLE_TYPE, "result");
|
||||
private final static MethodAccessor PARTIAL_RESULT_MESSAGE_ACCESSOR = Accessors.getMethodAccessor(PARTIAL_DATA_RESULT_CLASS, "message");
|
||||
|
||||
/**
|
||||
* Construct a new NMS wrapper.
|
||||
**/
|
||||
public WrappedDataResult(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
this.setHandle(handle);
|
||||
}
|
||||
|
||||
public static WrappedDataResult fromHandle(Object handle) {
|
||||
return new WrappedDataResult(handle);
|
||||
}
|
||||
|
||||
public Optional<Object> getResult() {
|
||||
return (Optional) RESULT_ACCESSOR.invoke(this.handle);
|
||||
}
|
||||
|
||||
public Optional<String> getErrorMessage() {
|
||||
return (Optional) ERROR_ACCESSOR.invoke(this.handle);
|
||||
}
|
||||
|
||||
public Object getOrThrow(Function<String, Throwable> errorHandler) {
|
||||
Optional<String> err = getErrorMessage();
|
||||
if(err.isPresent()) {
|
||||
return errorHandler.apply((String) PARTIAL_RESULT_MESSAGE_ACCESSOR.invoke(err.get()));
|
||||
}
|
||||
Optional<Object> result = getResult();
|
||||
if(result.isPresent()) {
|
||||
return result.get();
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.comphenix.protocol.wrappers.codecs;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.AbstractWrapper;
|
||||
|
||||
public class WrappedDynamicOps extends AbstractWrapper {
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDynamicOpsClass();
|
||||
public static final FieldAccessor NBT_ACCESSOR = Accessors.getFieldAccessor(MinecraftReflection.getNbtOpsClass(), MinecraftReflection.getNbtOpsClass(), false);
|
||||
public static final FieldAccessor[] JSON_ACCESSORS = Accessors.getFieldAccessorArray(MinecraftReflection.getJsonOpsClass(), MinecraftReflection.getJsonOpsClass(), false);
|
||||
private WrappedDynamicOps(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
this.setHandle(handle);
|
||||
}
|
||||
public static WrappedDynamicOps fromHandle(Object handle) {
|
||||
return new WrappedDynamicOps(handle);
|
||||
}
|
||||
public static WrappedDynamicOps json(boolean compressed) {
|
||||
return fromHandle(JSON_ACCESSORS[compressed ? 1 : 0].get(null));
|
||||
}
|
||||
|
||||
public static WrappedDynamicOps nbt() {
|
||||
return fromHandle(NBT_ACCESSOR);
|
||||
}
|
||||
}
|
||||
@@ -286,11 +286,6 @@ public final class LegacyServerPing extends AbstractWrapper implements ServerPin
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJson() {
|
||||
return (String) GSON_TO_JSON.invoke(PING_GSON.get(null), getHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the player count and maximum is visible.
|
||||
* <p>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.comphenix.protocol.wrappers.ping;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public interface ServerPingImpl extends Cloneable {
|
||||
@@ -35,7 +38,6 @@ public interface ServerPingImpl extends Cloneable {
|
||||
|
||||
boolean arePlayersVisible();
|
||||
void setPlayersVisible(boolean visible);
|
||||
String getJson();
|
||||
|
||||
Object getHandle();
|
||||
}
|
||||
@@ -1,39 +1,31 @@
|
||||
package com.comphenix.protocol.wrappers.ping;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import com.comphenix.protocol.events.InternalStructure;
|
||||
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.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.*;
|
||||
import com.comphenix.protocol.wrappers.codecs.WrappedCodec;
|
||||
import com.comphenix.protocol.wrappers.codecs.WrappedDynamicOps;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public final class ServerPingRecord implements ServerPingImpl {
|
||||
private static Class<?> SERVER_PING;
|
||||
private static Class<?> PLAYER_SAMPLE_CLASS;
|
||||
private static Class<?> SERVER_DATA_CLASS;
|
||||
|
||||
private static Class<?> GSON_CLASS;
|
||||
private static MethodAccessor GSON_TO_JSON;
|
||||
private static MethodAccessor GSON_FROM_JSON;
|
||||
private static FieldAccessor DATA_SERIALIZER_GSON;
|
||||
private static Class<?> JSON_ELEMENT_CLASS;
|
||||
|
||||
private static WrappedChatComponent DEFAULT_DESCRIPTION;
|
||||
|
||||
private static ConstructorAccessor PING_CTOR;
|
||||
private static WrappedCodec CODEC;
|
||||
|
||||
private static EquivalentConverter<List<WrappedGameProfile>> PROFILE_LIST_CONVERTER;
|
||||
|
||||
@@ -65,13 +57,6 @@ public final class ServerPingRecord implements ServerPingImpl {
|
||||
PROFILE_LIST_CONVERTER = BukkitConverters.getListConverter(BukkitConverters.getWrappedGameProfileConverter());
|
||||
|
||||
DEFAULT_DESCRIPTION = WrappedChatComponent.fromLegacyText("A Minecraft Server");
|
||||
|
||||
GSON_CLASS = MinecraftReflection.getMinecraftGsonClass();
|
||||
GSON_TO_JSON = Accessors.getMethodAccessor(GSON_CLASS, "toJson", Object.class);
|
||||
GSON_FROM_JSON = Accessors.getMethodAccessor(GSON_CLASS, "fromJson", String.class, Class.class);
|
||||
DATA_SERIALIZER_GSON = Accessors.getFieldAccessor(MinecraftReflection.getPacketDataSerializerClass(), GSON_CLASS, true);
|
||||
JSON_ELEMENT_CLASS = MinecraftReflection.getLibraryClass("com.google.gson.JsonElement");
|
||||
CODEC = WrappedCodec.fromHandle(Accessors.getFieldAccessor(SERVER_PING, MinecraftReflection.getCodecClass(), false).get(null));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to initialize Server Ping", ex);
|
||||
} finally {
|
||||
@@ -148,26 +133,15 @@ public final class ServerPingRecord implements ServerPingImpl {
|
||||
int max = Bukkit.getMaxPlayers();
|
||||
int online = Bukkit.getOnlinePlayers().size();
|
||||
|
||||
return new PlayerSample(max, online, new ArrayList<>());
|
||||
return new PlayerSample(max, online, null);
|
||||
}
|
||||
|
||||
private static Favicon defaultFavicon() {
|
||||
return new Favicon();
|
||||
}
|
||||
|
||||
public static ServerPingRecord fromJson(String json) {
|
||||
|
||||
Object jsonElement = GSON_FROM_JSON.invoke(DATA_SERIALIZER_GSON.get(null), json, JSON_ELEMENT_CLASS);
|
||||
|
||||
Object decoded = CODEC.parse(jsonElement, WrappedDynamicOps.json(false)).getOrThrow(e -> new IllegalStateException("Failed to decode: " + e));
|
||||
return new ServerPingRecord(decoded);
|
||||
}
|
||||
|
||||
public ServerPingRecord(Object handle) {
|
||||
initialize();
|
||||
if(handle.getClass() != SERVER_PING) {
|
||||
throw new IllegalArgumentException("Expected handle of type " + SERVER_PING.getName() + " but got " + handle.getClass().getName());
|
||||
}
|
||||
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
|
||||
InternalStructure structure = new InternalStructure(handle, modifier);
|
||||
@@ -312,35 +286,15 @@ public final class ServerPingRecord implements ServerPingImpl {
|
||||
this.playersVisible = visible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJson() {
|
||||
Object encoded = CODEC.encode(getHandle(), WrappedDynamicOps.json(false)).getOrThrow(e -> new IllegalStateException("Failed to encode: " + e));
|
||||
return (String) GSON_TO_JSON.invoke(DATA_SERIALIZER_GSON.get(null), encoded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
WrappedChatComponent wrappedDescription = description != null ? description : DEFAULT_DESCRIPTION;
|
||||
Object descHandle = wrappedDescription.getHandle();
|
||||
|
||||
Optional<Object> playersHandle = Optional.ofNullable(SAMPLE_WRAPPER.unwrap(playerSample != null ? playerSample : new ArrayList<>())); // sample has to be non-null in handle
|
||||
Optional<Object> playersHandle = Optional.ofNullable(playerSample != null ? SAMPLE_WRAPPER.unwrap(playerSample) : null);
|
||||
Optional<Object> versionHandle = Optional.ofNullable(serverData != null ? DATA_WRAPPER.unwrap(serverData) : null);
|
||||
Optional<Object> favHandle = Optional.ofNullable(favicon != null ? FAVICON_WRAPPER.unwrap(favicon) : null);
|
||||
|
||||
return PING_CTOR.invoke(descHandle, playersHandle, versionHandle, favHandle, enforceSafeChat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof ServerPingRecord)) {
|
||||
return false;
|
||||
}
|
||||
ServerPingRecord other = (ServerPingRecord) obj;
|
||||
|
||||
return Objects.equals(description, other.description)
|
||||
&& Objects.equals(playerSample, other.playerSample)
|
||||
&& Objects.equals(serverData, other.serverData)
|
||||
&& ((favicon == null && other.favicon.iconBytes == null)
|
||||
|| ((favicon != null) == (other.favicon != null) && Arrays.equals(favicon.iconBytes, other.favicon.iconBytes)));
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ 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.utility.MinecraftReflectionTestUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
@@ -32,9 +31,6 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import net.minecraft.network.EnumProtocol;
|
||||
import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||
import net.minecraft.network.protocol.login.PacketLoginInStart;
|
||||
@@ -361,17 +357,4 @@ public class PacketTypeTest {
|
||||
}
|
||||
assertFalse(fail, "Packet type(s) failed to instantiate");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPacketBundleWriting() {
|
||||
PacketContainer bundlePacket = new PacketContainer(PacketType.Play.Server.BUNDLE);
|
||||
assertEquals(MinecraftReflection.getPackedBundlePacketClass().orElseThrow(() -> new IllegalStateException("Packet Bundle class is not present")), bundlePacket.getHandle().getClass());
|
||||
List<PacketContainer> bundle = new ArrayList<>();
|
||||
|
||||
PacketContainer chatMessage = new PacketContainer(PacketType.Play.Server.SYSTEM_CHAT);
|
||||
chatMessage.getStrings().write(0, WrappedChatComponent.fromText("Test").getJson());
|
||||
chatMessage.getBooleans().write(0, false);
|
||||
bundle.add(chatMessage);
|
||||
bundlePacket.getPacketBundles().write(0, bundle);
|
||||
}
|
||||
}
|
||||
@@ -40,13 +40,26 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
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.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.MovingObjectPositionBlock;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
||||
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.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -755,7 +768,7 @@ public class PacketContainerTest {
|
||||
NativeGameMode.CREATIVE,
|
||||
new WrappedGameProfile(new UUID(0, 0), "system"),
|
||||
null,
|
||||
(WrappedRemoteChatSessionData) null);
|
||||
null);
|
||||
updatePlayerInfoActions.getPlayerInfoDataLists().write(1, Collections.singletonList(data));
|
||||
|
||||
Set<EnumWrappers.PlayerInfoAction> readActions = updatePlayerInfoActions.getPlayerInfoActions().read(0);
|
||||
@@ -774,17 +787,21 @@ public class PacketContainerTest {
|
||||
Assertions.assertEquals(NativeGameMode.CREATIVE, firstData.getGameMode());
|
||||
}
|
||||
|
||||
// TODO: fix this this at some point
|
||||
/*
|
||||
@Test
|
||||
public void testSignedChatMessage() {
|
||||
PacketContainer chatPacket = new PacketContainer(PacketType.Play.Client.CHAT);
|
||||
|
||||
byte[] signature = new byte[256];
|
||||
WrappedMessageSignature wrappedSignature = new WrappedMessageSignature(signature);
|
||||
chatPacket.getMessageSignatures().write(0, wrappedSignature);
|
||||
byte[] signature = new byte[512];
|
||||
long salt = 124L;
|
||||
WrappedSaltedSignature wrappedSignature = new WrappedSaltedSignature(salt, signature);
|
||||
chatPacket.getSignatures().write(0, wrappedSignature);
|
||||
|
||||
WrappedMessageSignature read = chatPacket.getMessageSignatures().read(0);
|
||||
assertArrayEquals(signature, read.getBytes());
|
||||
}
|
||||
WrappedSaltedSignature read = chatPacket.getSignatures().read(0);
|
||||
assertEquals(salt, read.getSalt());
|
||||
assertArrayEquals(signature, read.getSignature());
|
||||
}*/
|
||||
|
||||
private void assertPacketsEqualAndSerializable(PacketContainer constructed, PacketContainer cloned) {
|
||||
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
|
||||
@@ -854,6 +871,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
// gives some indication which cloning process fails as the checks itself are happening outside this method
|
||||
System.out.println("Cloning " + type);
|
||||
|
||||
// Clone the packet all three ways
|
||||
PacketContainer shallowCloned = constructed.shallowClone();
|
||||
@@ -868,8 +886,8 @@ public class PacketContainerTest {
|
||||
serializedCloned.getLongs().write(0, 0L);
|
||||
}
|
||||
this.assertPacketsEqualAndSerializable(constructed, serializedCloned);
|
||||
} catch (Throwable t) {
|
||||
Assertions.fail("Unable to clone " + type, t);
|
||||
} catch (Exception ex) {
|
||||
Assertions.fail("Unable to clone " + type, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
|
||||
import com.comphenix.protocol.wrappers.WrappedRemoteChatSessionData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -57,17 +49,4 @@ public class TestUtils {
|
||||
public static void setFinalField(Object obj, Field field, Object newValue) {
|
||||
Accessors.getFieldAccessor(field).set(obj, newValue);
|
||||
}
|
||||
|
||||
public static KeyPair generateKeyPair() throws Exception {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(1024);
|
||||
return keyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
public static WrappedRemoteChatSessionData creteDummyRemoteChatSessionData() throws Exception {
|
||||
byte[] signature = new byte[256];
|
||||
new Random().nextBytes(signature);
|
||||
|
||||
return new WrappedRemoteChatSessionData(UUID.randomUUID(), new WrappedProfilePublicKey.WrappedProfileKeyData(Instant.now(), TestUtils.generateKeyPair().getPublic(), signature));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
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;
|
||||
@@ -16,41 +20,37 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class BukkitConvertersTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
||||
item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
|
||||
item.setItemMeta(meta);
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
||||
item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
|
||||
item.setItemMeta(meta);
|
||||
|
||||
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
|
||||
Object nmsStack = converter.getGeneric(item);
|
||||
ItemStack back = converter.getSpecific(nmsStack);
|
||||
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
|
||||
Object nmsStack = converter.getGeneric(item);
|
||||
ItemStack back = converter.getSpecific(nmsStack);
|
||||
|
||||
assertEquals(item.getType(), back.getType());
|
||||
assertEquals(item.getDurability(), back.getDurability());
|
||||
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
||||
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
||||
}
|
||||
assertEquals(item.getType(), back.getType());
|
||||
assertEquals(item.getDurability(), back.getDurability());
|
||||
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
||||
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEither() {
|
||||
Either<String, String> test = new Left<>("bla");
|
||||
|
||||
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
|
||||
Converters.passthrough(String.class), Converters.passthrough(String.class)
|
||||
Converters.passthrough(String.class), Converters.passthrough(String.class)
|
||||
);
|
||||
|
||||
com.mojang.datafixers.util.Either<String, String> nmsEither = (com.mojang.datafixers.util.Either<String, String>) converter.getGeneric(test);
|
||||
@@ -72,23 +72,4 @@ public class BukkitConvertersTest {
|
||||
assertTrue(EqualsBuilder.reflectionEquals(container, specific)); // PacketContainer does not properly implement equals(.)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWrappedMessageSignatureConverter() {
|
||||
byte[] data = new byte[256];
|
||||
new Random().nextBytes(data);
|
||||
WrappedMessageSignature messageSignature = new WrappedMessageSignature(data);
|
||||
|
||||
assertArrayEquals(data, BukkitConverters.getWrappedMessageSignatureConverter().getSpecific(BukkitConverters.getWrappedMessageSignatureConverter().getGeneric(messageSignature)).getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChatSessionDataConverter() throws Exception {
|
||||
WrappedRemoteChatSessionData wrappedRemoteChatSessionData = TestUtils.creteDummyRemoteChatSessionData();
|
||||
Object generic = BukkitConverters.getWrappedRemoteChatSessionDataConverter().getGeneric(wrappedRemoteChatSessionData);
|
||||
|
||||
WrappedRemoteChatSessionData specific = BukkitConverters.getWrappedRemoteChatSessionDataConverter().getSpecific(generic);
|
||||
assertEquals(wrappedRemoteChatSessionData, specific);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ package com.comphenix.protocol.wrappers;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.TestUtils;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -34,19 +33,14 @@ public class PlayerInfoDataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
public void test() {
|
||||
WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Name");
|
||||
WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name");
|
||||
|
||||
testWriteBack(new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName));
|
||||
testWriteBack(new PlayerInfoData(profile.getUUID(), 42, false, NativeGameMode.CREATIVE, profile, displayName, TestUtils.creteDummyRemoteChatSessionData()));
|
||||
testWriteBack(new PlayerInfoData(profile.getUUID(), 42, false, NativeGameMode.CREATIVE, null, null, TestUtils.creteDummyRemoteChatSessionData()));
|
||||
testWriteBack(new PlayerInfoData(profile.getUUID(), 42, true, NativeGameMode.CREATIVE, null, displayName));
|
||||
}
|
||||
|
||||
private static void testWriteBack(PlayerInfoData data) {
|
||||
PlayerInfoData data = new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName);
|
||||
Object generic = PlayerInfoData.getConverter().getGeneric(data);
|
||||
PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic);
|
||||
|
||||
assertEquals(data, back);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ 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.Test;
|
||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||
@@ -50,18 +49,6 @@ public class WrappedServerPingTest {
|
||||
|
||||
WrappedServerPing roundTrip = packet.getServerPings().read(0);
|
||||
|
||||
String asJson = serverPing.toJson();
|
||||
WrappedServerPing deserialized = WrappedServerPing.fromJson(asJson);
|
||||
deserialized.setMotD(serverPing.getMotD());
|
||||
|
||||
// Deserializing to JSON and parsing the JSON again can lead to a different object as the Mojang Datafixer optimizes server icons or reorders components in the server description
|
||||
assertEquals(serverPing.getVersionName(), deserialized.getVersionName(), "Failed to serialize as JSON and deserialize afterwards (version name mismatch)");
|
||||
assertEquals(serverPing.getVersionProtocol(), deserialized.getVersionProtocol(), "Failed to serialize as JSON and deserialize afterwards (version protocol mismatch)");
|
||||
assertEquals(serverPing.getPlayersOnline(), deserialized.getPlayersOnline(), "Failed to serialize as JSON and deserialize afterwards (players online mismatch)");
|
||||
assertEquals(serverPing.getPlayersMaximum(), deserialized.getPlayersMaximum(), "Failed to serialize as JSON and deserialize afterwards (players maximum mismatch)");
|
||||
assertEquals(serverPing.getPlayers(), deserialized.getPlayers(), "Failed to serialize as JSON and deserialize afterwards (player sample mismatch)");
|
||||
assertEquals(PlainTextComponentSerializer.plainText().serialize(AdventureComponentConverter.fromWrapper(serverPing.getMotD())), PlainTextComponentSerializer.plainText().serialize(AdventureComponentConverter.fromWrapper(deserialized.getMotD()))); // Check if plain text is equivalent
|
||||
|
||||
assertEquals(5, roundTrip.getPlayersOnline());
|
||||
assertEquals(10, roundTrip.getPlayersMaximum());
|
||||
assertEquals("Minecraft 123", roundTrip.getVersionName());
|
||||
|
||||
Reference in new issue
Block a user