Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41bb4bacb2 | ||
|
|
9487c42985 | ||
|
|
55f7b67f9d | ||
|
|
e44d1e6051 | ||
|
|
baecaf4ca4 | ||
|
|
151d4a289f | ||
|
|
1b4d79b302 | ||
|
|
74833f8680 | ||
|
|
e77f8ced4c | ||
|
|
1cd83e493d | ||
|
|
40b6c66491 | ||
|
|
723fc2c7ec | ||
|
|
dd687ce175 | ||
|
|
8774d87d59 | ||
|
|
8361cf078f | ||
|
|
dbedab0c14 | ||
|
|
5dda8c8ab1 | ||
|
|
4c0c18d7c6 | ||
|
|
9c20455bf6 | ||
|
|
8175443da0 | ||
|
|
95a884974a | ||
|
|
153dd61994 | ||
|
|
263ec8a36e | ||
|
|
af46ba4d1a | ||
|
|
dd85904642 | ||
|
|
7a8fce224e | ||
|
|
9ca7c91a76 | ||
|
|
466354cd2c | ||
|
|
99504dab8f | ||
|
|
9b6603e2eb | ||
|
|
4fc476a125 | ||
|
|
583ed4b58a | ||
|
|
638e81b9ce | ||
|
|
9a0703d05d | ||
|
|
9de096f783 | ||
|
|
c54a99945d | ||
|
|
90a38cc15c | ||
|
|
76930ae6e8 | ||
|
|
d745cfb184 | ||
|
|
4be2bf38ff | ||
|
|
0a32f24f08 | ||
|
|
1c2bc274dd | ||
|
|
9b54794f6b | ||
|
|
42bec5a858 | ||
|
|
fa317c1167 | ||
|
|
cc17b9ee6e | ||
|
|
190ca1ff6a | ||
|
|
c51930121f | ||
|
|
c7a8d734d4 | ||
|
|
b446cf2183 | ||
|
|
f11c246276 | ||
|
|
6f91bd23de | ||
|
|
45c293df7d | ||
|
|
5acdb2b3c5 | ||
|
|
72c1f3e26c | ||
|
|
b3ccf82597 | ||
|
|
0c01a11755 | ||
|
|
7ce3f471bf | ||
|
|
97972acee8 | ||
|
|
a0bb11e1bd | ||
|
|
ba74fceed6 |
No files matched your search
@@ -19,7 +19,7 @@ This page will detail specific things that must be done if you intend to contrib
|
||||
|
||||
#### Ready? Let's get started!
|
||||
1. Read the [Protocol Changes](http://wiki.vg/Protocol_History). Always make sure the list is both
|
||||
complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [freenode.net](http://freenode.net)
|
||||
complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [libera.chat](http://libera.chat)
|
||||
or #spigot on [irc.spi.gt](http://irc.spi.gt) ([webchat](https://irc.spi.gt/iris/?channels=spigot)).
|
||||
2. Search for usages of the now-defunct NMS package guard and change them.
|
||||
3. The class `com.comphenix.protocol.PacketType` contains a list of all the packets. If any packets were added or removed
|
||||
@@ -35,4 +35,4 @@ and the release date.
|
||||
8. `com.comphenix.protocol.utility.MinecraftProtocolVersion` contains a map of all the protocol version integers.
|
||||
If the protocol version has been incremented, add a new line to the map.
|
||||
9. `mvn` in root directory again. If it builds successfully, test on the appropriate version of a Spigot server. If
|
||||
the build fails, debug!
|
||||
the build fails, debug!
|
||||
@@ -0,0 +1,25 @@
|
||||
name: ProtocolLib full build lifecycle
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Run maven build lifecycle
|
||||
run: mvn --batch-mode clean test package
|
||||
|
||||
- name: Upload plugin file
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ProtocolLib
|
||||
path: target/ProtocolLib.jar
|
||||
+2
-1
@@ -179,4 +179,5 @@ logs/
|
||||
|
||||
.gradle/
|
||||
build/
|
||||
logs/
|
||||
logs/
|
||||
.java-version
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
language: java
|
||||
jdk:
|
||||
- openjdk8
|
||||
script: mvn clean test
|
||||
install: true
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- "dmulloy2@live.com"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
@@ -1,4 +1,4 @@
|
||||
# ProtocolLib [](https://travis-ci.org/dmulloy2/ProtocolLib)
|
||||
# ProtocolLib
|
||||
|
||||
Certain tasks are impossible to perform with the standard Bukkit API, and may require
|
||||
working with and even modify Minecraft directly. A common technique is to modify incoming
|
||||
@@ -53,7 +53,7 @@ You can also add ProtocolLib as a Maven dependency:
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>4.6.0</version>
|
||||
<version>4.7.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
````
|
||||
@@ -66,7 +66,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.6.0";
|
||||
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.7.0";
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
before_install:
|
||||
- source "$HOME/.sdkman/bin/sdkman-init.sh"
|
||||
- sdk update
|
||||
- sdk install java 17.0.1-tem
|
||||
- sdk use java 17.0.1-tem
|
||||
@@ -1,10 +1,10 @@
|
||||
<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>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<name>ProtocolLib</name>
|
||||
<version>4.6.0</version>
|
||||
<version>4.8.0</version>
|
||||
|
||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||
<url>https://github.com/dmulloy2/ProtocolLib</url>
|
||||
@@ -16,8 +16,10 @@
|
||||
<project.build.number></project.build.number>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
|
||||
<powermock.version>2.0.7</powermock.version>
|
||||
<spigot.version>1.16.4-R0.1-SNAPSHOT</spigot.version>
|
||||
<junit.version>5.8.2</junit.version>
|
||||
<mockito.version>4.3.1</mockito.version>
|
||||
<netty.version>4.1.74.Final</netty.version>
|
||||
<spigot.version>1.18.2-R0.1-SNAPSHOT</spigot.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -71,7 +73,7 @@
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<version>3.10.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -81,7 +83,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.2.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
@@ -99,6 +101,14 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</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>
|
||||
@@ -108,19 +118,22 @@
|
||||
<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.2.0</version>
|
||||
<version>3.3.2</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>
|
||||
Comphenix and dmulloy2. Licensed under the GNU GPL v2.
|
||||
</bottom>
|
||||
<additionalOptions>
|
||||
<additionalOption>-Xdoclint:none</additionalOption>
|
||||
</additionalOptions>
|
||||
@@ -147,8 +160,8 @@
|
||||
</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>
|
||||
<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>
|
||||
<!--<project.fullVersion>${project.version}</project.fullVersion>-->
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
@@ -182,7 +195,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
@@ -224,7 +237,7 @@
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GNU GENERAL PUBLIC LICENSE - Version 2, June 1991</name>
|
||||
<url>http://www.gnu.org/licenses/gpl-2.0.txt</url>
|
||||
<url>https://www.gnu.org/licenses/gpl-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
@@ -233,7 +246,7 @@
|
||||
<developer>
|
||||
<id>dmulloy2</id>
|
||||
<name>Dan Mulloy</name>
|
||||
<url>http://dmulloy2.net/</url>
|
||||
<url>https://dmulloy2.net/</url>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
<role>maintainer</role>
|
||||
@@ -243,7 +256,7 @@
|
||||
<id>aadnk</id>
|
||||
<name>Kristian S. Stangeland</name>
|
||||
<email>kr_stang@hotmail.com</email>
|
||||
<url>http://comphenix.net/</url>
|
||||
<url>https://comphenix.net/</url>
|
||||
<roles>
|
||||
<role>former author</role>
|
||||
</roles>
|
||||
@@ -254,18 +267,18 @@
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>dmulloy2-releases</id>
|
||||
<url>https://repo.dmulloy2.net/nexus/repository/releases/</url>
|
||||
<url>https://repo.dmulloy2.net/repository/releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>dmulloy2-snapshots</id>
|
||||
<url>https://repo.dmulloy2.net/nexus/repository/snapshots/</url>
|
||||
<url>https://repo.dmulloy2.net/repository/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/nexus/repository/public/</url>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
@@ -274,55 +287,88 @@
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Compile with the old version of Netty for backwards compat -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.0.23.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- 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>
|
||||
</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.9.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy -->
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.10.16</version>
|
||||
<version>1.12.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing dependencies -->
|
||||
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<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>3.5.10</version>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<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>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito2</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<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>
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.comphenix.protocol;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
@@ -31,13 +32,16 @@ import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.libs.org.apache.commons.io.HexDump;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
@@ -47,6 +51,8 @@ import org.bukkit.plugin.Plugin;
|
||||
public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
public static final String NAME = "packetlog";
|
||||
|
||||
private static MethodAccessor HEX_DUMP;
|
||||
|
||||
private List<PacketType> sendingTypes = new ArrayList<>();
|
||||
private List<PacketType> receivingTypes = new ArrayList<>();
|
||||
|
||||
@@ -199,7 +205,13 @@ public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
|
||||
private static String hexDump(byte[] bytes) throws IOException {
|
||||
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
HexDump.dump(bytes, 0, output, 0);
|
||||
if (HEX_DUMP == null) {
|
||||
Class<?> hexDumpClass = MinecraftReflection.getLibraryClass("org.apache.commons.io.HexDump");
|
||||
HEX_DUMP = Accessors.getMethodAccessor(FuzzyReflection.fromClass(hexDumpClass)
|
||||
.getMethodByParameters("dump", byte[].class, long.class, OutputStream.class, int.class));
|
||||
}
|
||||
|
||||
HEX_DUMP.invoke(null, bytes, 0, output, 0);
|
||||
return new String(output.toByteArray(), Charsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.function.Consumer;
|
||||
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
|
||||
import com.comphenix.protocol.events.ConnectionSide;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.utility.Constants;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.base.Preconditions;
|
||||
@@ -107,93 +108,105 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x02, "SpawnEntityLiving", "SPacketSpawnMob");
|
||||
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x03, "SpawnEntityPainting", "SPacketSpawnPainting");
|
||||
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x04, "NamedEntitySpawn", "SPacketSpawnPlayer");
|
||||
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x05, "Animation", "SPacketAnimation");
|
||||
public static final PacketType STATISTIC = new PacketType(PROTOCOL, SENDER, 0x06, "Statistic", "SPacketStatistics");
|
||||
public static final PacketType BLOCK_BREAK = new PacketType(PROTOCOL, SENDER, 0x07, "BlockBreak");
|
||||
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x08, "BlockBreakAnimation", "SPacketBlockBreakAnim");
|
||||
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x09, "TileEntityData", "SPacketUpdateTileEntity");
|
||||
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x0A, "BlockAction", "SPacketBlockAction");
|
||||
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x0B, "BlockChange", "SPacketBlockChange");
|
||||
public static final PacketType BOSS = new PacketType(PROTOCOL, SENDER, 0x0C, "Boss", "SPacketUpdateBossInfo");
|
||||
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x0D, "ServerDifficulty", "SPacketServerDifficulty");
|
||||
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x0E, "Chat", "SPacketChat");
|
||||
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x0F, "TabComplete", "SPacketTabComplete");
|
||||
public static final PacketType COMMANDS = new PacketType(PROTOCOL, SENDER, 0x10, "Commands");
|
||||
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x11, "Transaction", "SPacketConfirmTransaction");
|
||||
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x12, "CloseWindow", "SPacketCloseWindow");
|
||||
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x13, "WindowItems", "SPacketWindowItems");
|
||||
public static final PacketType WINDOW_DATA = new PacketType(PROTOCOL, SENDER, 0x14, "WindowData", "SPacketWindowProperty");
|
||||
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x15, "SetSlot", "SPacketSetSlot");
|
||||
public static final PacketType SET_COOLDOWN = new PacketType(PROTOCOL, SENDER, 0x16, "SetCooldown", "SPacketCooldown");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x17, "CustomPayload", "SPacketCustomPayload");
|
||||
public static final PacketType CUSTOM_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x18, "CustomSoundEffect", "SPacketCustomSound");
|
||||
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x19, "KickDisconnect", "SPacketDisconnect");
|
||||
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1A, "EntityStatus", "SPacketEntityStatus");
|
||||
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x1B, "Explosion", "SPacketExplosion");
|
||||
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x1C, "UnloadChunk", "SPacketUnloadChunk");
|
||||
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x1D, "GameStateChange", "SPacketChangeGameState");
|
||||
public static final PacketType OPEN_WINDOW_HORSE = new PacketType(PROTOCOL, SENDER, 0x1E, "OpenWindowHorse");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x1F, "KeepAlive", "SPacketKeepAlive");
|
||||
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x20, "MapChunk", "SPacketChunkData");
|
||||
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x21, "WorldEvent", "SPacketEffect");
|
||||
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x22, "WorldParticles", "SPacketParticles");
|
||||
public static final PacketType LIGHT_UPDATE = new PacketType(PROTOCOL, SENDER, 0x23, "LightUpdate");
|
||||
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x24, "Login", "SPacketJoinGame");
|
||||
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x25, "Map", "SPacketMaps");
|
||||
public static final PacketType OPEN_WINDOW_MERCHANT = new PacketType(PROTOCOL, SENDER, 0x26, "OpenWindowMerchant");
|
||||
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x27, "Entity$RelEntityMove", "SPacketEntity$S15PacketEntityRelMove");
|
||||
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x28, "Entity$RelEntityMoveLook", "SPacketEntity$S17PacketEntityLookMove");
|
||||
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x29, "Entity$EntityLook", "SPacketEntity$S16PacketEntityLook");
|
||||
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x2A, "Entity", "SPacketEntity");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x2B, "VehicleMove", "SPacketMoveVehicle");
|
||||
public static final PacketType OPEN_BOOK = new PacketType(PROTOCOL, SENDER, 0x2C, "OpenBook");
|
||||
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2D, "OpenWindow", "SPacketOpenWindow");
|
||||
public static final PacketType OPEN_SIGN_EDITOR = new PacketType(PROTOCOL, SENDER, 0x2E, "OpenSignEditor", "SPacketSignEditorOpen");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x2F, "AutoRecipe", "SPacketPlaceGhostRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x30, "Abilities", "SPacketPlayerAbilities");
|
||||
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 0x31, "CombatEvent", "SPacketCombatEvent");
|
||||
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x32, "PlayerInfo", "SPacketPlayerListItem");
|
||||
public static final PacketType LOOK_AT = new PacketType(PROTOCOL, SENDER, 0x33, "LookAt", "SPacketPlayerPosLook");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x34, "Position");
|
||||
public static final PacketType RECIPES = new PacketType(PROTOCOL, SENDER, 0x35, "Recipes", "SPacketRecipeBook");
|
||||
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x36, "EntityDestroy", "SPacketDestroyEntities");
|
||||
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x37, "RemoveEntityEffect", "SPacketRemoveEntityEffect");
|
||||
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x38, "ResourcePackSend", "SPacketResourcePackSend");
|
||||
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x39, "Respawn", "SPacketRespawn");
|
||||
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x3A, "EntityHeadRotation", "SPacketEntityHeadLook");
|
||||
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x3B, "MultiBlockChange", "SPacketMultiBlockChange");
|
||||
public static final PacketType SELECT_ADVANCEMENT_TAB = new PacketType(PROTOCOL, SENDER, 0x3C, "SelectAdvancementTab", "SPacketSelectAdvancementsTab");
|
||||
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 0x3D, "WorldBorder", "SPacketWorldBorder");
|
||||
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x3E, "Camera", "SPacketCamera");
|
||||
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x3F, "HeldItemSlot", "SPacketHeldItemChange");
|
||||
public static final PacketType VIEW_CENTRE = new PacketType(PROTOCOL, SENDER, 0x40, "ViewCentre");
|
||||
public static final PacketType VIEW_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x41, "ViewDistance");
|
||||
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x42, "SpawnPosition", "SPacketSpawnPosition");
|
||||
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x43, "ScoreboardDisplayObjective", "SPacketDisplayObjective");
|
||||
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x44, "EntityMetadata", "SPacketEntityMetadata");
|
||||
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x45, "AttachEntity", "SPacketEntityAttach");
|
||||
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x46, "EntityVelocity", "SPacketEntityVelocity");
|
||||
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x47, "EntityEquipment", "SPacketEntityEquipment");
|
||||
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x48, "Experience", "SPacketSetExperience");
|
||||
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x49, "UpdateHealth", "SPacketUpdateHealth");
|
||||
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x4A, "ScoreboardObjective", "SPacketScoreboardObjective");
|
||||
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x4B, "Mount", "SPacketSetPassengers");
|
||||
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x4C, "ScoreboardTeam", "SPacketTeams");
|
||||
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x4D, "ScoreboardScore", "SPacketUpdateScore");
|
||||
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x4E, "UpdateTime", "SPacketTimeUpdate");
|
||||
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x4F, "Title", "SPacketTitle");
|
||||
public static final PacketType ENTITY_SOUND = new PacketType(PROTOCOL, SENDER, 0x50, "EntitySound", "SPacketSoundEffect");
|
||||
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x51, "NamedSoundEffect");
|
||||
public static final PacketType STOP_SOUND = new PacketType(PROTOCOL, SENDER, 0x52, "StopSound");
|
||||
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x53, "PlayerListHeaderFooter", "SPacketPlayerListHeaderFooter");
|
||||
public static final PacketType NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x54, "NBTQuery");
|
||||
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x55, "Collect", "SPacketCollectItem");
|
||||
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x56, "EntityTeleport", "SPacketEntityTeleport");
|
||||
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x57, "Advancements", "SPacketAdvancementInfo");
|
||||
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x58, "UpdateAttributes", "SPacketEntityProperties");
|
||||
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x59, "EntityEffect", "SPacketEntityEffect");
|
||||
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x5A, "RecipeUpdate");
|
||||
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x5B, "Tags");
|
||||
public static final PacketType ADD_VIBRATION_SIGNAL = new PacketType(PROTOCOL, SENDER, 0x05, "AddVibrationSignal");
|
||||
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x06, "Animation", "SPacketAnimation");
|
||||
public static final PacketType STATISTIC = new PacketType(PROTOCOL, SENDER, 0x07, "Statistic", "SPacketStatistics");
|
||||
public static final PacketType BLOCK_BREAK = new PacketType(PROTOCOL, SENDER, 0x08, "BlockBreak");
|
||||
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x09, "BlockBreakAnimation", "SPacketBlockBreakAnim");
|
||||
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x0A, "TileEntityData", "SPacketUpdateTileEntity");
|
||||
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x0B, "BlockAction", "SPacketBlockAction");
|
||||
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x0C, "BlockChange", "SPacketBlockChange");
|
||||
public static final PacketType BOSS = new PacketType(PROTOCOL, SENDER, 0x0D, "Boss", "SPacketUpdateBossInfo");
|
||||
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x0E, "ServerDifficulty", "SPacketServerDifficulty");
|
||||
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x0F, "Chat", "SPacketChat");
|
||||
public static final PacketType CLEAR_TITLES = new PacketType(PROTOCOL, SENDER, 0x10, "ClearTitles");
|
||||
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x11, "TabComplete", "SPacketTabComplete");
|
||||
public static final PacketType COMMANDS = new PacketType(PROTOCOL, SENDER, 0x12, "Commands");
|
||||
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x13, "CloseWindow", "SPacketCloseWindow");
|
||||
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x14, "WindowItems", "SPacketWindowItems");
|
||||
public static final PacketType WINDOW_DATA = new PacketType(PROTOCOL, SENDER, 0x15, "WindowData", "SPacketWindowProperty");
|
||||
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x16, "SetSlot", "SPacketSetSlot");
|
||||
public static final PacketType SET_COOLDOWN = new PacketType(PROTOCOL, SENDER, 0x17, "SetCooldown", "SPacketCooldown");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x18, "CustomPayload", "SPacketCustomPayload");
|
||||
public static final PacketType CUSTOM_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x19, "CustomSoundEffect", "SPacketCustomSound");
|
||||
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x1A, "KickDisconnect", "SPacketDisconnect");
|
||||
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1B, "EntityStatus", "SPacketEntityStatus");
|
||||
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x1C, "Explosion", "SPacketExplosion");
|
||||
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x1D, "UnloadChunk", "SPacketUnloadChunk");
|
||||
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x1E, "GameStateChange", "SPacketChangeGameState");
|
||||
public static final PacketType OPEN_WINDOW_HORSE = new PacketType(PROTOCOL, SENDER, 0x1F, "OpenWindowHorse");
|
||||
public static final PacketType INITIALIZE_BORDER = new PacketType(PROTOCOL, SENDER, 0x20, "InitializeBorder");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x21, "KeepAlive", "SPacketKeepAlive");
|
||||
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x22, "MapChunk", "SPacketChunkData", "LevelChunkWithLight");
|
||||
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x23, "WorldEvent", "SPacketEffect");
|
||||
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x24, "WorldParticles", "SPacketParticles");
|
||||
public static final PacketType LIGHT_UPDATE = new PacketType(PROTOCOL, SENDER, 0x25, "LightUpdate");
|
||||
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x26, "Login", "SPacketJoinGame");
|
||||
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x27, "Map", "SPacketMaps");
|
||||
public static final PacketType OPEN_WINDOW_MERCHANT = new PacketType(PROTOCOL, SENDER, 0x28, "OpenWindowMerchant");
|
||||
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x29, "Entity$PacketPlayOutRelEntityMove", "Entity$RelEntityMove");
|
||||
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x2A, "Entity$PacketPlayOutRelEntityMoveLook", "Entity$RelEntityMoveLook");
|
||||
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x2B, "Entity$PacketPlayOutEntityLook", "Entity$EntityLook");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x2C, "VehicleMove", "SPacketMoveVehicle");
|
||||
public static final PacketType OPEN_BOOK = new PacketType(PROTOCOL, SENDER, 0x2D, "OpenBook");
|
||||
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2E, "OpenWindow", "SPacketOpenWindow");
|
||||
public static final PacketType OPEN_SIGN_EDITOR = new PacketType(PROTOCOL, SENDER, 0x2F, "OpenSignEditor", "SPacketSignEditorOpen");
|
||||
public static final PacketType PING = new PacketType(PROTOCOL, SENDER, 0x30, "Ping");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x31, "AutoRecipe", "SPacketPlaceGhostRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x32, "Abilities", "SPacketPlayerAbilities");
|
||||
public static final PacketType PLAYER_COMBAT_END = new PacketType(PROTOCOL, SENDER, 0x33, "PlayerCombatEnd");
|
||||
public static final PacketType PLAYER_COMBAT_ENTER = new PacketType(PROTOCOL, SENDER, 0x34, "PlayerCombatEnter");
|
||||
public static final PacketType PLAYER_COMBAT_KILL = new PacketType(PROTOCOL, SENDER, 0x35, "PlayerCombatKill");
|
||||
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x36, "PlayerInfo", "SPacketPlayerListItem");
|
||||
public static final PacketType LOOK_AT = new PacketType(PROTOCOL, SENDER, 0x37, "LookAt", "SPacketPlayerPosLook");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x38, "Position");
|
||||
public static final PacketType RECIPES = new PacketType(PROTOCOL, SENDER, 0x39, "Recipes", "SPacketRecipeBook");
|
||||
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x3A, "EntityDestroy", "SPacketDestroyEntities");
|
||||
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x3B, "RemoveEntityEffect", "SPacketRemoveEntityEffect");
|
||||
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x3C, "ResourcePackSend", "SPacketResourcePackSend");
|
||||
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x3D, "Respawn", "SPacketRespawn");
|
||||
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x3E, "EntityHeadRotation", "SPacketEntityHeadLook");
|
||||
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x3F, "MultiBlockChange", "SPacketMultiBlockChange");
|
||||
public static final PacketType SELECT_ADVANCEMENT_TAB = new PacketType(PROTOCOL, SENDER, 0x40, "SelectAdvancementTab", "SPacketSelectAdvancementsTab");
|
||||
public static final PacketType SET_ACTION_BAR_TEXT = new PacketType(PROTOCOL, SENDER, 0x41, "SetActionBarText");
|
||||
public static final PacketType SET_BORDER_CENTER = new PacketType(PROTOCOL, SENDER, 0x42, "SetBorderCenter");
|
||||
public static final PacketType SET_BORDER_LERP_SIZE = new PacketType(PROTOCOL, SENDER, 0x43, "SetBorderLerpSize");
|
||||
public static final PacketType SET_BORDER_SIZE = new PacketType(PROTOCOL, SENDER, 0x44, "SetBorderSize");
|
||||
public static final PacketType SET_BORDER_WARNING_DELAY = new PacketType(PROTOCOL, SENDER, 0x45, "SetBorderWarningDelay");
|
||||
public static final PacketType SET_BORDER_WARNING_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x46, "SetBorderWarningDistance");
|
||||
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x47, "Camera", "SPacketCamera");
|
||||
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x48, "HeldItemSlot", "SPacketHeldItemChange");
|
||||
public static final PacketType VIEW_CENTRE = new PacketType(PROTOCOL, SENDER, 0x49, "ViewCentre");
|
||||
public static final PacketType VIEW_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x4A, "ViewDistance");
|
||||
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x4B, "SpawnPosition", "SPacketSpawnPosition");
|
||||
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x4C, "ScoreboardDisplayObjective", "SPacketDisplayObjective");
|
||||
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x4D, "EntityMetadata", "SPacketEntityMetadata");
|
||||
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x4E, "AttachEntity", "SPacketEntityAttach");
|
||||
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x4F, "EntityVelocity", "SPacketEntityVelocity");
|
||||
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x50, "EntityEquipment", "SPacketEntityEquipment");
|
||||
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x51, "Experience", "SPacketSetExperience");
|
||||
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x52, "UpdateHealth", "SPacketUpdateHealth");
|
||||
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x53, "ScoreboardObjective", "SPacketScoreboardObjective");
|
||||
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x54, "Mount", "SPacketSetPassengers");
|
||||
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x55, "ScoreboardTeam", "SPacketTeams");
|
||||
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x56, "ScoreboardScore", "SPacketUpdateScore");
|
||||
public static final PacketType UPDATE_SIMULATION_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x57, "SetSimulationDistance");
|
||||
public static final PacketType SET_SUBTITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x58, "SetSubtitleText");
|
||||
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x59, "UpdateTime", "SPacketTimeUpdate");
|
||||
public static final PacketType SET_TITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x5A, "SetTitleText");
|
||||
public static final PacketType SET_TITLES_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x5B, "SetTitlesAnimation");
|
||||
public static final PacketType ENTITY_SOUND = new PacketType(PROTOCOL, SENDER, 0x5C, "EntitySound", "SPacketSoundEffect");
|
||||
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x5D, "NamedSoundEffect");
|
||||
public static final PacketType STOP_SOUND = new PacketType(PROTOCOL, SENDER, 0x5E, "StopSound");
|
||||
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x5F, "PlayerListHeaderFooter", "SPacketPlayerListHeaderFooter");
|
||||
public static final PacketType NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x60, "NBTQuery");
|
||||
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x61, "Collect", "SPacketCollectItem");
|
||||
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x62, "EntityTeleport", "SPacketEntityTeleport");
|
||||
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x63, "Advancements", "SPacketAdvancementInfo");
|
||||
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x64, "UpdateAttributes", "SPacketEntityProperties");
|
||||
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x65, "EntityEffect", "SPacketEntityEffect");
|
||||
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x66, "RecipeUpdate");
|
||||
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x67, "Tags");
|
||||
|
||||
// ---- Removed in 1.9
|
||||
|
||||
@@ -256,7 +269,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
* @deprecated Removed in 1.14
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x33, "Bed", "SPacketUseBed");
|
||||
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 251, "Bed", "SPacketUseBed");
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link #BED}
|
||||
@@ -268,7 +281,37 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
* @deprecated Removed in 1.16
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x02, "SpawnEntityWeather", "SPacketSpawnGlobalEntity");
|
||||
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 250, "SpawnEntityWeather", "SPacketSpawnGlobalEntity");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17, split into separate packets
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 249, "Title");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17, split into separate packets
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 248, "WorldBorder");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17, split into separate packets
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 247, "CombatEvent");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 246, "Transaction", "SPacketConfirmTransaction");
|
||||
|
||||
/**
|
||||
* @deprecated Made abstract in 1.17, no actual packet anymore
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 245, "Entity", "SPacketEntity");
|
||||
|
||||
private final static Server INSTANCE = new Server();
|
||||
|
||||
@@ -297,29 +340,29 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x04, "ClientCommand", "CPacketClientStatus");
|
||||
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x05, "Settings", "CPacketClientSettings");
|
||||
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x06, "TabComplete", "CPacketTabComplete");
|
||||
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x07, "Transaction", "CPacketConfirmTransaction");
|
||||
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x08, "EnchantItem", "CPacketEnchantItem");
|
||||
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x09, "WindowClick", "CPacketClickWindow");
|
||||
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x0A, "CloseWindow", "CPacketCloseWindow");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x0B, "CustomPayload", "CPacketCustomPayload");
|
||||
public static final PacketType B_EDIT = new PacketType(PROTOCOL, SENDER, 0x0C, "BEdit");
|
||||
public static final PacketType ENTITY_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x0D, "EntityNBTQuery");
|
||||
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0E, "UseEntity", "CPacketUseEntity");
|
||||
public static final PacketType JIGSAW_GENERATE = new PacketType(PROTOCOL, SENDER, 0x0F, "JigsawGenerate");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x10, "KeepAlive", "CPacketKeepAlive");
|
||||
public static final PacketType DIFFICULTY_LOCK = new PacketType(PROTOCOL, SENDER, 0x11, "DifficultyLock");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x12, "Flying$Position", "CPacketPlayer$Position");
|
||||
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x13, "Flying$PositionLook", "CPacketPlayer$PositionRotation");
|
||||
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x14, "Flying$Look", "CPacketPlayer$Rotation");
|
||||
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x15, "Flying", "CPacketPlayer");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x16, "VehicleMove", "CPacketVehicleMove");
|
||||
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x17, "BoatMove", "CPacketSteerBoat");
|
||||
public static final PacketType PICK_ITEM = new PacketType(PROTOCOL, SENDER, 0x18, "PickItem");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x19, "AutoRecipe", "CPacketPlaceRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x1A, "Abilities", "CPacketPlayerAbilities");
|
||||
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x1B, "BlockDig", "CPacketPlayerDigging");
|
||||
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x1C, "EntityAction", "CPacketEntityAction");
|
||||
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x1D, "SteerVehicle", "CPacketInput");
|
||||
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x07, "EnchantItem", "CPacketEnchantItem");
|
||||
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x08, "WindowClick", "CPacketClickWindow");
|
||||
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x09, "CloseWindow", "CPacketCloseWindow");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x0A, "CustomPayload", "CPacketCustomPayload");
|
||||
public static final PacketType B_EDIT = new PacketType(PROTOCOL, SENDER, 0x0B, "BEdit");
|
||||
public static final PacketType ENTITY_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x0C, "EntityNBTQuery");
|
||||
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0D, "UseEntity", "CPacketUseEntity");
|
||||
public static final PacketType JIGSAW_GENERATE = new PacketType(PROTOCOL, SENDER, 0x0E, "JigsawGenerate");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x0F, "KeepAlive", "CPacketKeepAlive");
|
||||
public static final PacketType DIFFICULTY_LOCK = new PacketType(PROTOCOL, SENDER, 0x10, "DifficultyLock");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x11, "Flying$PacketPlayInPosition", "Flying$Position", "CPacketPlayer$Position");
|
||||
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x12, "Flying$PacketPlayInPositionLook", "Flying$PositionLook", "CPacketPlayer$PositionRotation");
|
||||
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x13, "Flying$PacketPlayInLook", "Flying$Look", "CPacketPlayer$Rotation");
|
||||
public static final PacketType GROUND = new PacketType(PROTOCOL, SENDER, 0x14, "Flying$d");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x15, "VehicleMove", "CPacketVehicleMove");
|
||||
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x16, "BoatMove", "CPacketSteerBoat");
|
||||
public static final PacketType PICK_ITEM = new PacketType(PROTOCOL, SENDER, 0x17, "PickItem");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x18, "AutoRecipe", "CPacketPlaceRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x19, "Abilities", "CPacketPlayerAbilities");
|
||||
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x1A, "BlockDig", "CPacketPlayerDigging");
|
||||
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x1B, "EntityAction", "CPacketEntityAction");
|
||||
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x1C, "SteerVehicle", "CPacketInput");
|
||||
public static final PacketType PONG = new PacketType(PROTOCOL, SENDER, 0x1D, "Pong", "ServerboundPongPacket");
|
||||
public static final PacketType RECIPE_SETTINGS = new PacketType(PROTOCOL, SENDER, 0x1E, "RecipeSettings");
|
||||
public static final PacketType RECIPE_DISPLAYED = new PacketType(PROTOCOL, SENDER, 0x1F, "RecipeDisplayed", "CPacketRecipeInfo");
|
||||
public static final PacketType ITEM_NAME = new PacketType(PROTOCOL, SENDER, 0x20, "ItemName");
|
||||
@@ -339,6 +382,18 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x2E, "UseItem", "CPacketPlayerTryUseItemOnBlock");
|
||||
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x2F, "BlockPlace", "CPacketPlayerTryUseItem");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 255, "Transaction", "CPacketConfirmTransaction");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 254, "Flying", "CPacketPlayer");
|
||||
|
||||
private final static Client INSTANCE = new Client();
|
||||
|
||||
// Prevent accidental construction
|
||||
@@ -490,15 +545,23 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
* @author Kristian
|
||||
*/
|
||||
public enum Protocol {
|
||||
HANDSHAKING,
|
||||
PLAY,
|
||||
STATUS,
|
||||
LOGIN,
|
||||
HANDSHAKING("Handshaking", "handshake"),
|
||||
PLAY("Play", "game"),
|
||||
STATUS("Status", "status"),
|
||||
LOGIN("Login", "login"),
|
||||
|
||||
/**
|
||||
* Only for packets removed in Minecraft 1.7.2
|
||||
*/
|
||||
LEGACY;
|
||||
LEGACY("", "");
|
||||
|
||||
private String packetName;
|
||||
private String mojangName;
|
||||
|
||||
Protocol(String packetName, String mojangName) {
|
||||
this.packetName = packetName;
|
||||
this.mojangName = mojangName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the correct protocol enum from a given vanilla enum instance.
|
||||
@@ -520,7 +583,11 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
}
|
||||
|
||||
public String getPacketName() {
|
||||
return WordUtils.capitalize(name().toLowerCase(Locale.ENGLISH));
|
||||
return packetName;
|
||||
}
|
||||
|
||||
public String getMojangName() {
|
||||
return mojangName;
|
||||
}
|
||||
|
||||
public String getMcpPacketName() {
|
||||
@@ -537,12 +604,22 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
/**
|
||||
* Indicates that packets of this type will be sent by connected clients.
|
||||
*/
|
||||
CLIENT,
|
||||
CLIENT("Serverbound", "In", "client"),
|
||||
|
||||
/**
|
||||
* Indicate that packets of this type will be sent by the current server.
|
||||
*/
|
||||
SERVER;
|
||||
SERVER("Clientbound", "Out", "server");
|
||||
|
||||
private String mojangName;
|
||||
private String packetName;
|
||||
private String mcpName;
|
||||
|
||||
Sender(String mojangName, String packetName, String mcpName) {
|
||||
this.mojangName = mojangName;
|
||||
this.packetName = packetName;
|
||||
this.mcpName = mcpName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the equivialent connection side.
|
||||
@@ -553,11 +630,15 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
}
|
||||
|
||||
public String getPacketName() {
|
||||
return this == CLIENT ? "In" : "Out";
|
||||
return packetName;
|
||||
}
|
||||
|
||||
public String getMcpPacketName() {
|
||||
return name().toLowerCase(Locale.ENGLISH);
|
||||
return mcpName;
|
||||
}
|
||||
|
||||
public String getMojangName() {
|
||||
return mojangName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,13 +655,13 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
/**
|
||||
* Protocol version of all the current IDs.
|
||||
*/
|
||||
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.NETHER_UPDATE;
|
||||
private static final MinecraftVersion PROTOCOL_VERSION = Constants.CURRENT_VERSION;
|
||||
|
||||
private final Protocol protocol;
|
||||
private final Sender sender;
|
||||
private final int currentId;
|
||||
private final MinecraftVersion version;
|
||||
private final String[] classNames;
|
||||
private final List<String> classNames;
|
||||
String[] names;
|
||||
|
||||
private String name;
|
||||
@@ -710,7 +791,17 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatMojangClassName(Protocol protocol, Sender sender, String name) {
|
||||
return "net.minecraft.network.protocol." + protocol.getMojangName() + "." + sender.getMojangName()
|
||||
+ name + "Packet";
|
||||
}
|
||||
|
||||
private static String formatClassName(Protocol protocol, Sender sender, String name) {
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
return "net.minecraft.network.protocol." + protocol.getMojangName() + ".Packet"
|
||||
+ protocol.getPacketName() + sender.getPacketName() + name;
|
||||
}
|
||||
|
||||
String base = MinecraftReflection.getMinecraftPackage() + ".Packet";
|
||||
if (name.startsWith(base)) {
|
||||
return name;
|
||||
@@ -810,8 +901,8 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
|
||||
// Check any aliases
|
||||
for (PacketType check : map.values()) {
|
||||
String[] aliases = check.getClassNames();
|
||||
if (aliases.length > 1) {
|
||||
List<String> aliases = check.getClassNames();
|
||||
if (aliases.size() > 1) {
|
||||
for (String alias : aliases) {
|
||||
if (alias.equals(clazz)) {
|
||||
// We have a match!
|
||||
@@ -852,7 +943,9 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
* Determine if a given class represents a packet class.
|
||||
* @param packetClass - the class to lookup.
|
||||
* @return TRUE if this is a packet class, FALSE otherwise.
|
||||
* @deprecated Doesn't really have a purpose
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean hasClass(Class<?> packetClass) {
|
||||
return PacketRegistry.getPacketType(packetClass) != null;
|
||||
}
|
||||
@@ -931,12 +1024,13 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
this.currentId = currentId;
|
||||
this.version = version;
|
||||
|
||||
this.classNames = new String[names.length];
|
||||
for (int i = 0; i < classNames.length; i++) {
|
||||
this.classNames = new ArrayList<>();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (isMcpPacketName(names[i])) { // Minecraft MCP packets
|
||||
classNames[i] = formatMcpClassName(protocol, sender, names[i]);
|
||||
classNames.add(formatMcpClassName(protocol, sender, names[i]));
|
||||
} else {
|
||||
classNames[i] = formatClassName(protocol, sender, names[i]);
|
||||
classNames.add(formatClassName(protocol, sender, names[i]));
|
||||
classNames.add(formatMojangClassName(protocol, sender, names[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -997,7 +1091,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
return currentId;
|
||||
}
|
||||
|
||||
public String[] getClassNames() {
|
||||
public List<String> getClassNames() {
|
||||
return classNames;
|
||||
}
|
||||
|
||||
@@ -1006,11 +1100,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
* @return The packet class, or NULL if not found.
|
||||
*/
|
||||
public Class<?> getPacketClass() {
|
||||
try {
|
||||
return PacketRegistry.getPacketClassFromType(this);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
return PacketRegistry.tryGetPacketClass(this).orElse(null);
|
||||
}
|
||||
|
||||
// Only used by Enum processor
|
||||
@@ -1112,7 +1202,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
Class<?> clazz = getPacketClass();
|
||||
|
||||
if (clazz == null)
|
||||
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + Arrays.toString(classNames) + " (unregistered)]";
|
||||
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + classNames + " (unregistered)]";
|
||||
else
|
||||
return name() + "[class=" + clazz.getSimpleName() + ", id=" + currentId + "]";
|
||||
}
|
||||
|
||||
@@ -110,22 +110,6 @@ public class PacketTypeEnum implements Iterable<PacketType> {
|
||||
public boolean hasMember(PacketType member) {
|
||||
return members.contains(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a member by name,
|
||||
* @param name - name of member to retrieve.
|
||||
* @return The member, or NULL if not found.
|
||||
* @deprecated Don't use this
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketType valueOf(String name) {
|
||||
for (PacketType member : members) {
|
||||
if (member.name().equals(name))
|
||||
return member;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every registered member.
|
||||
|
||||
@@ -108,7 +108,7 @@ class PacketTypeLookup {
|
||||
// Skip unknown current packets
|
||||
if (type.getCurrentId() != PacketType.UNKNOWN_PACKET) {
|
||||
idLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
|
||||
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames()[0], type);
|
||||
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames().get(0), type);
|
||||
}
|
||||
nameLookup.put(type.name(), type);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.comphenix.protocol.updater.Updater;
|
||||
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||
import com.comphenix.protocol.utility.ChatExtensions;
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.NettyVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -170,7 +171,11 @@ public class ProtocolLib extends JavaPlugin {
|
||||
// Print the state of the debug mode
|
||||
if (config.isDebug()) {
|
||||
logger.warning("Debug mode is enabled!");
|
||||
logger.info("Detected netty version: " + NettyVersion.getVersion());
|
||||
} else {
|
||||
NettyVersion.getVersion(); // this will cache the version
|
||||
}
|
||||
|
||||
// And the state of the error reporter
|
||||
if (config.isDetailedErrorReporting()) {
|
||||
detailedReporter.setDetailedReporting(true);
|
||||
|
||||
@@ -38,12 +38,12 @@ public class ProtocolLibrary {
|
||||
/**
|
||||
* The maximum version ProtocolLib has been tested with.
|
||||
*/
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.16.5";
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.18.2";
|
||||
|
||||
/**
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.16.5) was released.
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.18.2) was released.
|
||||
*/
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2021-01-15";
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2022-02-28";
|
||||
|
||||
/**
|
||||
* Plugins that are currently incompatible with ProtocolLib.
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.text.MessageFormat;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
@@ -82,4 +83,10 @@ public class ProtocolLogger {
|
||||
logger.log(Level.WARNING, "[Debug] " + message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void warnAbove(MinecraftVersion version, String message, Object... args) {
|
||||
if (version.atOrAbove()) {
|
||||
log(Level.WARNING, message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,11 +32,11 @@ public class PacketTypeSet {
|
||||
* @param type - the type to add.
|
||||
*/
|
||||
public synchronized void addType(PacketType type) {
|
||||
Class<?> packetClass = getPacketClass(type);
|
||||
Class<?> packetClass = type.getPacketClass();
|
||||
types.add(Preconditions.checkNotNull(type, "type cannot be NULL."));
|
||||
|
||||
if (packetClass != null) {
|
||||
classes.add(getPacketClass(type));
|
||||
classes.add(type.getPacketClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +55,11 @@ public class PacketTypeSet {
|
||||
* @param type - the type to remove.
|
||||
*/
|
||||
public synchronized void removeType(PacketType type) {
|
||||
Class<?> packetClass = getPacketClass(type);
|
||||
Class<?> packetClass = type.getPacketClass();
|
||||
types.remove(Preconditions.checkNotNull(type, "type cannot be NULL."));
|
||||
|
||||
if (packetClass != null) {
|
||||
classes.remove(getPacketClass(type));
|
||||
classes.remove(packetClass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,16 +72,7 @@ public class PacketTypeSet {
|
||||
removeType(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the packet class associated with a particular type.
|
||||
* @param type - the packet type.
|
||||
* @return The associated packet type.
|
||||
*/
|
||||
protected Class<?> getPacketClass(PacketType type) {
|
||||
return PacketRegistry.getPacketClassFromType(type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the given packet type exists in the set.
|
||||
* @param type - the type to find.
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,45 @@
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class InternalStructure extends AbstractStructure {
|
||||
|
||||
protected InternalStructure(Object handle, StructureModifier<Object> structureModifier) {
|
||||
super(handle, structureModifier);
|
||||
}
|
||||
|
||||
protected static final EquivalentConverter<InternalStructure> CONVERTER = new EquivalentConverter<InternalStructure>() {
|
||||
@Override
|
||||
public Object getGeneric(InternalStructure specific) {
|
||||
return specific.handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalStructure getSpecific(Object generic) {
|
||||
return new InternalStructure(generic, new StructureModifier<>(generic.getClass()).withTarget(generic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<InternalStructure> getSpecificType() {
|
||||
return InternalStructure.class;
|
||||
}
|
||||
};
|
||||
|
||||
public StructureModifier<InternalStructure> getStructures() {
|
||||
return structureModifier.withType(Object.class, CONVERTER);
|
||||
}
|
||||
|
||||
public StructureModifier<Optional<InternalStructure>> getOptionalStructures() {
|
||||
return structureModifier.withType(Optional.class, Converters.optional(CONVERTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InternalStructure[handle=" + handle + " (" + handle.getClass().getSimpleName() + ")]";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -45,6 +45,7 @@ import net.bytebuddy.matcher.ElementMatchers;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
|
||||
@@ -176,7 +177,12 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
public UUID getUniqueId() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PlayerProfile getPlayerProfile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -27,6 +28,7 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftFields;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.WrappedIntHashMap;
|
||||
@@ -66,7 +68,10 @@ class EntityUtilities {
|
||||
Collection<?> trackedPlayers = getTrackedPlayers(entity);
|
||||
List<Object> nmsPlayers = unwrapBukkit(observers);
|
||||
|
||||
trackedPlayers.removeAll(nmsPlayers);
|
||||
List<Object> removingEntries = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove() ?
|
||||
getPlayerConnections(nmsPlayers) : nmsPlayers;
|
||||
|
||||
trackedPlayers.removeAll(removingEntries);
|
||||
|
||||
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
|
||||
|
||||
@@ -102,7 +107,9 @@ class EntityUtilities {
|
||||
|
||||
// Wrap every player - we also ensure that the underlying tracker list is immutable
|
||||
for (Object tracker : trackedPlayers) {
|
||||
if (MinecraftReflection.isMinecraftPlayer(tracker)) {
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove() && MinecraftReflection.isServerHandler(tracker)) {
|
||||
result.add(MinecraftReflection.getBukkitPlayerFromConnection(tracker));
|
||||
} else if (MinecraftReflection.isMinecraftPlayer(tracker)) {
|
||||
result.add((Player) MinecraftReflection.getBukkitEntity(tracker));
|
||||
}
|
||||
}
|
||||
@@ -139,7 +146,7 @@ class EntityUtilities {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getNewEntityTracker(Object worldServer, int entityId) {
|
||||
if (getChunkProvider == null) {
|
||||
Class<?> chunkProviderClass = MinecraftReflection.getMinecraftClass("ChunkProviderServer");
|
||||
Class<?> chunkProviderClass = MinecraftReflection.getChunkProviderServer();
|
||||
getChunkProvider = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(worldServer.getClass(), false).getMethod(
|
||||
FuzzyMethodContract.newBuilder().parameterCount(0).returnTypeExact(chunkProviderClass).build()));
|
||||
@@ -148,7 +155,7 @@ class EntityUtilities {
|
||||
Object chunkProvider = getChunkProvider.invoke(worldServer);
|
||||
|
||||
if (chunkMapField == null) {
|
||||
Class<?> chunkMapClass = MinecraftReflection.getMinecraftClass("PlayerChunkMap");
|
||||
Class<?> chunkMapClass = MinecraftReflection.getPlayerChunkMap();
|
||||
chunkMapField = Accessors.getFieldAccessor(
|
||||
FuzzyReflection.fromClass(chunkProvider.getClass(), false).getField(
|
||||
FuzzyFieldContract.newBuilder().typeExact(chunkMapClass).build()));
|
||||
@@ -157,9 +164,21 @@ class EntityUtilities {
|
||||
Object playerChunkMap = chunkMapField.get(chunkProvider);
|
||||
|
||||
if (trackedEntitiesField == null) {
|
||||
trackedEntitiesField = Accessors.getFieldAccessor(
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
trackedEntitiesField = Accessors.getFieldAccessor(
|
||||
FuzzyReflection.fromClass(playerChunkMap.getClass(), true).getField(
|
||||
FuzzyFieldContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.requirePublic()
|
||||
.typeExact(MinecraftReflection.getInt2ObjectMapClass())
|
||||
.build()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
trackedEntitiesField = Accessors.getFieldAccessor(
|
||||
FuzzyReflection.fromClass(playerChunkMap.getClass(), false).getField(
|
||||
FuzzyFieldContract.newBuilder().typeDerivedOf(Map.class).nameExact("trackedEntities").build()));
|
||||
}
|
||||
}
|
||||
|
||||
Map<Integer, Object> trackedEntities = (Map<Integer, Object>) trackedEntitiesField.get(playerChunkMap);
|
||||
@@ -229,14 +248,17 @@ class EntityUtilities {
|
||||
Object tracker = null;
|
||||
|
||||
if (trackerEntry != null) {
|
||||
// plugins like citizens will use their own tracker
|
||||
// plugins like citizens will use their own tracker class, so cache the result
|
||||
FieldAccessor trackerField = trackerFields.computeIfAbsent(trackerEntry.getClass(), x -> {
|
||||
// get the first entity field
|
||||
try {
|
||||
return Accessors.getFieldAccessor(trackerEntry.getClass(), "tracker", true);
|
||||
} catch (Exception e) {
|
||||
// Assume it's the first entity field then
|
||||
return Accessors.getFieldAccessor(FuzzyReflection.fromObject(trackerEntry, true)
|
||||
.getFieldByType("tracker", MinecraftReflection.getEntityClass()));
|
||||
return Accessors.getFieldAccessor(FuzzyReflection.fromClass(trackerEntry.getClass(), true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(MinecraftReflection.getEntityClass()).build()));
|
||||
} catch (Exception ex) {
|
||||
// try with the default class
|
||||
Class<?> trackerEntryClass = MinecraftReflection.getEntityTrackerClass();
|
||||
return Accessors.getFieldAccessor(FuzzyReflection.fromClass(trackerEntryClass, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(MinecraftReflection.getEntityClass()).build()));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -250,6 +272,12 @@ class EntityUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
private List<Object> getPlayerConnections(List<Object> nmsPlayers) {
|
||||
List<Object> connections = new ArrayList<>(nmsPlayers.size());
|
||||
nmsPlayers.forEach(nmsPlayer -> connections.add(MinecraftFields.getPlayerConnection(nmsPlayer)));
|
||||
return connections;
|
||||
}
|
||||
|
||||
private List<Object> unwrapBukkit(List<Player> players) {
|
||||
List<Object> output = Lists.newArrayList();
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
|
||||
@@ -39,14 +39,6 @@ public interface ListenerInvoker {
|
||||
*/
|
||||
void invokePacketSending(PacketEvent event);
|
||||
|
||||
/**
|
||||
* Retrieve the associated ID of a packet.
|
||||
* @param packet - the packet.
|
||||
* @return The packet ID.
|
||||
*/
|
||||
@Deprecated
|
||||
int getPacketID(Object packet);
|
||||
|
||||
/**
|
||||
* Retrieve the associated type of a packet.
|
||||
* @param packet - the packet.
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.comphenix.protocol.injector;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.error.RethrowErrorReporter;
|
||||
@@ -146,13 +147,11 @@ public class PacketConstructor {
|
||||
types[i] = Object.class;
|
||||
}
|
||||
}
|
||||
Class<?> packetType = PacketRegistry.getPacketClassFromType(type, true);
|
||||
|
||||
if (packetType == null)
|
||||
throw new IllegalArgumentException("Could not find a packet by the type " + type);
|
||||
|
||||
|
||||
Class<?> packetClass = PacketRegistry.getPacketClassFromType(type);
|
||||
|
||||
// Find the correct constructor
|
||||
for (Constructor<?> constructor : packetType.getConstructors()) {
|
||||
for (Constructor<?> constructor : packetClass.getConstructors()) {
|
||||
Class<?>[] params = constructor.getParameterTypes();
|
||||
|
||||
if (isCompatible(types, params)) {
|
||||
|
||||
@@ -979,12 +979,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
return phaseLoginCount.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getPacketID(Object packet) {
|
||||
return PacketRegistry.getPacketID(packet.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketType getPacketType(Object packet) {
|
||||
if (packet == null)
|
||||
|
||||
@@ -19,17 +19,29 @@ package com.comphenix.protocol.injector;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
||||
import com.comphenix.protocol.reflect.compiler.CompileListener;
|
||||
import com.comphenix.protocol.reflect.compiler.CompiledStructureModifier;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.ZeroBuffer;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
/**
|
||||
* Caches structure modifiers.
|
||||
@@ -37,9 +49,42 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
*/
|
||||
public class StructureCache {
|
||||
// Structure modifiers
|
||||
private static ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
|
||||
// invocation cache for packets
|
||||
private static final ConcurrentMap<Class<?>, Supplier<Object>> PACKET_INSTANCE_CREATORS = new ConcurrentHashMap<>();
|
||||
// packet data serializer which always returns an empty nbt tag compound
|
||||
private static boolean trickTried;
|
||||
private static ConstructorAccessor TRICKED_DATA_SERIALIZER;
|
||||
|
||||
private static Set<PacketType> compiling = new HashSet<>();
|
||||
private static final Set<PacketType> compiling = new HashSet<>();
|
||||
|
||||
public static Object newPacket(Class<?> clazz) {
|
||||
Object result = DefaultInstances.DEFAULT.create(clazz);
|
||||
|
||||
if (result == null) {
|
||||
return PACKET_INSTANCE_CREATORS.computeIfAbsent(clazz, $ -> {
|
||||
ConstructorAccessor accessor = Accessors.getConstructorAccessorOrNull(clazz, MinecraftReflection.getPacketDataSerializerClass());
|
||||
if (accessor != null) {
|
||||
return () -> {
|
||||
try {
|
||||
return accessor.invoke(MinecraftReflection.getPacketDataSerializer(new ZeroBuffer()));
|
||||
} catch (Exception exception) {
|
||||
// try trick nms around as they want a non-null compound in the map_chunk packet constructor
|
||||
ConstructorAccessor trickyDataSerializerAccessor = getTrickDataSerializerOrNull();
|
||||
if (trickyDataSerializerAccessor != null) {
|
||||
return accessor.invoke(trickyDataSerializerAccessor.invoke(new ZeroBuffer()));
|
||||
}
|
||||
// the tricks are over
|
||||
throw new IllegalArgumentException("Unable to create packet " + clazz, exception);
|
||||
}
|
||||
};
|
||||
}
|
||||
throw new IllegalArgumentException("No matching constructor to create packet in class " + clazz);
|
||||
}).get();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty Minecraft packet of the given type.
|
||||
@@ -47,20 +92,7 @@ public class StructureCache {
|
||||
* @return Created packet.
|
||||
*/
|
||||
public static Object newPacket(PacketType type) {
|
||||
Class<?> clazz = PacketRegistry.getPacketClassFromType(type, true);
|
||||
|
||||
// Check the return value
|
||||
if (clazz != null) {
|
||||
// TODO: Optimize DefaultInstances
|
||||
Object result = DefaultInstances.DEFAULT.create(clazz);
|
||||
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("Failed to create packet for type: " + type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot find associated packet class: " + type);
|
||||
return newPacket(PacketRegistry.getPacketClassFromType(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +123,9 @@ public class StructureCache {
|
||||
*/
|
||||
public static StructureModifier<Object> getStructure(Class<?> packetType, boolean compile) {
|
||||
// Get the ID from the class
|
||||
return getStructure(PacketRegistry.getPacketType(packetType), compile);
|
||||
PacketType type = PacketRegistry.getPacketType(packetType);
|
||||
Preconditions.checkNotNull(type, "No packet type associated with " + packetType);
|
||||
return getStructure(type, compile);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,13 +135,14 @@ public class StructureCache {
|
||||
* @return A structure modifier.
|
||||
*/
|
||||
public static StructureModifier<Object> getStructure(final PacketType type, boolean compile) {
|
||||
Preconditions.checkNotNull(type, "type cannot be null");
|
||||
StructureModifier<Object> result = structureModifiers.get(type);
|
||||
|
||||
// We don't want to create this for every lookup
|
||||
if (result == null) {
|
||||
// Use the vanilla class definition
|
||||
final StructureModifier<Object> value = new StructureModifier<Object>(
|
||||
PacketRegistry.getPacketClassFromType(type, true), MinecraftReflection.getPacketClass(), true);
|
||||
final StructureModifier<Object> value = new StructureModifier<>(
|
||||
PacketRegistry.getPacketClassFromType(type), MinecraftReflection.getPacketClass(), true);
|
||||
|
||||
result = structureModifiers.putIfAbsent(type, value);
|
||||
|
||||
@@ -124,16 +159,42 @@ public class StructureCache {
|
||||
final BackgroundCompiler compiler = BackgroundCompiler.getInstance();
|
||||
|
||||
if (!compiling.contains(type) && compiler != null) {
|
||||
compiler.scheduleCompilation(result, new CompileListener<Object>() {
|
||||
@Override
|
||||
public void onCompiled(StructureModifier<Object> compiledModifier) {
|
||||
structureModifiers.put(type, compiledModifier);
|
||||
}
|
||||
});
|
||||
compiler.scheduleCompilation(result,
|
||||
compiledModifier -> structureModifiers.put(type, compiledModifier));
|
||||
compiling.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a null
|
||||
* check in the MapChunk packet constructor.
|
||||
* @return an accessor to a constructor which creates a data serializer.
|
||||
*/
|
||||
private static ConstructorAccessor getTrickDataSerializerOrNull() {
|
||||
if (TRICKED_DATA_SERIALIZER == null && !trickTried) {
|
||||
// ensure that we only try once to create the class
|
||||
trickTried = true;
|
||||
try {
|
||||
// create an empty instance of a nbt tag compound that we can re-use when needed
|
||||
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
|
||||
// create the method in the class to read an empty nbt tag compound (currently used for MAP_CHUNK because of null check)
|
||||
Class<?> generatedClass = ByteBuddyFactory.getInstance()
|
||||
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
|
||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializer")
|
||||
.method(ElementMatchers.returns(MinecraftReflection.getNBTCompoundClass())
|
||||
.and(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())))
|
||||
.intercept(FixedValue.value(compound))
|
||||
.make()
|
||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
|
||||
.getLoaded();
|
||||
TRICKED_DATA_SERIALIZER = Accessors.getConstructorAccessor(generatedClass, ByteBuf.class);
|
||||
} catch (Exception ignored) {
|
||||
// can happen if unsupported
|
||||
}
|
||||
}
|
||||
return TRICKED_DATA_SERIALIZER;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.VolatileField;
|
||||
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.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.ByteBuddyGenerated;
|
||||
import com.comphenix.protocol.utility.MinecraftFields;
|
||||
@@ -44,7 +45,6 @@ import com.google.common.base.Preconditions;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.util.AttributeKey;
|
||||
@@ -57,6 +57,7 @@ import org.bukkit.entity.Player;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.*;
|
||||
@@ -85,6 +86,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
|
||||
// Versioning
|
||||
private static Class<?> PACKET_SET_PROTOCOL = null;
|
||||
private static FieldAccessor PROTOCOL_VERSION_ACCESSOR = null;
|
||||
|
||||
private static AtomicInteger keyId = new AtomicInteger();
|
||||
private static AttributeKey<Integer> PROTOCOL_KEY;
|
||||
@@ -273,7 +275,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
|
||||
super.write(ctx, packet, promise);
|
||||
ChannelInjector.this.finalWrite();
|
||||
ChannelInjector.this.finalWrite(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -542,7 +544,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
/**
|
||||
* Invoked when a packet has been written to the channel
|
||||
*/
|
||||
private void finalWrite() {
|
||||
private void finalWrite(Object packet) {
|
||||
PacketEvent event = finalEvent;
|
||||
|
||||
if (event != null) {
|
||||
@@ -551,6 +553,10 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
currentEvent = null;
|
||||
|
||||
processor.invokePostEvent(event, NetworkMarker.getNetworkMarker(event));
|
||||
|
||||
// remove the stored packet markers to prevent memory leaks
|
||||
// See: https://github.com/dmulloy2/ProtocolLib/issues/1509
|
||||
packetMarker.remove(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,15 +669,21 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
if (PACKET_SET_PROTOCOL == null) {
|
||||
try {
|
||||
PACKET_SET_PROTOCOL = PacketType.Handshake.Client.SET_PROTOCOL.getPacketClass();
|
||||
|
||||
// resolve the protocol version field here - if we're unable to find it we don't need to worry about it
|
||||
Field protocolVersionField = FuzzyReflection.fromClass(PACKET_SET_PROTOCOL, true).getField(FuzzyFieldContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.typeExact(int.class)
|
||||
.build());
|
||||
PROTOCOL_VERSION_ACCESSOR = Accessors.getFieldAccessor(protocolVersionField);
|
||||
} catch (Throwable ex) {
|
||||
PACKET_SET_PROTOCOL = getClass(); // If we can't find it don't worry about it
|
||||
}
|
||||
}
|
||||
|
||||
if (PACKET_SET_PROTOCOL.equals(packetClass)) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromObject(packet);
|
||||
try {
|
||||
int protocol = (int) fuzzy.invokeMethod(packet, "getProtocol", int.class);
|
||||
int protocol = (int) PROTOCOL_VERSION_ACCESSOR.get(packet);
|
||||
originalChannel.attr(PROTOCOL_KEY).set(protocol);
|
||||
} catch (Throwable ex) {
|
||||
// Oh well
|
||||
@@ -951,7 +963,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
|
||||
@Override
|
||||
public Socket getSocket() {
|
||||
return SocketAdapter.adapt((SocketChannel) injector.originalChannel);
|
||||
return SocketAdapter.adapt(injector.originalChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -989,6 +1001,11 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
injector.setPlayer(updatedPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return injector.originalChannel.isActive();
|
||||
}
|
||||
|
||||
ChannelInjector getChannelInjector() {
|
||||
return injector;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class NettyByteBufAdapter extends AbstractByteBuf {
|
||||
private static FieldAccessor READER_INDEX;
|
||||
private static FieldAccessor WRITER_INDEX;
|
||||
|
||||
private static final int CAPACITY = Short.MAX_VALUE;
|
||||
private static final int CAPACITY = Integer.MAX_VALUE;
|
||||
|
||||
private NettyByteBufAdapter(DataInputStream input, DataOutputStream output) {
|
||||
// Just pick a figure
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2015 dmulloy2
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.injector.netty;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.injector.packet.MapContainer;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public class NettyProtocolRegistry extends ProtocolRegistry {
|
||||
|
||||
public NettyProtocolRegistry() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void initialize() {
|
||||
if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BEE_UPDATE)) {
|
||||
initializeNew();
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] protocols = enumProtocol.getEnumConstants();
|
||||
|
||||
// ID to Packet class maps
|
||||
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
|
||||
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
|
||||
|
||||
Register result = new Register();
|
||||
StructureModifier<Object> modifier = null;
|
||||
|
||||
// Iterate through the protocols
|
||||
for (Object protocol : protocols) {
|
||||
if (modifier == null) {
|
||||
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
|
||||
}
|
||||
|
||||
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
||||
for (Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
|
||||
String direction = entry.getKey().toString();
|
||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||
serverMaps.put(protocol, entry.getValue());
|
||||
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
|
||||
clientMaps.put(protocol, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maps we have to occasionally check have changed
|
||||
for (Object map : serverMaps.values()) {
|
||||
result.containers.add(new MapContainer(map));
|
||||
}
|
||||
|
||||
for (Object map : clientMaps.values()) {
|
||||
result.containers.add(new MapContainer(map));
|
||||
}
|
||||
|
||||
for (Object protocol : protocols) {
|
||||
Enum<?> enumProtocol = (Enum<?>) protocol;
|
||||
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
|
||||
|
||||
// Associate known types
|
||||
if (serverMaps.containsKey(protocol))
|
||||
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
|
||||
if (clientMaps.containsKey(protocol))
|
||||
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
|
||||
}
|
||||
|
||||
// Exchange (thread safe, as we have only one writer)
|
||||
this.register = result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private synchronized void initializeNew() {
|
||||
Object[] protocols = enumProtocol.getEnumConstants();
|
||||
|
||||
// ID to Packet class maps
|
||||
Map<Object, Map<Class<?>, Integer>> serverMaps = Maps.newLinkedHashMap();
|
||||
Map<Object, Map<Class<?>, Integer>> clientMaps = Maps.newLinkedHashMap();
|
||||
|
||||
Register result = new Register();
|
||||
Field mainMapField = null;
|
||||
Field packetMapField = null;
|
||||
|
||||
// Iterate through the protocols
|
||||
for (Object protocol : protocols) {
|
||||
if (mainMapField == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true);
|
||||
mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.FINAL)
|
||||
.typeDerivedOf(Map.class)
|
||||
.build());
|
||||
mainMapField.setAccessible(true);
|
||||
}
|
||||
|
||||
Map<Object, Object> directionMap;
|
||||
|
||||
try {
|
||||
directionMap = (Map<Object, Object>) mainMapField.get(protocol);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to access packet map", ex);
|
||||
}
|
||||
|
||||
for (Entry<Object, Object> entry : directionMap.entrySet()) {
|
||||
Object holder = entry.getValue();
|
||||
if (packetMapField == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(holder.getClass(), true);
|
||||
packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.FINAL)
|
||||
.typeDerivedOf(Map.class)
|
||||
.build());
|
||||
packetMapField.setAccessible(true);
|
||||
}
|
||||
|
||||
Map<Class<?>, Integer> packetMap;
|
||||
|
||||
try {
|
||||
packetMap = (Map<Class<?>, Integer>) packetMapField.get(holder);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to access packet map", ex);
|
||||
}
|
||||
|
||||
String direction = entry.getKey().toString();
|
||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||
serverMaps.put(protocol, packetMap);
|
||||
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
|
||||
clientMaps.put(protocol, packetMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maps we have to occasionally check have changed
|
||||
// TODO: Find equivalent in Object2IntMap
|
||||
|
||||
/* for (Object map : serverMaps.values()) {
|
||||
result.containers.add(new MapContainer(map));
|
||||
}
|
||||
|
||||
for (Object map : clientMaps.values()) {
|
||||
result.containers.add(new MapContainer(map));
|
||||
} */
|
||||
|
||||
for (Object protocol : protocols) {
|
||||
Enum<?> enumProtocol = (Enum<?>) protocol;
|
||||
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
|
||||
|
||||
// Associate known types
|
||||
if (serverMaps.containsKey(protocol)) {
|
||||
associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER);
|
||||
}
|
||||
if (clientMaps.containsKey(protocol)) {
|
||||
associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange (thread safe, as we have only one writer)
|
||||
this.register = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses a key->value map to value->key
|
||||
* Non-deterministic behavior when multiple keys are mapped to the same value
|
||||
*/
|
||||
private <K, V> Map<V, K> reverse(Map<K, V> map) {
|
||||
Map<V, K> newMap = new HashMap<>(map.size());
|
||||
for (Entry<K, V> entry : map.entrySet()) {
|
||||
newMap.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
|
||||
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
||||
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
|
||||
// System.out.println(Arrays.toString(type.getClassNames()) + " -> " + entry.getValue());
|
||||
|
||||
try {
|
||||
register.typeToClass.put(type, entry.getValue());
|
||||
|
||||
if (sender == Sender.SERVER)
|
||||
register.serverPackets.add(type);
|
||||
if (sender == Sender.CLIENT)
|
||||
register.clientPackets.add(type);
|
||||
} catch (Exception ex) {
|
||||
ProtocolLogger.debug("Encountered an exception associating packet " + type, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,4 +385,4 @@ public class PipelineProxy implements ChannelPipeline {
|
||||
return pipeline.voidPromise();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.VolatileField;
|
||||
import com.comphenix.protocol.utility.NettyVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -146,10 +147,15 @@ public class ProtocolInjector implements ChannelListener {
|
||||
protected void initChannel(final Channel channel) throws Exception {
|
||||
try {
|
||||
synchronized (networkManagers) {
|
||||
// For some reason it needs to be delayed on 1.12, but the delay breaks 1.11 and below
|
||||
// For some reason it needs to be delayed when using netty 4.1.24 (minecraft 1.12) or newer,
|
||||
// but the delay breaks older minecraft versions
|
||||
// TODO I see this more as a temporary hotfix than a permanent solution
|
||||
if (MinecraftVersion.getCurrentVersion().getMinor() >= 12) {
|
||||
channel.eventLoop().submit(() ->
|
||||
|
||||
// Check if the netty version is greater than 4.1.24, that's the version bundled with spigot 1.12
|
||||
NettyVersion ver = NettyVersion.getVersion();
|
||||
if ((ver.isValid() && ver.isGreaterThan(4,1,24)) ||
|
||||
MinecraftVersion.getCurrentVersion().getMinor() >= 12) { // fallback if netty version couldn't be detected
|
||||
channel.eventLoop().submit(() ->
|
||||
injectionFactory.fromChannel(channel, ProtocolInjector.this, playerFactory).inject());
|
||||
} else {
|
||||
injectionFactory.fromChannel(channel, ProtocolInjector.this, playerFactory).inject();
|
||||
@@ -180,6 +186,12 @@ public class ProtocolInjector implements ChannelListener {
|
||||
channel.pipeline().addFirst(beginInitProtocol);
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSharable() {
|
||||
// Needed if multiple objects are stored in the bootstrap list
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromObject(serverConnection, true);
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
package com.comphenix.protocol.injector.netty;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.injector.packet.MapContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Represents a way of accessing the new netty Protocol enum.
|
||||
* @author Kristian
|
||||
*/
|
||||
|
||||
public abstract class ProtocolRegistry {
|
||||
/**
|
||||
* Represents a register we are currently building.
|
||||
* @author Kristian
|
||||
*/
|
||||
protected static class Register {
|
||||
// The main lookup table
|
||||
public BiMap<PacketType, Class<?>> typeToClass = HashBiMap.create();
|
||||
public volatile Set<PacketType> serverPackets = Sets.newHashSet();
|
||||
public volatile Set<PacketType> clientPackets = Sets.newHashSet();
|
||||
public List<MapContainer> containers = Lists.newArrayList();
|
||||
|
||||
public Register() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current register is outdated.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean isOutdated() {
|
||||
for (MapContainer container : containers) {
|
||||
if (container.hasChanged()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<?> enumProtocol;
|
||||
|
||||
// Current register
|
||||
protected volatile Register register;
|
||||
|
||||
public ProtocolRegistry() {
|
||||
enumProtocol = MinecraftReflection.getEnumProtocolClass();
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable view of the packet type lookup.
|
||||
* @return The packet type lookup.
|
||||
*/
|
||||
public Map<PacketType, Class<?>> getPacketTypeLookup() {
|
||||
return Collections.unmodifiableMap(register.typeToClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable view of the class to packet type lookup.
|
||||
* @return The packet type lookup.
|
||||
*/
|
||||
public Map<Class<?>, PacketType> getPacketClassLookup() {
|
||||
return Collections.unmodifiableMap(register.typeToClass.inverse());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known client packet, from every protocol.
|
||||
* @return Every client packet.
|
||||
*/
|
||||
public Set<PacketType> getClientPackets() {
|
||||
return Collections.unmodifiableSet(register.clientPackets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known server packet, from every protocol.
|
||||
* @return Every server packet.
|
||||
*/
|
||||
public Set<PacketType> getServerPackets() {
|
||||
return Collections.unmodifiableSet(register.serverPackets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that our local register is up-to-date with Minecraft.
|
||||
* <p>
|
||||
* This operation may block the calling thread.
|
||||
*/
|
||||
public synchronized void synchronize() {
|
||||
// Check if the packet registry has changed
|
||||
if (register.isOutdated()) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the packet lookup tables in each protocol.
|
||||
*/
|
||||
protected abstract void initialize();
|
||||
|
||||
protected abstract void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender);
|
||||
|
||||
/**
|
||||
* Retrieve the number of mapping in all the maps.
|
||||
* @param maps - iterable of maps.
|
||||
* @return The sum of all the entries.
|
||||
*/
|
||||
protected final int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
|
||||
int count = 0;
|
||||
|
||||
for (Map<Integer, Class<?>> map : maps)
|
||||
count += map.size();
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,11 @@ public class SocketAdapter extends Socket {
|
||||
this.ch = ch;
|
||||
}
|
||||
|
||||
public static SocketAdapter adapt(SocketChannel ch) {
|
||||
return new SocketAdapter(ch);
|
||||
public static SocketAdapter adapt(Channel ch) {
|
||||
if (!(ch instanceof SocketChannel)) {
|
||||
return null;
|
||||
}
|
||||
return new SocketAdapter((SocketChannel) ch);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,42 +17,275 @@
|
||||
|
||||
package com.comphenix.protocol.injector.packet;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
|
||||
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Function;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Static packet registry in Minecraft.
|
||||
* @author Kristian
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class PacketRegistry {
|
||||
// The Netty packet registry
|
||||
private static volatile ProtocolRegistry NETTY;
|
||||
|
||||
// Whether or not the registry has been initialized
|
||||
private static volatile boolean INITIALIZED = false;
|
||||
|
||||
/**
|
||||
* Represents a register we are currently building.
|
||||
* @author Kristian
|
||||
*/
|
||||
protected static class Register {
|
||||
// The main lookup table
|
||||
private final Map<PacketType, Optional<Class<?>>> typeToClass = new ConcurrentHashMap<>();
|
||||
private final Map<Class<?>, PacketType> classToType = new ConcurrentHashMap<>();
|
||||
|
||||
private volatile Set<PacketType> serverPackets = Sets.newHashSet();
|
||||
private volatile Set<PacketType> clientPackets = Sets.newHashSet();
|
||||
private final List<MapContainer> containers = Lists.newArrayList();
|
||||
|
||||
public Register() {}
|
||||
|
||||
public void registerPacket(PacketType type, Class<?> clazz, Sender sender) {
|
||||
typeToClass.put(type, Optional.of(clazz));
|
||||
classToType.put(clazz, type);
|
||||
if (sender == Sender.CLIENT) {
|
||||
clientPackets.add(type);
|
||||
} else {
|
||||
serverPackets.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
public void addContainer(MapContainer container) {
|
||||
containers.add(container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current register is outdated.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean isOutdated() {
|
||||
for (MapContainer container : containers) {
|
||||
if (container.hasChanged()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final Class<?> ENUM_PROTOCOL = MinecraftReflection.getEnumProtocolClass();
|
||||
|
||||
// Current register
|
||||
protected static volatile Register REGISTER;
|
||||
|
||||
/**
|
||||
* Ensure that our local register is up-to-date with Minecraft.
|
||||
* <p>
|
||||
* This operation may block the calling thread.
|
||||
*/
|
||||
public static synchronized void synchronize() {
|
||||
// Check if the packet registry has changed
|
||||
if (REGISTER.isOutdated()) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
|
||||
protected static synchronized Register createOldRegister() {
|
||||
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
|
||||
|
||||
// ID to Packet class maps
|
||||
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
|
||||
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
|
||||
|
||||
Register result = new Register();
|
||||
StructureModifier<Object> modifier = null;
|
||||
|
||||
// Iterate through the protocols
|
||||
for (Object protocol : protocols) {
|
||||
if (modifier == null) {
|
||||
modifier = new StructureModifier<>(protocol.getClass().getSuperclass(), false);
|
||||
}
|
||||
|
||||
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
||||
for (Map.Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
|
||||
String direction = entry.getKey().toString();
|
||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||
serverMaps.put(protocol, entry.getValue());
|
||||
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
|
||||
clientMaps.put(protocol, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maps we have to occasionally check have changed
|
||||
for (Object map : serverMaps.values()) {
|
||||
result.addContainer(new MapContainer(map));
|
||||
}
|
||||
|
||||
for (Object map : clientMaps.values()) {
|
||||
result.addContainer(new MapContainer(map));
|
||||
}
|
||||
|
||||
for (Object protocol : protocols) {
|
||||
Enum<?> enumProtocol = (Enum<?>) protocol;
|
||||
PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol);
|
||||
|
||||
// Associate known types
|
||||
if (serverMaps.containsKey(protocol))
|
||||
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
|
||||
if (clientMaps.containsKey(protocol))
|
||||
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static synchronized Register createNewRegister() {
|
||||
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
|
||||
|
||||
// ID to Packet class maps
|
||||
Map<Object, Map<Class<?>, Integer>> serverMaps = Maps.newLinkedHashMap();
|
||||
Map<Object, Map<Class<?>, Integer>> clientMaps = Maps.newLinkedHashMap();
|
||||
|
||||
Register result = new Register();
|
||||
Field mainMapField = null;
|
||||
Field packetMapField = null;
|
||||
|
||||
// Iterate through the protocols
|
||||
for (Object protocol : protocols) {
|
||||
if (mainMapField == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true);
|
||||
mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.FINAL)
|
||||
.typeDerivedOf(Map.class)
|
||||
.build());
|
||||
mainMapField.setAccessible(true);
|
||||
}
|
||||
|
||||
Map<Object, Object> directionMap;
|
||||
|
||||
try {
|
||||
directionMap = (Map<Object, Object>) mainMapField.get(protocol);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to access packet map", ex);
|
||||
}
|
||||
|
||||
for (Map.Entry<Object, Object> entry : directionMap.entrySet()) {
|
||||
Object holder = entry.getValue();
|
||||
if (packetMapField == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(holder.getClass(), true);
|
||||
packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.FINAL)
|
||||
.typeDerivedOf(Map.class)
|
||||
.build());
|
||||
packetMapField.setAccessible(true);
|
||||
}
|
||||
|
||||
Map<Class<?>, Integer> packetMap;
|
||||
|
||||
try {
|
||||
packetMap = (Map<Class<?>, Integer>) packetMapField.get(holder);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to access packet map", ex);
|
||||
}
|
||||
|
||||
String direction = entry.getKey().toString();
|
||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||
serverMaps.put(protocol, packetMap);
|
||||
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
|
||||
clientMaps.put(protocol, packetMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maps we have to occasionally check have changed
|
||||
// TODO: Find equivalent in Object2IntMap
|
||||
|
||||
/* for (Object map : serverMaps.values()) {
|
||||
result.containers.add(new MapContainer(map));
|
||||
}
|
||||
|
||||
for (Object map : clientMaps.values()) {
|
||||
result.containers.add(new MapContainer(map));
|
||||
} */
|
||||
|
||||
for (Object protocol : protocols) {
|
||||
Enum<?> enumProtocol = (Enum<?>) protocol;
|
||||
PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol);
|
||||
|
||||
// Associate known types
|
||||
if (serverMaps.containsKey(protocol)) {
|
||||
associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER);
|
||||
}
|
||||
if (clientMaps.containsKey(protocol)) {
|
||||
associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses a key->value map to value->key
|
||||
* Non-deterministic behavior when multiple keys are mapped to the same value
|
||||
*/
|
||||
private static <K, V> Map<V, K> reverse(Map<K, V> map) {
|
||||
Map<V, K> newMap = new HashMap<>(map.size());
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
newMap.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
protected static void associatePackets(Register register, Map<Integer, Class<?>> lookup, PacketType.Protocol protocol, Sender sender) {
|
||||
for (Map.Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
||||
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
|
||||
|
||||
try {
|
||||
register.registerPacket(type, entry.getValue(), sender);
|
||||
} catch (Exception ex) {
|
||||
ProtocolLogger.debug("Encountered an exception associating packet " + type, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void associate(PacketType type, Class<?> clazz) {
|
||||
if (clazz != null) {
|
||||
REGISTER.typeToClass.put(type, Optional.of(clazz));
|
||||
REGISTER.classToType.put(clazz, type);
|
||||
} else {
|
||||
REGISTER.typeToClass.put(type, Optional.empty());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the packet registry.
|
||||
*/
|
||||
private static void initialize() {
|
||||
if (INITIALIZED) {
|
||||
if (NETTY == null) {
|
||||
throw new IllegalStateException("Failed to initialize packet registry.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!INITIALIZED) {
|
||||
INITIALIZED = true;
|
||||
|
||||
NETTY = new NettyProtocolRegistry();
|
||||
INITIALIZED = true;
|
||||
if (MinecraftVersion.BEE_UPDATE.atOrAbove()) {
|
||||
REGISTER = createNewRegister();
|
||||
} else {
|
||||
REGISTER = createOldRegister();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,35 +295,7 @@ public class PacketRegistry {
|
||||
*/
|
||||
public static boolean isSupported(PacketType type) {
|
||||
initialize();
|
||||
return NETTY.getPacketTypeLookup().containsKey(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a map of every packet class to every ID.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getPacketToType()} instead.
|
||||
* @return A map of packet classes and their corresponding ID.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Map<Class, Integer> getPacketToID() {
|
||||
initialize();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Class, Integer> result = (Map) Maps.transformValues(
|
||||
NETTY.getPacketClassLookup(), PacketType::getCurrentId);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a map of every packet class to the respective packet type.
|
||||
* @return A map of packet classes and their corresponding packet type.
|
||||
*/
|
||||
public static Map<Class, PacketType> getPacketToType() {
|
||||
initialize();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Class, PacketType> result = (Map) NETTY.getPacketClassLookup();
|
||||
return result;
|
||||
return tryGetPacketClass(type).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,9 +304,9 @@ public class PacketRegistry {
|
||||
*/
|
||||
public static Set<PacketType> getServerPacketTypes() {
|
||||
initialize();
|
||||
NETTY.synchronize();
|
||||
synchronize();
|
||||
|
||||
return NETTY.getServerPackets();
|
||||
return Collections.unmodifiableSet(REGISTER.serverPackets);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,88 +315,68 @@ public class PacketRegistry {
|
||||
*/
|
||||
public static Set<PacketType> getClientPacketTypes() {
|
||||
initialize();
|
||||
NETTY.synchronize();
|
||||
synchronize();
|
||||
|
||||
return NETTY.getClientPackets();
|
||||
return Collections.unmodifiableSet(REGISTER.clientPackets);
|
||||
}
|
||||
|
||||
private static Class<?> searchForPacket(List<String> classNames) {
|
||||
for (String name : classNames) {
|
||||
try {
|
||||
Class<?> clazz = MinecraftReflection.getMinecraftClass(name);
|
||||
if (MinecraftReflection.getPacketClass().isAssignableFrom(clazz)
|
||||
&& !Modifier.isAbstract(clazz.getModifiers())) {
|
||||
return clazz;
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given packet ID.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getPacketClassFromType(PacketType)} instead.
|
||||
* @param packetID - the packet ID.
|
||||
* @return The associated class.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Class getPacketClassFromID(int packetID) {
|
||||
initialize();
|
||||
return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given type.
|
||||
* @param type - the packet type.
|
||||
* @return The associated class.
|
||||
*/
|
||||
public static Class getPacketClassFromType(PacketType type) {
|
||||
return getPacketClassFromType(type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given type.
|
||||
* <p>
|
||||
* Note that forceVanillla will be ignored on MC 1.7.2 and later.
|
||||
*
|
||||
* @param type - the packet type.
|
||||
* @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
|
||||
* @return The associated class.
|
||||
* @deprecated forceVanilla no longer has any effect
|
||||
*/
|
||||
public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) {
|
||||
@Deprecated
|
||||
public static Class<?> getPacketClassFromType(PacketType type, boolean forceVanilla) {
|
||||
return getPacketClassFromType(type);
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> tryGetPacketClass(PacketType type) {
|
||||
initialize();
|
||||
|
||||
// Try the lookup first
|
||||
Class<?> clazz = NETTY.getPacketTypeLookup().get(type);
|
||||
if (clazz != null) {
|
||||
return clazz;
|
||||
// Try the lookup first (may be null, so check contains)
|
||||
Optional<Class<?>> res = REGISTER.typeToClass.get(type);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Then try looking up the class names
|
||||
for (String name : type.getClassNames()) {
|
||||
try {
|
||||
clazz = MinecraftReflection.getMinecraftClass(name);
|
||||
break;
|
||||
} catch (Exception ignored) { }
|
||||
Class<?> clazz = searchForPacket(type.getClassNames());
|
||||
if (clazz != null) {
|
||||
// we'd like for it to be associated correctly from the get-go; this is OK on older versions though
|
||||
ProtocolLogger.warnAbove(type.getCurrentVersion(), "Updating associated class for {0} to {1}", type.name(), clazz);
|
||||
}
|
||||
|
||||
// TODO Cache the result?
|
||||
return clazz;
|
||||
// cache it for next time
|
||||
associate(type, clazz);
|
||||
return Optional.ofNullable(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given packet ID.
|
||||
* <p>
|
||||
* This method has been deprecated.
|
||||
* @param packetID - the packet ID.
|
||||
* @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
|
||||
* @return The associated class.
|
||||
* Get the packet class associated with a given type. First attempts to read from the
|
||||
* type-to-class mapping, and tries
|
||||
* @param type the packet type
|
||||
* @return The associated class
|
||||
*/
|
||||
@Deprecated
|
||||
public static Class getPacketClassFromID(int packetID, boolean forceVanilla) {
|
||||
initialize();
|
||||
return getPacketClassFromID(packetID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the packet ID of a given packet.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getPacketType(Class)}.
|
||||
* @param packet - the type of packet to check.
|
||||
* @return The legacy ID of the given packet.
|
||||
* @throws IllegalArgumentException If this is not a valid packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public static int getPacketID(Class<?> packet) {
|
||||
initialize();
|
||||
return NETTY.getPacketClassLookup().get(packet).getCurrentId();
|
||||
public static Class<?> getPacketClassFromType(PacketType type) {
|
||||
return tryGetPacketClass(type)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Could not find packet for type " + type.name()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +385,8 @@ public class PacketRegistry {
|
||||
* @return The packet type, or NULL if not found.
|
||||
*/
|
||||
public static PacketType getPacketType(Class<?> packet) {
|
||||
return getPacketType(packet, null);
|
||||
initialize();
|
||||
return REGISTER.classToType.get(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,9 +394,10 @@ public class PacketRegistry {
|
||||
* @param packet - the class of the packet.
|
||||
* @param sender - the sender of the packet, or NULL.
|
||||
* @return The packet type, or NULL if not found.
|
||||
* @deprecated sender no longer has any effect
|
||||
*/
|
||||
@Deprecated
|
||||
public static PacketType getPacketType(Class<?> packet, Sender sender) {
|
||||
initialize();
|
||||
return NETTY.getPacketClassLookup().get(packet);
|
||||
return getPacketType(packet);
|
||||
}
|
||||
}
|
||||
@@ -80,4 +80,9 @@ public class BukkitSocketInjector implements SocketInjector {
|
||||
public void setUpdatedPlayer(Player updatedPlayer) {
|
||||
this.player = updatedPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return player.isOnline();
|
||||
}
|
||||
}
|
||||
@@ -18,22 +18,24 @@ public interface SocketInjector {
|
||||
* Retrieve the associated socket of this player.
|
||||
* @return The associated socket.
|
||||
* @throws IllegalAccessException If we're unable to read the socket field.
|
||||
* @deprecated May be null on certain server implementations. Also don't use raw sockets.
|
||||
*/
|
||||
public abstract Socket getSocket() throws IllegalAccessException;
|
||||
@Deprecated
|
||||
Socket getSocket() throws IllegalAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve the associated address of this player.
|
||||
* @return The associated address.
|
||||
* @throws IllegalAccessException If we're unable to read the socket field.
|
||||
*/
|
||||
public abstract SocketAddress getAddress() throws IllegalAccessException;
|
||||
SocketAddress getAddress() throws IllegalAccessException;
|
||||
|
||||
/**
|
||||
* Attempt to disconnect the current client.
|
||||
* @param message - the message to display.
|
||||
* @throws InvocationTargetException If disconnection failed.
|
||||
*/
|
||||
public abstract void disconnect(String message) throws InvocationTargetException;
|
||||
void disconnect(String message) throws InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Send a packet to the client.
|
||||
@@ -42,30 +44,36 @@ public interface SocketInjector {
|
||||
* @param filtered - whether or not the packet will be filtered by our listeners.
|
||||
* @throws InvocationTargetException If an error occured when sending the packet.
|
||||
*/
|
||||
public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
|
||||
void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
|
||||
throws InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Retrieve the hooked player.
|
||||
* @return The hooked player.
|
||||
*/
|
||||
public abstract Player getPlayer();
|
||||
Player getPlayer();
|
||||
|
||||
/**
|
||||
* Retrieve the hooked player object OR the more up-to-date player instance.
|
||||
* @return The hooked player, or a more up-to-date instance.
|
||||
*/
|
||||
public abstract Player getUpdatedPlayer();
|
||||
Player getUpdatedPlayer();
|
||||
|
||||
/**
|
||||
* Invoked when a delegated socket injector transfers the state of one injector to the next.
|
||||
* @param delegate - the new injector.
|
||||
*/
|
||||
public abstract void transferState(SocketInjector delegate);
|
||||
void transferState(SocketInjector delegate);
|
||||
|
||||
/**
|
||||
* Set the real Bukkit player that we will use.
|
||||
* @param updatedPlayer - the real Bukkit player.
|
||||
*/
|
||||
public abstract void setUpdatedPlayer(Player updatedPlayer);
|
||||
void setUpdatedPlayer(Player updatedPlayer);
|
||||
|
||||
/**
|
||||
* Determines if the player is currently connected.
|
||||
* @return true if the player is connected.
|
||||
*/
|
||||
boolean isConnected();
|
||||
}
|
||||
@@ -157,9 +157,9 @@ public class TemporaryPlayerFactory {
|
||||
|
||||
// Methods that are supported in the fallback instance
|
||||
if (methodName.equals("isOnline"))
|
||||
return injector.getSocket() != null && injector.getSocket().isConnected();
|
||||
return injector.isConnected();
|
||||
else if (methodName.equals("getName"))
|
||||
return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]";
|
||||
return "UNKNOWN[" + injector.getAddress() + "]";
|
||||
|
||||
// Ignore all other methods
|
||||
throw new UnsupportedOperationException(
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.comphenix.protocol.metrics;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
@@ -87,13 +86,7 @@ public class Statistics {
|
||||
|
||||
for (PacketListener listener : ProtocolLibrary.getProtocolManager().getPacketListeners()) {
|
||||
String name = PacketAdapter.getPluginName(listener);
|
||||
|
||||
// Increment occurence
|
||||
if (!users.containsKey(name)) {
|
||||
users.put(name, 1);
|
||||
} else {
|
||||
users.put(name, users.get(name) + 1);
|
||||
}
|
||||
users.put(name, 1);
|
||||
}
|
||||
|
||||
return users;
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.comphenix.protocol.reflect;
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
@@ -394,20 +395,12 @@ public class FieldUtils {
|
||||
writeStaticField(field, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #writeStaticField(Class, String, Object, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void writeStaticFinalField(Class<?> clazz, String fieldName, Object value, boolean forceAccess) throws Exception {
|
||||
Field field = getField(clazz, fieldName, forceAccess);
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException("Cannot locate field " + fieldName + " in " + clazz);
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(null, value);
|
||||
writeStaticField(clazz, fieldName, value, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,12 +435,8 @@ public class FieldUtils {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException("The field must not be null");
|
||||
}
|
||||
if (forceAccess && !field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
} else {
|
||||
MemberUtils.setAccessibleWorkaround(field);
|
||||
}
|
||||
field.set(target, value);
|
||||
|
||||
Accessors.getFieldAccessor(field, forceAccess).set(target, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -117,12 +117,11 @@ public class ObjectWriter {
|
||||
}
|
||||
|
||||
// Copy private fields underneath
|
||||
Class<?> superclass = commonType.getSuperclass();
|
||||
|
||||
if (superclass != null && !superclass.equals(Object.class)) {
|
||||
copyToInternal(source, destination, superclass, false);
|
||||
}
|
||||
|
||||
// Class<?> superclass = commonType.getSuperclass();
|
||||
//
|
||||
// if (superclass != null && !superclass.equals(Object.class)) {
|
||||
// copyToInternal(source, destination, superclass, false);
|
||||
// }
|
||||
} catch (FieldAccessException e) {
|
||||
throw new RuntimeException("Unable to copy fields from " + commonType.getName(), e);
|
||||
}
|
||||
|
||||
@@ -308,7 +308,9 @@ public class StructureModifier<TField> {
|
||||
* @param fieldIndex - index of the field.
|
||||
* @param value - TRUE if this field should be read only, FALSE otherwise.
|
||||
* @throws FieldAccessException If we cannot modify the read-only status.
|
||||
* @deprecated In recent java versions (starting at 9) the modifier field is secured and will not be writeable.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setReadOnly(int fieldIndex, boolean value) throws FieldAccessException {
|
||||
if (fieldIndex < 0 || fieldIndex >= data.size())
|
||||
throw new IllegalArgumentException("Index parameter is not within [0 - " + data.size() + ")");
|
||||
@@ -325,7 +327,9 @@ public class StructureModifier<TField> {
|
||||
* @param field - the field to change.
|
||||
* @param isReadOnly - TRUE if the field should be read only, FALSE otherwise.
|
||||
* @throws IllegalAccessException If an error occured.
|
||||
* @deprecated In recent java versions (starting at 9) the modifier field is secured and will not be writeable.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static void setFinalState(Field field, boolean isReadOnly) throws IllegalAccessException {
|
||||
if (isReadOnly)
|
||||
FieldUtils.writeField((Object) field, "modifiers", field.getModifiers() | Modifier.FINAL, true);
|
||||
|
||||
@@ -289,6 +289,7 @@ public final class Accessors {
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static ConstructorAccessor getConstructorAccessor(final Constructor<?> constructor) {
|
||||
constructor.setAccessible(true); // let us in even if we are not allowed to
|
||||
return new DefaultConstrutorAccessor(constructor);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
final class DefaultFieldAccessor implements FieldAccessor {
|
||||
|
||||
private final Field field;
|
||||
|
||||
|
||||
private MethodHandle setter;
|
||||
|
||||
public DefaultFieldAccessor(Field field) {
|
||||
this.field = field;
|
||||
// try to get a getter and setter handle for the field
|
||||
if (UnsafeFieldAccess.hasTrustedLookup()) {
|
||||
try {
|
||||
setter = UnsafeFieldAccess.findSetter(field);
|
||||
} catch (ReflectiveOperationException exception) {
|
||||
ProtocolLogger.debug("Unable to get setter for field " + field, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object get(Object instance) {
|
||||
try {
|
||||
@@ -19,18 +33,25 @@ final class DefaultFieldAccessor implements FieldAccessor {
|
||||
throw new IllegalStateException("Cannot use reflection.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(Object instance, Object value) {
|
||||
try {
|
||||
field.set(instance, value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (setter == null) {
|
||||
field.set(instance, value);
|
||||
} else {
|
||||
setter.invoke(instance, value);
|
||||
}
|
||||
} catch (IllegalArgumentException | ClassCastException e) {
|
||||
throw new RuntimeException("Cannot set field " + field + " to value " + value, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
} catch (IllegalAccessException | WrongMethodTypeException e) {
|
||||
throw new IllegalStateException("Cannot use reflection.", e);
|
||||
} catch (Throwable ignored) {
|
||||
// cannot happen - this might only occur when the handle targets a method
|
||||
throw new RuntimeException("Cannot happen");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Field getField() {
|
||||
return field;
|
||||
@@ -43,16 +64,17 @@ final class DefaultFieldAccessor implements FieldAccessor {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if (obj instanceof DefaultFieldAccessor) {
|
||||
DefaultFieldAccessor other = (DefaultFieldAccessor) obj;
|
||||
return other.field == field;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DefaultFieldAccessor [field=" + field + "]";
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.logging.Level;
|
||||
|
||||
final class UnsafeFieldAccess {
|
||||
|
||||
private static final Lookup TRUSTED_LOOKUP;
|
||||
|
||||
static {
|
||||
Lookup trusted = null;
|
||||
try {
|
||||
// get the unsafe class
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
// get the unsafe instance
|
||||
Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
|
||||
// get the trusted lookup field
|
||||
Field trustedLookup = Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||
// get access to the base and offset value of it
|
||||
long offset = unsafe.staticFieldOffset(trustedLookup);
|
||||
Object baseValue = unsafe.staticFieldBase(trustedLookup);
|
||||
// get the trusted lookup instance
|
||||
trusted = (Lookup) unsafe.getObject(baseValue, offset);
|
||||
} catch (Exception exception) {
|
||||
ProtocolLogger.log(Level.SEVERE, "Unable to retrieve trusted lookup", exception);
|
||||
}
|
||||
|
||||
TRUSTED_LOOKUP = trusted;
|
||||
}
|
||||
|
||||
public static boolean hasTrustedLookup() {
|
||||
return TRUSTED_LOOKUP != null;
|
||||
}
|
||||
|
||||
public static MethodHandle findSetter(Field field) throws ReflectiveOperationException {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
return TRUSTED_LOOKUP.findStaticSetter(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
} else {
|
||||
return TRUSTED_LOOKUP.findSetter(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,11 +256,11 @@ public class AggregateCloner implements Cloner {
|
||||
if (index < cloners.size()) {
|
||||
Cloner cloner = cloners.get(index);
|
||||
|
||||
try {
|
||||
return cloner.clone(source);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to clone " + source + " (" + source.getClass() + ") with " + cloner, ex);
|
||||
}
|
||||
// try {
|
||||
return cloner.clone(source);
|
||||
// } catch (Exception ex) {
|
||||
// throw new RuntimeException("Failed to clone " + source + " (" + source.getClass() + ") with " + cloner, ex);
|
||||
// }
|
||||
}
|
||||
|
||||
// Damn - failure
|
||||
|
||||
@@ -88,6 +88,11 @@ public class BukkitCloner implements Cloner {
|
||||
fromManual(ComponentConverter::getBaseComponentArrayClass, source ->
|
||||
ComponentConverter.clone((BaseComponent[]) source));
|
||||
} catch (Throwable ignored) { }
|
||||
|
||||
try {
|
||||
fromManual(AdventureComponentConverter::getComponentClass, source ->
|
||||
AdventureComponentConverter.clone(source));
|
||||
} catch (Throwable ignored) { }
|
||||
}
|
||||
|
||||
private Function<Object, Object> findCloner(Class<?> type) {
|
||||
|
||||
@@ -62,29 +62,29 @@ public class ImmutableDetector implements Cloner {
|
||||
add(MinecraftReflection::getDataWatcherSerializerClass);
|
||||
add(MinecraftReflection::getBlockClass);
|
||||
add(MinecraftReflection::getItemClass);
|
||||
add("SoundEffect");
|
||||
add("sounds.SoundEffect", "SoundEffect");
|
||||
|
||||
if (MinecraftVersion.AQUATIC_UPDATE.atOrAbove()) {
|
||||
add(MinecraftReflection::getFluidTypeClass);
|
||||
add(MinecraftReflection::getParticleTypeClass);
|
||||
add("Particle");
|
||||
add("core.particles.Particle", "Particle");
|
||||
}
|
||||
|
||||
if (MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) {
|
||||
add("EntityTypes");
|
||||
add("VillagerType");
|
||||
add("VillagerProfession");
|
||||
add(MinecraftReflection::getEntityTypes);
|
||||
add("world.entity.npc.VillagerType", "VillagerType");
|
||||
add("world.entity.npc.VillagerProfession", "VillagerProfession");
|
||||
}
|
||||
|
||||
// TODO automatically detect the technically-not-an-enum enums that Mojang is so fond of
|
||||
// Would also probably go in tandem with having the FieldCloner use this
|
||||
|
||||
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
|
||||
add("IRegistry");
|
||||
add("core.IRegistry", "IRegistry");
|
||||
}
|
||||
|
||||
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
|
||||
add("ResourceKey");
|
||||
add(MinecraftReflection::getResourceKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,13 +97,11 @@ public class ImmutableDetector implements Cloner {
|
||||
} catch (RuntimeException ignored) { }
|
||||
}
|
||||
|
||||
private static void add(String className) {
|
||||
try {
|
||||
Class<?> clazz = MinecraftReflection.getMinecraftClass(className);
|
||||
if (clazz != null) {
|
||||
immutableNMS.add(clazz);
|
||||
}
|
||||
} catch (RuntimeException ignored) { }
|
||||
private static void add(String className, String... aliases) {
|
||||
Class<?> clazz = MinecraftReflection.getNullableNMS(className, aliases);
|
||||
if (clazz != null) {
|
||||
immutableNMS.add(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,8 +58,6 @@ public abstract class CompiledStructureModifier extends StructureModifier<Object
|
||||
throw new IllegalStateException("Cannot make compiled field " + fieldIndex + " read only.");
|
||||
}
|
||||
}
|
||||
|
||||
super.setReadOnly(fieldIndex, value);
|
||||
}
|
||||
|
||||
// Speed up the default writer
|
||||
|
||||
@@ -141,6 +141,18 @@ public final class StructureCompiler {
|
||||
private static String COMPILED_CLASS = PACKAGE_NAME + "/CompiledStructureModifier";
|
||||
private static String FIELD_EXCEPTION_CLASS = "com/comphenix/protocol/reflect/FieldAccessException";
|
||||
|
||||
// On java 9+ (53.0+) CLassLoader#defineClass(String, byte[], int, int) should not be used anymore.
|
||||
// It will throw warnings and on Java 16+ (60.0+), it does not work at all anymore.
|
||||
private static final boolean LEGACY_CLASS_DEFINITION =
|
||||
Float.parseFloat(System.getProperty("java.class.version")) < 53;
|
||||
/**
|
||||
* The MethodHandles.Lookup object for this compiler. Only used when using the modern defineClass strategy.
|
||||
*/
|
||||
private Object lookup = null;
|
||||
|
||||
// Used to get the MethodHandles.Lookup object on newer versions of Java.
|
||||
private volatile static Method lookupMethod;
|
||||
|
||||
public static boolean attemptClassLoad = false;
|
||||
|
||||
/**
|
||||
@@ -289,36 +301,54 @@ public final class StructureCompiler {
|
||||
|
||||
byte[] data = cw.toByteArray();
|
||||
|
||||
// Call the define method
|
||||
Class<?> clazz = defineClass(data);
|
||||
// DEBUG CODE: Print the content of the generated class.
|
||||
//org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(data);
|
||||
//cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), 0);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
private Class<?> defineClassLegacy(byte[] data) throws InvocationTargetException, IllegalAccessException,
|
||||
NoSuchMethodException {
|
||||
if (defineMethod == null) {
|
||||
Method defined = ClassLoader.class.getDeclaredMethod("defineClass",
|
||||
new Class<?>[]{String.class, byte[].class, int.class, int.class});
|
||||
|
||||
// Awesome. Now, create and return it.
|
||||
defined.setAccessible(true);
|
||||
defineMethod = defined;
|
||||
}
|
||||
return (Class<?>) defineMethod.invoke(loader, null, data, 0, data.length);
|
||||
}
|
||||
|
||||
private Class<?> defineClassModern(byte[] data) throws InvocationTargetException, IllegalAccessException,
|
||||
ClassNotFoundException, NoSuchMethodException {
|
||||
if (defineMethod == null) {
|
||||
defineMethod = Class.forName("java.lang.invoke.MethodHandles$Lookup")
|
||||
.getDeclaredMethod("defineClass", byte[].class);
|
||||
}
|
||||
if (lookupMethod == null) {
|
||||
lookupMethod = Class.forName("java.lang.invoke.MethodHandles").getDeclaredMethod("lookup");
|
||||
}
|
||||
if (lookup == null)
|
||||
lookup = lookupMethod.invoke(null);
|
||||
|
||||
return (Class<?>) defineMethod.invoke(lookup, data);
|
||||
}
|
||||
|
||||
private Class<?> defineClass(byte[] data) {
|
||||
try {
|
||||
if (defineMethod == null) {
|
||||
Method defined = ClassLoader.class.getDeclaredMethod("defineClass",
|
||||
new Class<?>[] { String.class, byte[].class, int.class, int.class });
|
||||
|
||||
// Awesome. Now, create and return it.
|
||||
defined.setAccessible(true);
|
||||
defineMethod = defined;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class clazz = (Class) defineMethod.invoke(loader, null, data, 0, data.length);
|
||||
|
||||
// DEBUG CODE: Print the content of the generated class.
|
||||
//org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(data);
|
||||
//cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), 0);
|
||||
|
||||
return clazz;
|
||||
|
||||
return LEGACY_CLASS_DEFINITION ? defineClassLegacy(data) : defineClassModern(data);
|
||||
} catch (SecurityException e) {
|
||||
throw new RuntimeException("Cannot use reflection to dynamically load a class.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Incompatible JVM.", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalStateException("Cannot call defineMethod - wrong JVM?", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Security limitation! Cannot dynamically load class.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("Error occured in code generator.", e);
|
||||
throw new RuntimeException("Error occurred in code generator.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,32 +17,31 @@
|
||||
|
||||
package com.comphenix.protocol.reflect.instances;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Used to construct default instances of any type.
|
||||
* @author Kristian
|
||||
*
|
||||
*/
|
||||
public class DefaultInstances implements InstanceProvider {
|
||||
|
||||
public static final InstanceProvider UUID_GENERATOR = type -> type == UUID.class ? new UUID(0L, 0L) : null;
|
||||
|
||||
/**
|
||||
* Standard default instance provider.
|
||||
*/
|
||||
public static final DefaultInstances DEFAULT = DefaultInstances.fromArray(
|
||||
PrimitiveGenerator.INSTANCE, CollectionGenerator.INSTANCE, UUID_GENERATOR);
|
||||
PrimitiveGenerator.INSTANCE,
|
||||
CollectionGenerator.INSTANCE,
|
||||
MinecraftGenerator.INSTANCE
|
||||
);
|
||||
|
||||
/**
|
||||
* The maximum height of the heirarchy of creates types. Used to prevent cycles.
|
||||
@@ -188,7 +187,7 @@ public class DefaultInstances implements InstanceProvider {
|
||||
// Note that we don't allow recursive types - that is, types that
|
||||
// require itself in the constructor.
|
||||
if (types.length < lastCount) {
|
||||
if (!contains(types, type)) {
|
||||
if (!contains(types, type) && !contains(types, MinecraftReflection.getPacketDataSerializerClass())) {
|
||||
if (nonNull) {
|
||||
// Make sure all of these types are non-null
|
||||
if (isAnyNull(types, providers, recursionLevel)) {
|
||||
@@ -273,7 +272,6 @@ public class DefaultInstances implements InstanceProvider {
|
||||
Constructor<T> minimum = getMinimumConstructor(type, providers, recursionLevel + 1);
|
||||
|
||||
// Create the type with this constructor using default values. This might fail, though.
|
||||
// TODO every packet has a zero-args constructor
|
||||
|
||||
try {
|
||||
if (minimum != null) {
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.comphenix.protocol.reflect.instances;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MinecraftGenerator {
|
||||
// system unique id representation
|
||||
public static final UUID SYS_UUID;
|
||||
// minecraft default types
|
||||
public static final Object AIR_ITEM_STACK;
|
||||
private static Object DEFAULT_ENTITY_TYPES; // modern servers only (older servers will use an entity type id)
|
||||
// minecraft method accessors
|
||||
private static final MethodAccessor NON_NULL_LIST_CREATE;
|
||||
// fast util mappings for paper relocation
|
||||
private static final Map<Class<?>, Constructor<?>> FAST_MAP_CONSTRUCTORS;
|
||||
|
||||
static {
|
||||
try {
|
||||
SYS_UUID = new UUID(0L, 0L);
|
||||
AIR_ITEM_STACK = BukkitConverters.getItemStackConverter().getGeneric(new ItemStack(Material.AIR));
|
||||
FAST_MAP_CONSTRUCTORS = new ConcurrentHashMap<>();
|
||||
NON_NULL_LIST_CREATE = MinecraftReflection.getNonNullListCreateAccessor();
|
||||
} catch (Throwable ex) {
|
||||
throw new RuntimeException("Failed to create static fields in MinecraftGenerator", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static final InstanceProvider INSTANCE = type -> {
|
||||
if (type != null) {
|
||||
if (type == UUID.class) {
|
||||
return SYS_UUID;
|
||||
} else if (type.isEnum()) {
|
||||
return type.getEnumConstants()[0];
|
||||
} else if (type == MinecraftReflection.getItemStackClass()) {
|
||||
return AIR_ITEM_STACK;
|
||||
} else if (type == MinecraftReflection.getEntityTypes()) {
|
||||
if (DEFAULT_ENTITY_TYPES == null) {
|
||||
// try to initialize now
|
||||
try {
|
||||
DEFAULT_ENTITY_TYPES = BukkitConverters.getEntityTypeConverter().getGeneric(EntityType.AREA_EFFECT_CLOUD);
|
||||
} catch (Exception ignored) {
|
||||
// not available in this version of minecraft
|
||||
}
|
||||
}
|
||||
return DEFAULT_ENTITY_TYPES;
|
||||
} else if (type.isAssignableFrom(Map.class)) {
|
||||
Constructor<?> ctor = FAST_MAP_CONSTRUCTORS.computeIfAbsent(type, __ -> {
|
||||
try {
|
||||
String name = type.getCanonicalName();
|
||||
if (name != null && name.contains("it.unimi.fastutils")) {
|
||||
return Class.forName(name.substring(name.length() - 3) + "OpenHashMap").getConstructor();
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return null;
|
||||
});
|
||||
if (ctor != null) {
|
||||
try {
|
||||
return ctor.newInstance();
|
||||
} catch (ReflectiveOperationException ignored) {}
|
||||
}
|
||||
} else if (NON_NULL_LIST_CREATE != null && type == MinecraftReflection.getNonNullListClass()) {
|
||||
return NON_NULL_LIST_CREATE.invoke(null);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
@@ -21,10 +21,10 @@ package com.comphenix.protocol.utility;
|
||||
*/
|
||||
|
||||
public final class Constants {
|
||||
public static final String PACKAGE_VERSION = "v1_16_R3";
|
||||
public static final String NMS = "net.minecraft.server." + PACKAGE_VERSION;
|
||||
public static final String PACKAGE_VERSION = "v1_18_R2";
|
||||
public static final String NMS = "net.minecraft";
|
||||
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
|
||||
public static final MinecraftVersion CURRENT_VERSION = MinecraftVersion.NETHER_UPDATE_2;
|
||||
public static final MinecraftVersion CURRENT_VERSION = MinecraftVersion.CAVES_CLIFFS_2;
|
||||
|
||||
public static void init() {
|
||||
MinecraftReflection.setMinecraftPackage(NMS, OBC);
|
||||
|
||||
@@ -15,15 +15,16 @@ public class MinecraftFields {
|
||||
// Cached accessors
|
||||
private static volatile FieldAccessor CONNECTION_ACCESSOR;
|
||||
private static volatile FieldAccessor NETWORK_ACCESSOR;
|
||||
|
||||
private static volatile FieldAccessor CONNECTION_ENTITY_ACCESSOR;
|
||||
|
||||
private MinecraftFields() {
|
||||
// Not constructable
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the network mananger associated with a particular player.
|
||||
* Retrieve the network manager associated with a particular player.
|
||||
* @param player - the player.
|
||||
* @return The network manager, or NULL if no network manager has been asssociated yet.
|
||||
* @return The network manager, or NULL if no network manager has been associated yet.
|
||||
*/
|
||||
public static Object getNetworkManager(Player player) {
|
||||
Object nmsPlayer = BukkitUnwrapper.getInstance().unwrapItem(player);
|
||||
@@ -50,9 +51,13 @@ public class MinecraftFields {
|
||||
Preconditions.checkNotNull(player, "player cannot be null!");
|
||||
return getPlayerConnection(BukkitUnwrapper.getInstance().unwrapItem(player));
|
||||
}
|
||||
|
||||
// Retrieve player connection from a native instance
|
||||
private static Object getPlayerConnection(Object nmsPlayer) {
|
||||
|
||||
/**
|
||||
* Retrieve the PlayerConnection (or NetServerHandler) associated with a player.
|
||||
* @param nmsPlayer - the NMS player.
|
||||
* @return The player connection.
|
||||
*/
|
||||
public static Object getPlayerConnection(Object nmsPlayer) {
|
||||
Preconditions.checkNotNull(nmsPlayer, "nmsPlayer cannot be null!");
|
||||
|
||||
if (CONNECTION_ACCESSOR == null) {
|
||||
@@ -61,4 +66,21 @@ public class MinecraftFields {
|
||||
}
|
||||
return CONNECTION_ACCESSOR.get(nmsPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the EntityPlayer player field from a PlayerConnection.
|
||||
*
|
||||
* @param playerConnection The PlayerConnection object from which to retrieve the EntityPlayer field.
|
||||
* @return The value of the EntityPlayer field in the PlayerConnection.
|
||||
*/
|
||||
public static Object getPlayerFromConnection(Object playerConnection) {
|
||||
Preconditions.checkNotNull(playerConnection, "playerConnection cannot be null!");
|
||||
|
||||
if (CONNECTION_ENTITY_ACCESSOR == null) {
|
||||
Class<?> connectionClass = MinecraftReflection.getPlayerConnectionClass();
|
||||
Class<?> entityPlayerClass = MinecraftReflection.getEntityPlayerClass();
|
||||
CONNECTION_ENTITY_ACCESSOR = Accessors.getFieldAccessor(connectionClass, entityPlayerClass, true);
|
||||
}
|
||||
return CONNECTION_ENTITY_ACCESSOR.get(playerConnection);
|
||||
}
|
||||
}
|
||||
@@ -248,8 +248,8 @@ public class MinecraftMethods {
|
||||
}
|
||||
}
|
||||
|
||||
if (packetReadByteBuf == null)
|
||||
throw new IllegalStateException("Unable to find Packet.read(PacketDataSerializer)");
|
||||
// if (packetReadByteBuf == null)
|
||||
// throw new IllegalStateException("Unable to find Packet.read(PacketDataSerializer)");
|
||||
if (packetWriteByteBuf == null)
|
||||
throw new IllegalStateException("Unable to find Packet.write(PacketDataSerializer)");
|
||||
}
|
||||
|
||||
@@ -72,6 +72,15 @@ public class MinecraftProtocolVersion {
|
||||
map.put(new MinecraftVersion(1, 16, 2), 751);
|
||||
map.put(new MinecraftVersion(1, 16, 3), 753);
|
||||
map.put(new MinecraftVersion(1, 16, 4), 754);
|
||||
map.put(new MinecraftVersion(1, 16, 5), 754);
|
||||
|
||||
map.put(new MinecraftVersion(1, 17, 0), 755);
|
||||
map.put(new MinecraftVersion(1, 17, 1), 756);
|
||||
|
||||
map.put(new MinecraftVersion(1, 18, 0), 757);
|
||||
map.put(new MinecraftVersion(1, 18, 1), 757);
|
||||
map.put(new MinecraftVersion(1, 18, 2), 758);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,8 @@ import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -43,6 +41,7 @@ import javax.annotation.Nonnull;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
@@ -57,6 +56,7 @@ import com.comphenix.protocol.reflect.ClassAnalyser;
|
||||
import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod;
|
||||
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.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
|
||||
@@ -65,6 +65,7 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException.Reason;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtType;
|
||||
import com.google.common.base.Joiner;
|
||||
@@ -222,30 +223,35 @@ public class MinecraftReflection {
|
||||
Class<?> craftEntity = getCraftEntityClass();
|
||||
Method getHandle = craftEntity.getMethod("getHandle");
|
||||
|
||||
MINECRAFT_FULL_PACKAGE = getPackage(getHandle.getReturnType().getCanonicalName());
|
||||
|
||||
// Pretty important invariantt
|
||||
if (!MINECRAFT_FULL_PACKAGE.startsWith(MINECRAFT_PREFIX_PACKAGE)) {
|
||||
// See if we got the Forge entity package
|
||||
if (MINECRAFT_FULL_PACKAGE.equals(FORGE_ENTITY_PACKAGE)) {
|
||||
// USe the standard NMS versioned package
|
||||
MINECRAFT_FULL_PACKAGE = CachedPackage.combine(MINECRAFT_PREFIX_PACKAGE, packageVersion);
|
||||
} else {
|
||||
// Assume they're the same instead
|
||||
MINECRAFT_PREFIX_PACKAGE = MINECRAFT_FULL_PACKAGE;
|
||||
}
|
||||
|
||||
// The package is usualy flat, so go with that assumption
|
||||
String matcher =
|
||||
(MINECRAFT_PREFIX_PACKAGE.length() > 0 ?
|
||||
Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + CANONICAL_REGEX;
|
||||
|
||||
// We'll still accept the default location, however
|
||||
setDynamicPackageMatcher("(" + matcher + ")|(" + MINECRAFT_OBJECT + ")");
|
||||
|
||||
} else {
|
||||
// Use the standard matcher
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
// total rework of the NMS structure in 1.17 (at least there's no versioning)
|
||||
MINECRAFT_FULL_PACKAGE = MINECRAFT_PREFIX_PACKAGE = "net.minecraft";
|
||||
setDynamicPackageMatcher(MINECRAFT_OBJECT);
|
||||
} else {
|
||||
MINECRAFT_FULL_PACKAGE = getPackage(getHandle.getReturnType().getCanonicalName());
|
||||
|
||||
// Pretty important invariantt
|
||||
if (!MINECRAFT_FULL_PACKAGE.startsWith(MINECRAFT_PREFIX_PACKAGE)) {
|
||||
// See if we got the Forge entity package
|
||||
if (MINECRAFT_FULL_PACKAGE.equals(FORGE_ENTITY_PACKAGE)) {
|
||||
// USe the standard NMS versioned package
|
||||
MINECRAFT_FULL_PACKAGE = CachedPackage.combine(MINECRAFT_PREFIX_PACKAGE, packageVersion);
|
||||
} else {
|
||||
// Assume they're the same instead
|
||||
MINECRAFT_PREFIX_PACKAGE = MINECRAFT_FULL_PACKAGE;
|
||||
}
|
||||
|
||||
// The package is usualy flat, so go with that assumption
|
||||
String matcher =
|
||||
(MINECRAFT_PREFIX_PACKAGE.length() > 0 ? Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + CANONICAL_REGEX;
|
||||
|
||||
// We'll still accept the default location, however
|
||||
setDynamicPackageMatcher("(" + matcher + ")|(" + MINECRAFT_OBJECT + ")");
|
||||
|
||||
} else {
|
||||
// Use the standard matcher
|
||||
setDynamicPackageMatcher(MINECRAFT_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
return MINECRAFT_FULL_PACKAGE;
|
||||
@@ -371,6 +377,21 @@ public class MinecraftReflection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Bukkit player from a given PlayerConnection.
|
||||
* @param playerConnection The PlayerConnection.
|
||||
* @return A bukkit player.
|
||||
* @throws RuntimeException If we were unable to retrieve the Bukkit player.
|
||||
*/
|
||||
public static Player getBukkitPlayerFromConnection(Object playerConnection)
|
||||
{
|
||||
try {
|
||||
return (Player) getBukkitEntity(MinecraftFields.getPlayerFromConnection(playerConnection));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot get Bukkit entity from connection " + playerConnection, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given object can be found within the package net.minecraft.server.
|
||||
* @param obj - the object to test.
|
||||
@@ -580,7 +601,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getEntityPlayerClass() {
|
||||
try {
|
||||
return getMinecraftClass("EntityPlayer");
|
||||
return getMinecraftClass("server.level.EntityPlayer","EntityPlayer");
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
// Grab CraftPlayer's handle
|
||||
@@ -637,7 +658,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getEntityClass() {
|
||||
try {
|
||||
return getMinecraftClass("Entity");
|
||||
return getMinecraftClass("server.world.Entity", "Entity");
|
||||
} catch (RuntimeException e) {
|
||||
return fallbackMethodReturn("Entity", "entity.CraftEntity", "getHandle");
|
||||
}
|
||||
@@ -657,7 +678,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getWorldServerClass() {
|
||||
try {
|
||||
return getMinecraftClass("WorldServer");
|
||||
return getMinecraftClass("server.level.WorldServer", "WorldServer");
|
||||
} catch (RuntimeException e) {
|
||||
return fallbackMethodReturn("WorldServer", "CraftWorld", "getHandle");
|
||||
}
|
||||
@@ -669,7 +690,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getNmsWorldClass() {
|
||||
try {
|
||||
return getMinecraftClass("World");
|
||||
return getMinecraftClass("world.level.World", "World");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass("World", getWorldServerClass().getSuperclass());
|
||||
}
|
||||
@@ -696,7 +717,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getPacketClass() {
|
||||
try {
|
||||
return getMinecraftClass("Packet");
|
||||
return getMinecraftClass("network.protocol.Packet", "Packet");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract paketContract = null;
|
||||
|
||||
@@ -752,8 +773,10 @@ public class MinecraftReflection {
|
||||
* @return The Enum protocol class.
|
||||
*/
|
||||
public static Class<?> getEnumProtocolClass() {
|
||||
try {
|
||||
return getMinecraftClass("EnumProtocol");
|
||||
return getMinecraftClass("network.EnumProtocol", "EnumProtocol");
|
||||
|
||||
/* try {
|
||||
return getMinecraftClass("network.EnumProtocol", "EnumProtocol");
|
||||
} catch (RuntimeException e) {
|
||||
Method protocolMethod = FuzzyReflection.fromClass(getNetworkManagerClass()).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
@@ -762,7 +785,7 @@ public class MinecraftReflection {
|
||||
build()
|
||||
);
|
||||
return setMinecraftClass("EnumProtocol", protocolMethod.getParameterTypes()[0]);
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -771,7 +794,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getIChatBaseComponentClass() {
|
||||
try {
|
||||
return getMinecraftClass("IChatBaseComponent");
|
||||
return getMinecraftClass("network.chat.IChatbaseComponent", "IChatBaseComponent");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass("IChatBaseComponent",
|
||||
Accessors.getMethodAccessor(getCraftChatMessage(), "fromString", String.class).
|
||||
@@ -790,7 +813,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getChatComponentTextClass() {
|
||||
try {
|
||||
return getMinecraftClass("ChatComponentText");
|
||||
return getMinecraftClass("network.chat.ChatComponentText", "ChatComponentText");
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
Method getScoreboardDisplayName = FuzzyReflection.fromClass(getEntityClass()).
|
||||
@@ -818,7 +841,8 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getChatSerializerClass() {
|
||||
try {
|
||||
return getMinecraftClass("ChatSerializer", "IChatBaseComponent$ChatSerializer");
|
||||
return getMinecraftClass("network.chat.IChatBaseComponent$ChatSerializer",
|
||||
"ChatSerializer", "IChatBaseComponent$ChatSerializer");
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: Figure out a functional fallback
|
||||
throw new IllegalStateException("Could not find ChatSerializer class.", e);
|
||||
@@ -830,11 +854,8 @@ public class MinecraftReflection {
|
||||
* @return The ServerPing class.
|
||||
*/
|
||||
public static Class<?> getServerPingClass() {
|
||||
if (!isUsingNetty())
|
||||
throw new IllegalStateException("ServerPing is only supported in 1.7.2.");
|
||||
|
||||
try {
|
||||
return getMinecraftClass("ServerPing");
|
||||
return getMinecraftClass("network.protocol.status.ServerPing", "ServerPing");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> statusServerInfo = PacketType.Status.Server.SERVER_INFO.getPacketClass();
|
||||
|
||||
@@ -856,11 +877,9 @@ public class MinecraftReflection {
|
||||
* @return The ServerPingServerData class.
|
||||
*/
|
||||
public static Class<?> getServerPingServerDataClass() {
|
||||
if (!isUsingNetty())
|
||||
throw new IllegalStateException("ServerPingServerData is only supported in 1.7.2.");
|
||||
|
||||
try {
|
||||
return getMinecraftClass("ServerPingServerData", "ServerPing$ServerData");
|
||||
return getMinecraftClass("network.protocol.status.ServerPing$ServerData",
|
||||
"ServerPingServerData", "ServerPing$ServerData");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(getServerPingClass(), true);
|
||||
return setMinecraftClass("ServerPingServerData", fuzzy.getFieldByType("(.*)(ServerData)(.*)").getType());
|
||||
@@ -872,11 +891,9 @@ public class MinecraftReflection {
|
||||
* @return The ServerPingPlayerSample class.
|
||||
*/
|
||||
public static Class<?> getServerPingPlayerSampleClass() {
|
||||
if (!isUsingNetty())
|
||||
throw new IllegalStateException("ServerPingPlayerSample is only supported in 1.7.2.");
|
||||
|
||||
try {
|
||||
return getMinecraftClass("ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
|
||||
return getMinecraftClass("network.protocol.status.ServerPing$ServerPingPlayerSample",
|
||||
"ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> serverPing = getServerPingClass();
|
||||
|
||||
@@ -942,7 +959,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getMinecraftServerClass() {
|
||||
try {
|
||||
return getMinecraftClass("MinecraftServer");
|
||||
return getMinecraftClass("server.MinecraftServer","MinecraftServer");
|
||||
} catch (RuntimeException e) {
|
||||
useFallbackServer();
|
||||
|
||||
@@ -958,7 +975,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getStatisticClass() {
|
||||
// TODO: Implement fallback
|
||||
return getMinecraftClass("Statistic");
|
||||
return getMinecraftClass("stats.Statistic", "Statistic");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -967,7 +984,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getStatisticListClass() {
|
||||
// TODO: Implement fallback
|
||||
return getMinecraftClass("StatisticList");
|
||||
return getMinecraftClass("stats.StatisticList", "StatisticList");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -994,7 +1011,8 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getPlayerListClass() {
|
||||
try {
|
||||
return getMinecraftClass("ServerConfigurationManager", "PlayerList");
|
||||
return getMinecraftClass("server.players.PlayerList",
|
||||
"ServerConfigurationManager", "PlayerList");
|
||||
} catch (RuntimeException e) {
|
||||
useFallbackServer();
|
||||
|
||||
@@ -1033,7 +1051,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getPlayerConnectionClass() {
|
||||
try {
|
||||
return getMinecraftClass("PlayerConnection", "NetServerHandler");
|
||||
return getMinecraftClass("server.network.PlayerConnection","PlayerConnection", "NetServerHandler");
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
// Use the player connection field
|
||||
@@ -1077,7 +1095,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getNetworkManagerClass() {
|
||||
try {
|
||||
return getMinecraftClass("INetworkManager", "NetworkManager");
|
||||
return getMinecraftClass("network.NetworkManager", "INetworkManager", "NetworkManager");
|
||||
} catch (RuntimeException e) {
|
||||
Constructor<?> selected = FuzzyReflection.fromClass(getPlayerConnectionClass()).
|
||||
getConstructor(FuzzyMethodContract.newBuilder().
|
||||
@@ -1110,7 +1128,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getItemStackClass() {
|
||||
try {
|
||||
return getMinecraftClass("ItemStack");
|
||||
return getMinecraftClass("world.item.ItemStack", "ItemStack");
|
||||
} catch (RuntimeException e) {
|
||||
// Use the handle reference
|
||||
return setMinecraftClass("ItemStack",
|
||||
@@ -1124,7 +1142,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getBlockClass() {
|
||||
try {
|
||||
return getMinecraftClass("Block");
|
||||
return getMinecraftClass("world.level.block.Block", "Block");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyReflection reflect = FuzzyReflection.fromClass(getItemStackClass());
|
||||
Set<Class<?>> candidates = new HashSet<Class<?>>();
|
||||
@@ -1149,15 +1167,15 @@ public class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getItemClass() {
|
||||
return getNullableNMS("Item");
|
||||
return getNullableNMS("world.item.Item", "Item");
|
||||
}
|
||||
|
||||
public static Class<?> getFluidTypeClass() {
|
||||
return getNullableNMS("FluidType");
|
||||
return getNullableNMS("world.level.material.FluidType", "FluidType");
|
||||
}
|
||||
|
||||
public static Class<?> getParticleTypeClass() {
|
||||
return getNullableNMS("ParticleType");
|
||||
return getNullableNMS("core.particles.ParticleType", "ParticleType");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1188,7 +1206,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getDataWatcherClass() {
|
||||
try {
|
||||
return getMinecraftClass("DataWatcher");
|
||||
return getMinecraftClass("network.syncher.DataWatcher", "DataWatcher");
|
||||
} catch (RuntimeException e) {
|
||||
// Describe the DataWatcher
|
||||
FuzzyClassContract dataWatcherContract = FuzzyClassContract.newBuilder().
|
||||
@@ -1236,7 +1254,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getBlockPositionClass() {
|
||||
try {
|
||||
return getMinecraftClass("BlockPosition");
|
||||
return getMinecraftClass("core.BlockPosition", "BlockPosition");
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
Class<?> normalChunkGenerator = getCraftBukkitClass("generator.NormalChunkGenerator");
|
||||
@@ -1263,7 +1281,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getVec3DClass() {
|
||||
try {
|
||||
return getMinecraftClass("Vec3D");
|
||||
return getMinecraftClass("world.phys.Vec3D", "Vec3D");
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: Figure out a fuzzy field contract
|
||||
return null;
|
||||
@@ -1288,13 +1306,10 @@ public class MinecraftReflection {
|
||||
* @return The ChunkCoordIntPair class.
|
||||
*/
|
||||
public static Class<?> getChunkCoordIntPair() {
|
||||
if (!isUsingNetty())
|
||||
throw new IllegalArgumentException("Not supported on 1.6.4 and older.");
|
||||
|
||||
try {
|
||||
return getMinecraftClass("ChunkCoordIntPair");
|
||||
return getMinecraftClass("world.level.ChunkCoordIntPair", "ChunkCoordIntPair");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.MULTI_BLOCK_CHANGE);
|
||||
Class<?> packet = PacketType.Play.Server.MULTI_BLOCK_CHANGE.getPacketClass();
|
||||
|
||||
AbstractFuzzyMatcher<Class<?>> chunkCoordIntContract = FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
@@ -1326,7 +1341,8 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getDataWatcherItemClass() {
|
||||
try {
|
||||
return getMinecraftClass("DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
|
||||
return getMinecraftClass("network.syncher.DataWatcher$Item",
|
||||
"DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
|
||||
} catch (RuntimeException e) {
|
||||
Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true).
|
||||
getMethod(FuzzyMethodContract.newBuilder().
|
||||
@@ -1342,7 +1358,7 @@ public class MinecraftReflection {
|
||||
|
||||
public static Class<?> getDataWatcherObjectClass() {
|
||||
try {
|
||||
return getMinecraftClass("DataWatcherObject");
|
||||
return getMinecraftClass("network.syncher.DataWatcherObject", "DataWatcherObject");
|
||||
} catch (RuntimeException ex) {
|
||||
return null;
|
||||
}
|
||||
@@ -1362,27 +1378,27 @@ public class MinecraftReflection {
|
||||
|
||||
public static Class<?> getDataWatcherSerializerClass() {
|
||||
// TODO Implement a fallback
|
||||
return getNullableNMS("DataWatcherSerializer");
|
||||
return getNullableNMS("network.syncher.DataWatcherSerializer", "DataWatcherSerializer");
|
||||
}
|
||||
|
||||
public static Class<?> getDataWatcherRegistryClass() {
|
||||
// TODO Implement a fallback
|
||||
return getMinecraftClass("DataWatcherRegistry");
|
||||
return getMinecraftClass("network.syncher.DataWatcherRegistry", "DataWatcherRegistry");
|
||||
}
|
||||
|
||||
public static Class<?> getMinecraftKeyClass() {
|
||||
// TODO Implement a fallback
|
||||
return getMinecraftClass("MinecraftKey");
|
||||
return getMinecraftClass("resources.MinecraftKey", "MinecraftKey");
|
||||
}
|
||||
|
||||
public static Class<?> getMobEffectListClass() {
|
||||
// TODO Implement a fallback
|
||||
return getMinecraftClass("MobEffectList");
|
||||
return getMinecraftClass("world.effect.MobEffectList", "MobEffectList");
|
||||
}
|
||||
|
||||
public static Class<?> getSoundEffectClass() {
|
||||
try {
|
||||
return getMinecraftClass("SoundEffect");
|
||||
return getMinecraftClass("sounds.SoundEffect", "SoundEffect");
|
||||
} catch (RuntimeException ex) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(PacketType.Play.Server.NAMED_SOUND_EFFECT.getPacketClass(), true);
|
||||
Field field = fuzzy.getFieldByType("(.*)(Sound)(.*)");
|
||||
@@ -1396,7 +1412,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getServerConnectionClass() {
|
||||
try {
|
||||
return getMinecraftClass("ServerConnection");
|
||||
return getMinecraftClass("server.network.ServerConnection", "ServerConnection");
|
||||
} catch (RuntimeException e) {
|
||||
Method selected = null;
|
||||
FuzzyClassContract.Builder serverConnectionContract = FuzzyClassContract.newBuilder().
|
||||
@@ -1441,7 +1457,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getNBTBaseClass() {
|
||||
try {
|
||||
return getMinecraftClass("NBTBase");
|
||||
return getMinecraftClass("nbt.NBTBase", "NBTBase");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> nbtBase = null;
|
||||
|
||||
@@ -1501,7 +1517,7 @@ public class MinecraftReflection {
|
||||
* @return The NBT read limiter.
|
||||
*/
|
||||
public static Class<?> getNBTReadLimiterClass() {
|
||||
return getMinecraftClass("NBTReadLimiter");
|
||||
return getMinecraftClass("nbt.NBTReadLimiter", "NBTReadLimiter");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1510,7 +1526,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getNBTCompoundClass() {
|
||||
try {
|
||||
return getMinecraftClass("NBTTagCompound");
|
||||
return getMinecraftClass("nbt.NBTTagCompound","NBTTagCompound");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass(
|
||||
"NBTTagCompound",
|
||||
@@ -1525,7 +1541,8 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getEntityTrackerClass() {
|
||||
try {
|
||||
return getMinecraftClass("EntityTracker", "PlayerChunkMap$EntityTracker");
|
||||
return getMinecraftClass("server.level.PlayerChunkMap$EntityTracker",
|
||||
"EntityTracker", "PlayerChunkMap$EntityTracker");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract entityTrackerContract = FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
@@ -1553,38 +1570,6 @@ public class MinecraftReflection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NetworkListenThread class (NMS).
|
||||
* <p>
|
||||
* Note that this class was removed after Minecraft 1.3.1.
|
||||
* @return NetworkListenThread class.
|
||||
*/
|
||||
public static Class<?> getNetworkListenThreadClass() {
|
||||
try {
|
||||
return getMinecraftClass("NetworkListenThread");
|
||||
} catch (RuntimeException e) {
|
||||
FuzzyClassContract networkListenContract = FuzzyClassContract.newBuilder().
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(ServerSocket.class)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(Thread.class)).
|
||||
field(FuzzyFieldContract.newBuilder().
|
||||
typeDerivedOf(List.class)).
|
||||
method(FuzzyMethodContract.newBuilder().
|
||||
parameterExactType(getPlayerConnectionClass())).
|
||||
build();
|
||||
|
||||
Field selected = FuzzyReflection.fromClass(MinecraftReflection.getMinecraftServerClass(), true).
|
||||
getField(FuzzyFieldContract.newBuilder().
|
||||
typeMatches(networkListenContract).
|
||||
build()
|
||||
);
|
||||
|
||||
// Go by the defined type of this field
|
||||
return setMinecraftClass("NetworkListenThread", selected.getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the attribute snapshot class.
|
||||
* <p>
|
||||
@@ -1593,7 +1578,8 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getAttributeSnapshotClass() {
|
||||
try {
|
||||
return getMinecraftClass("AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
|
||||
return getMinecraftClass("network.protocol.game.PacketPlayOutUpdateAttributes$AttributeSnapshot",
|
||||
"AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
|
||||
} catch (RuntimeException ex) {
|
||||
try {
|
||||
// It should be the parameter of a list in the update attributes packet
|
||||
@@ -1652,7 +1638,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getAttributeModifierClass() {
|
||||
try {
|
||||
return getMinecraftClass("AttributeModifier");
|
||||
return getMinecraftClass("world.entity.ai.attributes.AttributeModifier", "AttributeModifier");
|
||||
} catch (RuntimeException e) {
|
||||
getAttributeSnapshotClass();
|
||||
|
||||
@@ -1668,10 +1654,10 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getMobEffectClass() {
|
||||
try {
|
||||
return getMinecraftClass("MobEffect");
|
||||
return getMinecraftClass("world.effect.MobEffect", "MobEffect");
|
||||
} catch (RuntimeException e) {
|
||||
// It is the second parameter in Packet41MobEffect
|
||||
Class<?> packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.ENTITY_EFFECT);
|
||||
Class<?> packet = PacketType.Play.Server.ENTITY_EFFECT.getPacketClass();
|
||||
Constructor<?> constructor = FuzzyReflection.fromClass(packet).getConstructor(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(2).
|
||||
@@ -1689,7 +1675,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getPacketDataSerializerClass() {
|
||||
try {
|
||||
return getMinecraftClass("PacketDataSerializer");
|
||||
return getMinecraftClass("network.PacketDataSerializer", "PacketDataSerializer");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> packet = getPacketClass();
|
||||
Method method = FuzzyReflection.fromClass(packet).getMethod(
|
||||
@@ -1709,7 +1695,7 @@ public class MinecraftReflection {
|
||||
*/
|
||||
public static Class<?> getNbtCompressedStreamToolsClass() {
|
||||
try {
|
||||
return getMinecraftClass("NBTCompressedStreamTools");
|
||||
return getMinecraftClass("nbt.NBTCompressedStreamTools", "NBTCompressedStreamTools");
|
||||
} catch (RuntimeException e) {
|
||||
Class<?> packetSerializer = getPacketDataSerializerClass();
|
||||
|
||||
@@ -1738,7 +1724,7 @@ public class MinecraftReflection {
|
||||
* @return The tile entity class.
|
||||
*/
|
||||
public static Class<?> getTileEntityClass() {
|
||||
return getMinecraftClass("TileEntity");
|
||||
return getMinecraftClass("world.level.block.entity.TileEntity", "TileEntity");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1820,7 +1806,54 @@ public class MinecraftReflection {
|
||||
* @return The PlayerInfoData class
|
||||
*/
|
||||
public static Class<?> getPlayerInfoDataClass() {
|
||||
return getMinecraftClass("PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
return getMinecraftClass("network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData",
|
||||
"PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the entity use action class in 1.17.
|
||||
* @return The EntityUseAction class
|
||||
*/
|
||||
public static Class<?> getEnumEntityUseActionClass() {
|
||||
Class<?> packetClass = PacketType.Play.Client.USE_ENTITY.getPacketClass();
|
||||
return FuzzyReflection.fromClass(packetClass, true).getFieldByType("^.*(EnumEntityUseAction)").getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a method accessor to get the actual use action out of the wrapping EnumEntityUseAction in 1.17.
|
||||
* @return a method accessor to get the actual use action
|
||||
*/
|
||||
public static MethodAccessor getEntityUseActionEnumMethodAccessor() {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getEnumEntityUseActionClass(), true);
|
||||
return Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(EnumWrappers.getEntityUseActionClass())
|
||||
.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field accessor for the hand in the wrapping EnumEntityUseAction in 1.17.
|
||||
*
|
||||
* @param enumEntityUseAction the object instance of the action, the field is not present in attack.
|
||||
* @return a field accessor for the hand in the wrapping EnumEntityUseAction
|
||||
*/
|
||||
public static FieldAccessor getHandEntityUseActionEnumFieldAccessor(Object enumEntityUseAction) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromObject(enumEntityUseAction, true);
|
||||
return Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.typeExact(EnumWrappers.getHandClass())
|
||||
.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field accessor for the vec3d in the wrapping EnumEntityUseAction in 1.17.
|
||||
*
|
||||
* @param enumEntityUseAction the object instance of the action, the field is not present in attack.
|
||||
* @return a field accessor for the hand in the wrapping EnumEntityUseAction
|
||||
*/
|
||||
public static FieldAccessor getVec3EntityUseActionEnumFieldAccessor(Object enumEntityUseAction) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromObject(enumEntityUseAction, true);
|
||||
return Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract.newBuilder()
|
||||
.typeExact(MinecraftReflection.getVec3DClass())
|
||||
.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1837,7 +1870,7 @@ public class MinecraftReflection {
|
||||
* @return The IBlockData class
|
||||
*/
|
||||
public static Class<?> getIBlockDataClass() {
|
||||
return getMinecraftClass("IBlockData");
|
||||
return getMinecraftClass("world.level.block.state.IBlockData", "IBlockData");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1856,16 +1889,35 @@ public class MinecraftReflection {
|
||||
return getArrayClass(getMultiBlockChangeInfoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the PacketPlayOutGameStateChange.a class, aka GameState in 1.16
|
||||
* @return The GameState class
|
||||
*/
|
||||
public static Class<?> getGameStateClass() {
|
||||
// it's called "a" so there's not a whole lot we can do to identify it
|
||||
Class<?> packetClass = PacketType.Play.Server.GAME_STATE_CHANGE.getPacketClass();
|
||||
return packetClass.getClasses()[0];
|
||||
}
|
||||
|
||||
public static boolean signUpdateExists() {
|
||||
try {
|
||||
return getMinecraftClass("PacketPlayOutUpdateSign") != null;
|
||||
} catch (RuntimeException ex) {
|
||||
return false;
|
||||
}
|
||||
return getNullableNMS("PacketPlayOutUpdateSign") != null;
|
||||
}
|
||||
|
||||
public static Class<?> getNonNullListClass() {
|
||||
return getMinecraftClass("NonNullList");
|
||||
return getMinecraftClass("core.NonNullList", "NonNullList");
|
||||
}
|
||||
|
||||
public static MethodAccessor getNonNullListCreateAccessor() {
|
||||
try {
|
||||
Class<?> nonNullListType = MinecraftReflection.getNonNullListClass();
|
||||
return Accessors.getMethodAccessor(FuzzyReflection.fromClass(nonNullListType).getMethod(
|
||||
FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(nonNullListType)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getCraftSoundClass() {
|
||||
@@ -1873,7 +1925,7 @@ public class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getSectionPositionClass() {
|
||||
return getMinecraftClass("SectionPosition");
|
||||
return getMinecraftClass("core.SectionPosition", "SectionPosition");
|
||||
}
|
||||
|
||||
// ---- ItemStack conversions
|
||||
@@ -2027,10 +2079,12 @@ public class MinecraftReflection {
|
||||
.orElseThrow(() -> new RuntimeException("Failed to find NMS class: " + className));
|
||||
}
|
||||
|
||||
public static Class<?> getNullableNMS(String className) {
|
||||
if (minecraftPackage == null)
|
||||
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
|
||||
return minecraftPackage.getPackageClass(className).orElse(null);
|
||||
public static Class<?> getNullableNMS(String className, String... aliases) {
|
||||
try {
|
||||
return getMinecraftClass(className, aliases);
|
||||
} catch (RuntimeException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2163,4 +2217,74 @@ public class MinecraftReflection {
|
||||
throw new RuntimeException("Cannot construct packet serializer.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getNbtTagTypes() {
|
||||
return getMinecraftClass("nbt.NBTTagTypes", "NBTTagTypes");
|
||||
}
|
||||
|
||||
public static Class<?> getChatDeserializer() {
|
||||
return getMinecraftClass("util.ChatDeserializer", "ChatDeserializer");
|
||||
}
|
||||
|
||||
public static Class<?> getDimensionManager() {
|
||||
return getMinecraftClass("world.level.dimension.DimensionManager", "DimensionManager");
|
||||
}
|
||||
|
||||
public static Class<?> getMerchantRecipeList() {
|
||||
return getMinecraftClass("world.item.trading.MerchantRecipeList", "MerchantRecipeList");
|
||||
}
|
||||
|
||||
public static Class<?> getResourceKey() {
|
||||
return getMinecraftClass("resources.ResourceKey", "ResourceKey");
|
||||
}
|
||||
|
||||
public static Class<?> getEntityTypes() {
|
||||
return getMinecraftClass("world.entity.EntityTypes", "EntityTypes");
|
||||
}
|
||||
|
||||
public static Class<?> getParticleParam() {
|
||||
return getMinecraftClass("core.particles.ParticleParam", "ParticleParam");
|
||||
}
|
||||
|
||||
public static Class<?> getSectionPosition() {
|
||||
return getMinecraftClass("core.SectionPosition", "SectionPosition");
|
||||
}
|
||||
|
||||
public static Class<?> getChunkProviderServer() {
|
||||
return getMinecraftClass("server.level.ChunkProviderServer", "ChunkProviderServer");
|
||||
}
|
||||
|
||||
public static Class<?> getPlayerChunkMap() {
|
||||
return getMinecraftClass("server.level.PlayerChunkMap", "PlayerChunkMap");
|
||||
}
|
||||
|
||||
public static Class<?> getIRegistry() {
|
||||
return getNullableNMS("core.IRegistry", "IRegistry");
|
||||
}
|
||||
|
||||
public static Class<?> getAttributeBase() {
|
||||
return getMinecraftClass("world.entity.ai.attributes.AttributeBase", "AttributeBase");
|
||||
}
|
||||
|
||||
public static Class<?> getFastUtilClass(String className) {
|
||||
return getLibraryClass("it.unimi.dsi.fastutil." + className);
|
||||
}
|
||||
|
||||
public static Class<?> getInt2ObjectMapClass() {
|
||||
return getFastUtilClass("ints.Int2ObjectMap");
|
||||
}
|
||||
|
||||
public static Class<?> getIntArrayListClass() {
|
||||
return getFastUtilClass("ints.IntArrayList");
|
||||
}
|
||||
|
||||
public static Class<?> getLibraryClass(String classname) {
|
||||
try {
|
||||
return getMinecraftLibraryClass(classname);
|
||||
} catch (RuntimeException ex) {
|
||||
Class<?> clazz = getMinecraftLibraryClass("org.bukkit.craftbukkit.libs." + classname);
|
||||
setMinecraftLibraryClass(classname, clazz);
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,16 @@ public class MinecraftVersion implements Comparable<MinecraftVersion>, Serializa
|
||||
*/
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
|
||||
|
||||
/**
|
||||
* Version 1.18 - caves and cliffs part 2
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_2 = new MinecraftVersion("1.18");
|
||||
|
||||
/**
|
||||
* Version 1.17 - caves and cliffs part 1
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17");
|
||||
|
||||
/**
|
||||
* Version 1.16.2 - breaking change to the nether update
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import io.netty.util.Version;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class NettyVersion {
|
||||
private final static String NETTY_COMMON_ID = "netty-common";
|
||||
private final static String NETTY_ALL_ID = "netty-all";
|
||||
private static NettyVersion version;
|
||||
|
||||
public static NettyVersion getVersion() {
|
||||
if(version == null) {
|
||||
version = detectVersion();
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
private static NettyVersion detectVersion() {
|
||||
Map<String, Version> nettyArtifacts = Version.identify();
|
||||
Version version = nettyArtifacts.get(NETTY_COMMON_ID);
|
||||
if(version == null) {
|
||||
version = nettyArtifacts.get(NETTY_ALL_ID);
|
||||
}
|
||||
if(version != null) {
|
||||
return new NettyVersion(version.artifactVersion());
|
||||
}
|
||||
return new NettyVersion(null);
|
||||
}
|
||||
|
||||
private boolean valid = false;
|
||||
private int major, minor, revision;
|
||||
|
||||
public NettyVersion(String s) {
|
||||
if(s == null) {
|
||||
return;
|
||||
}
|
||||
String[] split = s.split( "\\.");
|
||||
try {
|
||||
this.major = Integer.parseInt(split[0]);
|
||||
this.minor = Integer.parseInt(split[1]);
|
||||
this.revision = Integer.parseInt(split[2]);
|
||||
this.valid = true;
|
||||
} catch (Throwable t) {
|
||||
ProtocolLibrary.getPlugin().getLogger().warning("Could not detect netty version: '" + s + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if(!valid) {
|
||||
return "(invalid)";
|
||||
}
|
||||
return major + "." + minor + "." + revision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof NettyVersion)) {
|
||||
return false;
|
||||
}
|
||||
NettyVersion v = (NettyVersion) obj;
|
||||
return v.major == major && v.minor == minor && v.revision == revision;
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return this.valid;
|
||||
}
|
||||
|
||||
public boolean isGreaterThan(int major, int minor, int rev) {
|
||||
return this.major > major || this.minor > minor || this.revision > rev;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,741 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.ByteBufProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class ZeroBuffer extends ByteBuf {
|
||||
@Override
|
||||
public int capacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf capacity(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxCapacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufAllocator alloc() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteOrder order() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf order(ByteOrder byteOrder) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf unwrap() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readerIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readerIndex(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writerIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writerIndex(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setIndex(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readableBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writableBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxWritableBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(int i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(int i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf clear() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf markReaderIndex() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf resetReaderIndex() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf markWriterIndex() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf resetWriterIndex() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardReadBytes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardSomeReadBytes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf ensureWritable(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ensureWritable(int i, boolean b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getUnsignedByte(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedShort(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMedium(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedMedium(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnsignedInt(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, ByteBuf byteBuf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, ByteBuf byteBuf, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, ByteBuf byteBuf, int i1, int i2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, byte[] bytes, int i1, int i2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, ByteBuffer byteBuffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int i, OutputStream outputStream, int i1) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(int i, GatheringByteChannel gatheringByteChannel, int i1) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBoolean(int i, boolean b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setByte(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setShort(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setMedium(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setInt(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setLong(int i, long l) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setChar(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setFloat(int i, float v) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setDouble(int i, double v) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int i, ByteBuf byteBuf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int i, ByteBuf byteBuf, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int i, ByteBuf byteBuf, int i1, int i2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int i, byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int i, byte[] bytes, int i1, int i2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int i, ByteBuffer byteBuffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int i, InputStream inputStream, int i1) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int i, ScatteringByteChannel scatteringByteChannel, int i1) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setZero(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readUnsignedByte() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedShort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readMedium() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedMedium() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readSlice(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf byteBuf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf byteBuf, int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf byteBuf, int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] bytes, int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuffer byteBuffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(OutputStream outputStream, int i) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBytes(GatheringByteChannel gatheringByteChannel, int i) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf skipBytes(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBoolean(boolean b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeByte(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeShort(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeMedium(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeInt(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeLong(long l) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeChar(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeFloat(float v) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeDouble(double v) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf byteBuf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf byteBuf, int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf byteBuf, int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] bytes, int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuffer byteBuffer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(InputStream inputStream, int i) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(ScatteringByteChannel scatteringByteChannel, int i) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeZero(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(int i, int i1, byte b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(byte b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int i, byte b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int i, int i1, byte b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor byteBufProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int i, int i1, ByteBufProcessor byteBufProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor byteBufProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int i, int i1, ByteBufProcessor byteBufProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf duplicate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nioBufferCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer internalNioBuffer(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers() {
|
||||
return new ByteBuffer[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers(int i, int i1) {
|
||||
return new ByteBuffer[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] array() {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMemoryAddress() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long memoryAddress() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Charset charset) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int i, int i1, Charset charset) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ByteBuf byteBuf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retain(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCnt() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retain() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2015 dmulloy2
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
/**
|
||||
* Utility class for converting between the Adventure API Component and ProtocolLib's wrapper
|
||||
* <p>
|
||||
* Note: The Adventure API Component is not included in CraftBukkit, Bukkit or Spigot and but is present in PaperMC.
|
||||
*/
|
||||
public class AdventureComponentConverter {
|
||||
|
||||
private AdventureComponentConverter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link WrappedChatComponent} into a {@link Component}
|
||||
* @param wrapper ProtocolLib wrapper
|
||||
* @return Component
|
||||
*/
|
||||
public static Component fromWrapper(WrappedChatComponent wrapper) {
|
||||
return GsonComponentSerializer.gson().deserialize(wrapper.getJson());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link Component} into a ProtocolLib wrapper
|
||||
* @param components Component
|
||||
* @return ProtocolLib wrapper
|
||||
*/
|
||||
public static WrappedChatComponent fromComponent(Component component) {
|
||||
return WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component));
|
||||
}
|
||||
|
||||
public static Class<?> getComponentClass() {
|
||||
return Component.class;
|
||||
}
|
||||
|
||||
public static Component clone(Object component) {
|
||||
return (Component) component;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,12 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
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.instances.DefaultInstances;
|
||||
import com.google.common.base.Defaults;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
@@ -41,9 +47,18 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class AutoWrapper<T> implements EquivalentConverter<T> {
|
||||
private static final Object[] NO_ARGS = new Object[0];
|
||||
|
||||
private Map<Integer, Function<Object, Object>> wrappers = new HashMap<>();
|
||||
private Map<Integer, Function<Object, Object>> unwrappers = new HashMap<>();
|
||||
|
||||
// lazy
|
||||
private FieldAccessor[] nmsAccessors;
|
||||
private FieldAccessor[] wrapperAccessors;
|
||||
|
||||
private Object[] nmsDefaultArgs;
|
||||
private ConstructorAccessor nmsInstanceCreator;
|
||||
|
||||
private Class<T> wrapperClass;
|
||||
private Class<?> nmsClass;
|
||||
|
||||
@@ -79,75 +94,77 @@ public class AutoWrapper<T> implements EquivalentConverter<T> {
|
||||
throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex);
|
||||
}
|
||||
|
||||
Field[] wrapperFields = wrapperClass.getDeclaredFields();
|
||||
Field[] nmsFields = Arrays
|
||||
.stream(nmsClass.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.toArray(Field[]::new);
|
||||
// ensures that all accessors are present
|
||||
computeFieldAccessors();
|
||||
|
||||
for (int i = 0; i < wrapperFields.length; i++) {
|
||||
try {
|
||||
Field wrapperField = wrapperFields[i];
|
||||
for (int i = 0; i < wrapperAccessors.length; i++) {
|
||||
FieldAccessor source = nmsAccessors[i];
|
||||
FieldAccessor target = wrapperAccessors[i];
|
||||
|
||||
Field nmsField = nmsFields[i];
|
||||
if (!nmsField.isAccessible())
|
||||
nmsField.setAccessible(true);
|
||||
Object value = source.get(nmsObject);
|
||||
if (wrappers.containsKey(i))
|
||||
value = wrappers.get(i).apply(value);
|
||||
|
||||
Object value = nmsField.get(nmsObject);
|
||||
if (wrappers.containsKey(i))
|
||||
value = wrappers.get(i).apply(value);
|
||||
|
||||
wrapperField.set(instance, value);
|
||||
} catch (Exception ex) {
|
||||
throw new InvalidWrapperException("Failed to wrap field at index " + i, ex);
|
||||
}
|
||||
target.set(instance, value);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Object unwrap(Object wrapper) {
|
||||
Object instance;
|
||||
// ensures that all accessors are present
|
||||
computeFieldAccessors();
|
||||
computeNmsConstructorAccess();
|
||||
|
||||
try {
|
||||
instance = nmsClass.newInstance();
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new InvalidWrapperException("Failed to construct new " + nmsClass.getSimpleName(), ex);
|
||||
}
|
||||
Object instance = nmsInstanceCreator.invoke(nmsDefaultArgs);
|
||||
|
||||
Field[] wrapperFields = wrapperClass.getDeclaredFields();
|
||||
Field[] nmsFields = Arrays
|
||||
.stream(nmsClass.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.toArray(Field[]::new);
|
||||
for (int i = 0; i < wrapperAccessors.length; i++) {
|
||||
FieldAccessor source = wrapperAccessors[i];
|
||||
FieldAccessor target = nmsAccessors[i];
|
||||
|
||||
for (int i = 0; i < wrapperFields.length; i++) {
|
||||
try {
|
||||
Field wrapperField = wrapperFields[i];
|
||||
Object value = source.get(wrapper);
|
||||
if (unwrappers.containsKey(i))
|
||||
value = unwrappers.get(i).apply(value);
|
||||
|
||||
Field nmsField = nmsFields[i];
|
||||
if (!nmsField.isAccessible())
|
||||
nmsField.setAccessible(true);
|
||||
if (Modifier.isFinal(nmsField.getModifiers()))
|
||||
unsetFinal(nmsField);
|
||||
|
||||
Object value = wrapperField.get(wrapper);
|
||||
if (unwrappers.containsKey(i))
|
||||
value = unwrappers.get(i).apply(value);
|
||||
|
||||
nmsField.set(instance, value);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new InvalidWrapperException("Failed to unwrap field", ex);
|
||||
}
|
||||
target.set(instance, value);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void unsetFinal(Field field) throws ReflectiveOperationException {
|
||||
Field modifiers = Field.class.getDeclaredField("modifiers");
|
||||
modifiers.setAccessible(true);
|
||||
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
||||
private void computeFieldAccessors() {
|
||||
if (nmsAccessors == null) {
|
||||
nmsAccessors = Arrays
|
||||
.stream(nmsClass.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.map(field -> Accessors.getFieldAccessor(field, true))
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
|
||||
if (wrapperAccessors == null) {
|
||||
wrapperAccessors = Arrays
|
||||
.stream(wrapperClass.getDeclaredFields())
|
||||
.map(field -> Accessors.getFieldAccessor(field, true))
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeNmsConstructorAccess() {
|
||||
if (nmsInstanceCreator == null) {
|
||||
ConstructorAccessor noArgs = Accessors.getConstructorAccessorOrNull(nmsClass);
|
||||
if (noArgs != null) {
|
||||
// no args constructor is available - use it
|
||||
nmsInstanceCreator = noArgs;
|
||||
nmsDefaultArgs = NO_ARGS;
|
||||
} else {
|
||||
// use the first constructor of the class
|
||||
nmsInstanceCreator = Accessors.getConstructorAccessor(nmsClass.getDeclaredConstructors()[0]);
|
||||
nmsDefaultArgs = Arrays
|
||||
.stream(nmsInstanceCreator.getConstructor().getParameterTypes())
|
||||
.map(type -> type.isPrimitive() ? Defaults.defaultValue(type) : null)
|
||||
.toArray(Object[]::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Equivalent conversion
|
||||
|
||||
@@ -17,12 +17,16 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -42,6 +46,7 @@ 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.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
@@ -49,12 +54,17 @@ import com.comphenix.protocol.wrappers.EnumWrappers.Dimension;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.FauxEnumConverter;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
@@ -257,6 +267,87 @@ public class BukkitConverters {
|
||||
};
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, Supplier<List<Object>>> LIST_SUPPLIERS = new ConcurrentHashMap<>();
|
||||
|
||||
private static <T> Object getGenericList(Class<?> listClass, List<T> specific, EquivalentConverter<T> itemConverter) {
|
||||
List<Object> newList;
|
||||
Supplier<List<Object>> supplier = LIST_SUPPLIERS.get(listClass);
|
||||
if (supplier == null) {
|
||||
try {
|
||||
Constructor<?> ctor = listClass.getConstructor();
|
||||
newList = (List<Object>) ctor.newInstance();
|
||||
supplier = () -> {
|
||||
try {
|
||||
return (List<Object>) ctor.newInstance();
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
};
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
// ex.printStackTrace();
|
||||
supplier = ArrayList::new;
|
||||
newList = new ArrayList<>();
|
||||
}
|
||||
|
||||
LIST_SUPPLIERS.put(listClass, supplier);
|
||||
} else {
|
||||
newList = supplier.get();
|
||||
}
|
||||
|
||||
// Convert each object
|
||||
for (T position : specific) {
|
||||
if (position != null) {
|
||||
Object converted = itemConverter.getGeneric(position);
|
||||
if (converted != null) {
|
||||
newList.add(converted);
|
||||
}
|
||||
} else {
|
||||
newList.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
private static <T> List<T> getSpecificList(Object generic, EquivalentConverter<T> itemConverter) {
|
||||
if (generic instanceof Collection) {
|
||||
List<T> items = new ArrayList<>();
|
||||
|
||||
// Copy everything to a new list
|
||||
for (Object item : (Collection<Object>) generic) {
|
||||
T result = itemConverter.getSpecific(item);
|
||||
|
||||
if (item != null)
|
||||
items.add(result);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
// Not valid
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> EquivalentConverter<List<T>> getListConverter(final Class<?> listClass, final EquivalentConverter<T> itemConverter) {
|
||||
return ignoreNull(new EquivalentConverter<List<T>>() {
|
||||
@Override
|
||||
public List<T> getSpecific(Object generic) {
|
||||
return getSpecificList(generic, itemConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(List<T> specific) {
|
||||
return getGenericList(listClass, specific, itemConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<List<T>> getSpecificType() {
|
||||
// Damn you Java
|
||||
Class<?> dummy = List.class;
|
||||
return (Class<List<T>>) dummy;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an equivalent converter for a list of generic items.
|
||||
* @param <T> Type
|
||||
@@ -268,46 +359,12 @@ public class BukkitConverters {
|
||||
return ignoreNull(new EquivalentConverter<List<T>>() {
|
||||
@Override
|
||||
public List<T> getSpecific(Object generic) {
|
||||
if (generic instanceof Collection) {
|
||||
List<T> items = new ArrayList<>();
|
||||
|
||||
// Copy everything to a new list
|
||||
for (Object item : (Collection<Object>) generic) {
|
||||
T result = itemConverter.getSpecific(item);
|
||||
|
||||
if (item != null)
|
||||
items.add(result);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
// Not valid
|
||||
return null;
|
||||
return getSpecificList(generic, itemConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(List<T> specific) {
|
||||
List<Object> newList;
|
||||
|
||||
try {
|
||||
newList = (List<Object>) specific.getClass().newInstance();
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
newList = new ArrayList<>();
|
||||
}
|
||||
|
||||
// Convert each object
|
||||
for (T position : specific) {
|
||||
if (position != null) {
|
||||
Object converted = itemConverter.getGeneric(position);
|
||||
if (converted != null) {
|
||||
newList.add(converted);
|
||||
}
|
||||
} else {
|
||||
newList.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
return newList;
|
||||
return getGenericList(specific.getClass(), specific, itemConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -349,20 +406,6 @@ public class BukkitConverters {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated While this solution is not as abhorrent as I had imagined, I still highly recommend switching to the
|
||||
* new conversion API.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T> EquivalentConverter<Set<T>> getSetConverter(final Class<?> genericType,
|
||||
final EquivalentConverter<T> itemConverter) {
|
||||
if (itemConverter instanceof EnumWrappers.EnumConverter) {
|
||||
((EnumWrappers.EnumConverter) itemConverter).setGenericType(genericType);
|
||||
}
|
||||
|
||||
return getSetConverter(itemConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an equivalent converter for a set of generic items.
|
||||
* @param <T> Element type
|
||||
@@ -674,7 +717,7 @@ public class BukkitConverters {
|
||||
ProtocolManager manager = managerRef.get();
|
||||
|
||||
// Use the entity ID to get a reference to the entity
|
||||
if (id != null && manager != null) {
|
||||
if (id != null && id >= 0 && manager != null) {
|
||||
return manager.getEntityFromID(world, id);
|
||||
} else {
|
||||
return null;
|
||||
@@ -700,7 +743,7 @@ public class BukkitConverters {
|
||||
@Override
|
||||
public Object getGeneric(EntityType specific) {
|
||||
if (entityTypeFromName == null) {
|
||||
Class<?> entityTypesClass = MinecraftReflection.getMinecraftClass("EntityTypes");
|
||||
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
|
||||
entityTypeFromName = Accessors.getMethodAccessor(
|
||||
FuzzyReflection
|
||||
.fromClass(entityTypesClass, false)
|
||||
@@ -718,7 +761,7 @@ public class BukkitConverters {
|
||||
@Override
|
||||
public EntityType getSpecific(Object generic) {
|
||||
if (getEntityTypeName == null) {
|
||||
Class<?> entityTypesClass = MinecraftReflection.getMinecraftClass("EntityTypes");
|
||||
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
|
||||
getEntityTypeName = Accessors.getMethodAccessor(
|
||||
FuzzyReflection
|
||||
.fromClass(entityTypesClass, false)
|
||||
@@ -1075,7 +1118,7 @@ public class BukkitConverters {
|
||||
public Advancement getSpecific(Object generic) {
|
||||
try {
|
||||
return (Advancement) getCraftBukkitClass("advancement.CraftAdvancement")
|
||||
.getConstructor(getMinecraftClass("Advancement"))
|
||||
.getConstructor(getMinecraftClass("advancements.Advancement", "Advancement"))
|
||||
.newInstance(generic);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
@@ -1194,7 +1237,12 @@ public class BukkitConverters {
|
||||
public Object getGeneric(PotionEffectType specific) {
|
||||
Class<?> clazz = MinecraftReflection.getMobEffectListClass();
|
||||
if (getMobEffect == null) {
|
||||
getMobEffect = Accessors.getMethodAccessor(clazz, "fromId", int.class);
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
|
||||
getMobEffect = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactArray(int.class)
|
||||
.returnTypeExact(clazz)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
}
|
||||
|
||||
int id = specific.getId();
|
||||
@@ -1205,7 +1253,12 @@ public class BukkitConverters {
|
||||
public PotionEffectType getSpecific(Object generic) {
|
||||
Class<?> clazz = MinecraftReflection.getMobEffectListClass();
|
||||
if (getMobEffectId == null) {
|
||||
getMobEffectId = Accessors.getMethodAccessor(clazz, "getId", clazz);
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
|
||||
getMobEffectId = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactArray(clazz)
|
||||
.returnTypeExact(int.class)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
}
|
||||
|
||||
int id = (int) getMobEffectId.invoke(null, generic);
|
||||
@@ -1234,7 +1287,7 @@ public class BukkitConverters {
|
||||
|
||||
if (worldKeyField == null) {
|
||||
Class<?> worldClass = MinecraftReflection.getNmsWorldClass();
|
||||
Class<?> resourceKeyClass = MinecraftReflection.getMinecraftClass("ResourceKey");
|
||||
Class<?> resourceKeyClass = MinecraftReflection.getResourceKey();
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(nmsWorld.getClass(), true);
|
||||
worldKeyField = Accessors.getFieldAccessor(fuzzy.getParameterizedField(resourceKeyClass, worldClass));
|
||||
@@ -1294,14 +1347,95 @@ public class BukkitConverters {
|
||||
}
|
||||
}
|
||||
|
||||
private static FieldAccessor dimensionKey;
|
||||
private static MethodAccessor worldHandleAccessor;
|
||||
private static MethodAccessor worldHandleDimensionManagerAccessor;
|
||||
|
||||
public static EquivalentConverter<World> getDimensionConverter() {
|
||||
return ignoreNull(new EquivalentConverter<World>() {
|
||||
@Override
|
||||
public Object getGeneric(World specific) {
|
||||
return getWorldHandleDimensionManagerAccessor().invoke(getWorldHandleAccessor().invoke(specific));
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getSpecific(Object generic) {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
if (getGeneric(world) == generic) {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<World> getSpecificType() {
|
||||
return World.class;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static MethodAccessor getWorldHandleAccessor() {
|
||||
if (worldHandleAccessor == null) {
|
||||
Method handleMethod = FuzzyReflection.fromClass(MinecraftReflection.getCraftWorldClass())
|
||||
.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.nameExact("getHandle") // i guess this will never change
|
||||
.returnTypeExact(MinecraftReflection.getWorldServerClass())
|
||||
.build());
|
||||
worldHandleAccessor = Accessors.getMethodAccessor(handleMethod);
|
||||
}
|
||||
return worldHandleAccessor;
|
||||
}
|
||||
|
||||
private static MethodAccessor getWorldHandleDimensionManagerAccessor() {
|
||||
if (worldHandleDimensionManagerAccessor == null) {
|
||||
Method dimensionGetter = FuzzyReflection.fromClass(MinecraftReflection.getWorldServerClass())
|
||||
.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(MinecraftReflection.getDimensionManager())
|
||||
.build());
|
||||
worldHandleDimensionManagerAccessor = Accessors.getMethodAccessor(dimensionGetter);
|
||||
}
|
||||
return worldHandleDimensionManagerAccessor;
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Integer> getDimensionIDConverter() {
|
||||
return ignoreNull(new EquivalentConverter<Integer>() {
|
||||
@Override
|
||||
public Object getGeneric(Integer specific) {
|
||||
if (dimensionManager == null) {
|
||||
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
|
||||
dimensionManager = MinecraftReflection.getDimensionManager();
|
||||
}
|
||||
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
World world = null;
|
||||
if (specific == 0) {
|
||||
world = Bukkit.getWorlds().get(0);
|
||||
} else if (specific == -1) {
|
||||
for (World world1 : Bukkit.getWorlds()) {
|
||||
if (world1.getEnvironment() == World.Environment.NETHER) {
|
||||
world = world1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (specific == 1) {
|
||||
for (World world1 : Bukkit.getWorlds()) {
|
||||
if (world1.getEnvironment() == World.Environment.THE_END) {
|
||||
world = world1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (world != null) {
|
||||
try {
|
||||
return getWorldHandleDimensionManagerAccessor().invoke(getWorldHandleAccessor().invoke(world));
|
||||
} catch (Exception ignored) {
|
||||
// method not available, fall through
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
|
||||
if (dimensionImplConverter == null) {
|
||||
dimensionImplConverter = new FauxEnumConverter<>(DimensionImpl.class, dimensionManager);
|
||||
@@ -1335,9 +1469,31 @@ public class BukkitConverters {
|
||||
@Override
|
||||
public Integer getSpecific(Object generic) {
|
||||
if (dimensionManager == null) {
|
||||
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
|
||||
dimensionManager = MinecraftReflection.getDimensionManager();
|
||||
}
|
||||
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
if (dimensionKey == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(dimensionManager, false);
|
||||
dimensionKey = Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract
|
||||
.newBuilder()
|
||||
.typeExact(MinecraftReflection.getMinecraftKeyClass())
|
||||
.banModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
}
|
||||
|
||||
MinecraftKey key = MinecraftKey.fromHandle(dimensionKey.get(generic));
|
||||
switch (key.getKey()) {
|
||||
case "overworld":
|
||||
return Dimension.OVERWORLD.getId();
|
||||
case "the_nether":
|
||||
return Dimension.THE_NETHER.getId();
|
||||
case "the_end":
|
||||
return Dimension.THE_END.getId();
|
||||
default:
|
||||
throw new IllegalArgumentException("id not supported for extra dimensions");
|
||||
}
|
||||
}
|
||||
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
|
||||
if (dimensionImplConverter == null) {
|
||||
dimensionImplConverter = new FauxEnumConverter<>(DimensionImpl.class, dimensionManager);
|
||||
@@ -1393,7 +1549,7 @@ public class BukkitConverters {
|
||||
@Override
|
||||
public Object getGeneric(List<MerchantRecipe> specific) {
|
||||
if (merchantRecipeListConstructor == null) {
|
||||
Class<?> merchantRecipeListClass = MinecraftReflection.getMinecraftClass("MerchantRecipeList");
|
||||
Class<?> merchantRecipeListClass = MinecraftReflection.getMerchantRecipeList();
|
||||
merchantRecipeListConstructor = Accessors.getConstructorAccessor(merchantRecipeListClass);
|
||||
Class<?> craftMerchantRecipeClass = MinecraftReflection.getCraftBukkitClass("inventory.CraftMerchantRecipe");
|
||||
FuzzyReflection reflection = FuzzyReflection.fromClass(craftMerchantRecipeClass, false);
|
||||
@@ -1407,7 +1563,9 @@ public class BukkitConverters {
|
||||
@Override
|
||||
public List<MerchantRecipe> getSpecific(Object generic) {
|
||||
if (nmsMerchantRecipeToBukkit == null) {
|
||||
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass("MerchantRecipe");
|
||||
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass(
|
||||
"world.item.trading.MerchantRecipe","MerchantRecipe"
|
||||
);
|
||||
FuzzyReflection reflection = FuzzyReflection.fromClass(merchantRecipeClass, false);
|
||||
nmsMerchantRecipeToBukkit = Accessors.getMethodAccessor(reflection.getMethodByName("asBukkit"));
|
||||
}
|
||||
@@ -1432,7 +1590,7 @@ public class BukkitConverters {
|
||||
@Override
|
||||
public Object getGeneric(BlockPosition specific) {
|
||||
if (sectionPositionClass == null) {
|
||||
sectionPositionClass = MinecraftReflection.getMinecraftClass("SectionPosition");
|
||||
sectionPositionClass = MinecraftReflection.getSectionPosition();
|
||||
}
|
||||
|
||||
if (sectionPositionCreate == null) {
|
||||
@@ -1461,4 +1619,73 @@ public class BukkitConverters {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Field gameStateMapField;
|
||||
private static Field gameStateIdField;
|
||||
|
||||
public static EquivalentConverter<Integer> getGameStateConverter() {
|
||||
return new EquivalentConverter<Integer>() {
|
||||
@Override
|
||||
public Object getGeneric(Integer specific) {
|
||||
if (specific == null) {
|
||||
specific = 0;
|
||||
}
|
||||
|
||||
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
|
||||
if (gameStateMapField == null) {
|
||||
Class<?> stateClass = MinecraftReflection.getGameStateClass();
|
||||
gameStateMapField = FuzzyReflection
|
||||
.fromClass(stateClass, true)
|
||||
.getField(FuzzyFieldContract
|
||||
.newBuilder()
|
||||
.typeDerivedOf(Map.class)
|
||||
.build());
|
||||
gameStateMapField.setAccessible(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Map<Integer, Object> map = (Map<Integer, Object>) gameStateMapField.get(null);
|
||||
return map.get(specific);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} else {
|
||||
return specific;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSpecific(Object generic) {
|
||||
if (generic == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
|
||||
if (gameStateIdField == null) {
|
||||
Class<?> stateClass = MinecraftReflection.getGameStateClass();
|
||||
gameStateIdField = FuzzyReflection
|
||||
.fromClass(stateClass, true)
|
||||
.getField(FuzzyFieldContract
|
||||
.newBuilder()
|
||||
.typeExact(int.class)
|
||||
.build());
|
||||
gameStateIdField.setAccessible(true);
|
||||
}
|
||||
|
||||
try {
|
||||
return (Integer) gameStateIdField.get(generic);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} else {
|
||||
return (Integer) generic;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Integer> getSpecificType() {
|
||||
return Integer.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
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.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a ChunkCoordIntPair.
|
||||
* @author Kristian
|
||||
@@ -79,9 +85,14 @@ public class ChunkCoordIntPair {
|
||||
public ChunkCoordIntPair getSpecific(Object generic) {
|
||||
if (MinecraftReflection.isChunkCoordIntPair(generic)) {
|
||||
if (COORD_X == null || COORD_Z == null) {
|
||||
FieldAccessor[] ints = Accessors.getFieldAccessorArray(COORD_PAIR_CLASS, int.class, true);
|
||||
COORD_X = ints[0];
|
||||
COORD_Z = ints[1];
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(COORD_PAIR_CLASS, true);
|
||||
List<Field> fields = fuzzy.getFieldList(FuzzyFieldContract
|
||||
.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.typeExact(int.class)
|
||||
.build());
|
||||
COORD_X = Accessors.getFieldAccessor(fields.get(0));
|
||||
COORD_Z = Accessors.getFieldAccessor(fields.get(1));
|
||||
}
|
||||
return new ChunkCoordIntPair((Integer) COORD_X.get(generic), (Integer) COORD_Z.get(generic));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
@@ -150,4 +151,24 @@ public class Converters {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> EquivalentConverter<Optional<T>> optional(final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<Optional<T>>() {
|
||||
@Override
|
||||
public Object getGeneric(Optional<T> specific) {
|
||||
return specific.map(converter::getGeneric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> getSpecific(Object generic) {
|
||||
Optional<Object> optional = (Optional<Object>) generic;
|
||||
return optional.map(converter::getSpecific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Optional<T>> getSpecificType() {
|
||||
return (Class<Optional<T>>) Optional.empty().getClass();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@@ -383,6 +384,7 @@ public abstract class EnumWrappers {
|
||||
SWIMMING,
|
||||
SPIN_ATTACK,
|
||||
CROUCHING,
|
||||
LONG_JUMPING,
|
||||
DYING;
|
||||
|
||||
private final static EquivalentConverter<EntityPose> POSE_CONVERTER = EnumWrappers.getEntityPoseConverter();
|
||||
@@ -481,7 +483,6 @@ public abstract class EnumWrappers {
|
||||
DIFFICULTY_CLASS = getEnum(PacketType.Play.Server.LOGIN.getPacketClass(), 1);
|
||||
}
|
||||
|
||||
ENTITY_USE_ACTION_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 0);
|
||||
GAMEMODE_CLASS = getEnum(PacketType.Play.Server.LOGIN.getPacketClass(), 0);
|
||||
RESOURCE_PACK_STATUS_CLASS = getEnum(PacketType.Play.Client.RESOURCE_PACK_STATUS.getPacketClass(), 0);
|
||||
PLAYER_INFO_ACTION_CLASS = getEnum(PacketType.Play.Server.PLAYER_INFO.getPacketClass(), 0);
|
||||
@@ -496,21 +497,29 @@ public abstract class EnumWrappers {
|
||||
|
||||
try {
|
||||
// TODO enum names are more stable than their packet associations
|
||||
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("EnumItemSlot");
|
||||
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("world.entity.EnumItemSlot", "EnumItemSlot");
|
||||
} catch (Exception ex) {
|
||||
ITEM_SLOT_CLASS = getEnum(PacketType.Play.Server.ENTITY_EQUIPMENT.getPacketClass(), 0);
|
||||
}
|
||||
|
||||
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
|
||||
// In 1.17 the hand and use action class is no longer a field in the packet
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
HAND_CLASS = MinecraftReflection.getMinecraftClass("world.EnumHand");
|
||||
// class is named 'b' in the packet but class order differs in spigot and paper so we can only use the first method's return type (safest way)
|
||||
ENTITY_USE_ACTION_CLASS = MinecraftReflection.getEnumEntityUseActionClass().getMethods()[0].getReturnType();
|
||||
} else {
|
||||
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
|
||||
ENTITY_USE_ACTION_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 0);
|
||||
}
|
||||
|
||||
DIRECTION_CLASS = getEnum(PacketType.Play.Server.SPAWN_ENTITY_PAINTING.getPacketClass(), 0);
|
||||
CHAT_TYPE_CLASS = getEnum(PacketType.Play.Server.CHAT.getPacketClass(), 0);
|
||||
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("EntityPose");
|
||||
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("world.entity.EntityPose", "EntityPose");
|
||||
|
||||
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
|
||||
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
|
||||
associate(CHAT_VISIBILITY_CLASS, ChatVisibility.class, getChatVisibilityConverter());
|
||||
associate(DIFFICULTY_CLASS, Difficulty.class, getDifficultyConverter());
|
||||
associate(ENTITY_USE_ACTION_CLASS, EntityUseAction.class, getEntityUseActionConverter());
|
||||
associate(GAMEMODE_CLASS, NativeGameMode.class, getGameModeConverter());
|
||||
associate(RESOURCE_PACK_STATUS_CLASS, ResourcePackStatus.class, getResourcePackStatusConverter());
|
||||
associate(PLAYER_INFO_ACTION_CLASS, PlayerInfoAction.class, getPlayerInfoActionConverter());
|
||||
@@ -523,15 +532,14 @@ public abstract class EnumWrappers {
|
||||
associate(PARTICLE_CLASS, Particle.class, getParticleConverter());
|
||||
associate(SOUND_CATEGORY_CLASS, SoundCategory.class, getSoundCategoryConverter());
|
||||
associate(ITEM_SLOT_CLASS, ItemSlot.class, getItemSlotConverter());
|
||||
associate(HAND_CLASS, Hand.class, getHandConverter());
|
||||
associate(DIRECTION_CLASS, Direction.class, getDirectionConverter());
|
||||
associate(CHAT_TYPE_CLASS, ChatType.class, getChatTypeConverter());
|
||||
|
||||
associate(HAND_CLASS, Hand.class, getHandConverter());
|
||||
associate(ENTITY_USE_ACTION_CLASS, EntityUseAction.class, getEntityUseActionConverter());
|
||||
|
||||
if (ENTITY_POSE_CLASS != null) {
|
||||
associate(ENTITY_POSE_CLASS, EntityPose.class, getEntityPoseConverter());
|
||||
}
|
||||
|
||||
INITIALIZED = true;
|
||||
}
|
||||
|
||||
private static void associate(Class<?> nativeClass, Class<?> wrapperClass, EquivalentConverter<?> converter) {
|
||||
@@ -550,12 +558,19 @@ public abstract class EnumWrappers {
|
||||
* @return The type of the enum field.
|
||||
*/
|
||||
private static Class<?> getEnum(Class<?> clazz, int index) {
|
||||
try {
|
||||
return FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class).get(index).getType();
|
||||
} catch (Throwable ex) {
|
||||
ProtocolLogger.debug("Exception getting enum from " + clazz + " at index " + index, ex);
|
||||
if (clazz == null) {
|
||||
// not supported in the current version
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Field> enumFields = FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class);
|
||||
if (enumFields.size() <= index) {
|
||||
// also probably not supported
|
||||
ProtocolLogger.debug("Enum field not found at index {0} of {1}", index, clazz);
|
||||
return null;
|
||||
}
|
||||
|
||||
return enumFields.get(index).getType();
|
||||
}
|
||||
|
||||
public static Map<Class<?>, EquivalentConverter<?>> getFromNativeMap() {
|
||||
@@ -772,22 +787,17 @@ public abstract class EnumWrappers {
|
||||
return new EnumConverter<>(genericClass, specificType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Replaced with {@link #getGenericConverter(Class, Class)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T extends Enum<T>> EquivalentConverter<T> getGenericConverter(Class<T> specificType) {
|
||||
return new EnumConverter<>(null, specificType);
|
||||
}
|
||||
|
||||
/**
|
||||
* The common Enum converter
|
||||
*/
|
||||
public static class EnumConverter<T extends Enum<T>> implements EquivalentConverter<T> {
|
||||
private Class<?> genericType;
|
||||
private Class<T> specificType;
|
||||
private final Class<?> genericType;
|
||||
private final Class<T> specificType;
|
||||
|
||||
public EnumConverter(Class<?> genericType, Class<T> specificType) {
|
||||
Validate.notNull(specificType, "specificType cannot be null");
|
||||
// would love to check if genericType is null, but it breaks other stuff
|
||||
|
||||
this.genericType = genericType;
|
||||
this.specificType = specificType;
|
||||
}
|
||||
@@ -806,10 +816,6 @@ public abstract class EnumWrappers {
|
||||
public Class<T> getSpecificType() {
|
||||
return specificType;
|
||||
}
|
||||
|
||||
void setGenericType(Class<?> genericType) {
|
||||
this.genericType = genericType;
|
||||
}
|
||||
}
|
||||
|
||||
public interface AliasedEnum {
|
||||
|
||||
@@ -10,7 +10,8 @@ import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class MovingObjectPositionBlock implements Cloneable {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("MovingObjectPositionBlock");
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.phys.MovingObjectPositionBlock", "MovingObjectPositionBlock");
|
||||
|
||||
private BlockPosition position;
|
||||
private Vector posVector;
|
||||
|
||||
@@ -17,12 +17,16 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Represents an immutable PlayerInfoData in the PLAYER_INFO packet.
|
||||
@@ -94,14 +98,17 @@ public class PlayerInfoData {
|
||||
public Object getGeneric(PlayerInfoData specific) {
|
||||
if (constructor == null) {
|
||||
try {
|
||||
// public PlayerInfoData(Packet, GameProfile, int, GameMode, ChatComponent)
|
||||
constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor(
|
||||
MinecraftReflection.getMinecraftClass("PacketPlayOutPlayerInfo"),
|
||||
MinecraftReflection.getGameProfileClass(),
|
||||
int.class,
|
||||
EnumWrappers.getGameModeClass(),
|
||||
MinecraftReflection.getIChatBaseComponentClass()
|
||||
);
|
||||
List<Class<?>> args = new ArrayList<>();
|
||||
if (!MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
args.add(PacketType.Play.Server.PLAYER_INFO.getPacketClass());
|
||||
}
|
||||
|
||||
args.add(MinecraftReflection.getGameProfileClass());
|
||||
args.add(int.class);
|
||||
args.add(EnumWrappers.getGameModeClass());
|
||||
args.add(MinecraftReflection.getIChatBaseComponentClass());
|
||||
|
||||
constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor(args.toArray(new Class<?>[0]));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot find PlayerInfoData constructor.", e);
|
||||
}
|
||||
@@ -110,16 +117,14 @@ public class PlayerInfoData {
|
||||
// Attempt to construct the underlying PlayerInfoData
|
||||
|
||||
try {
|
||||
// public PlayerInfoData(null, GameProfile, ping, GameMode, ChatComponent)
|
||||
// The packet isn't a field, so it can be null
|
||||
Object result = constructor.newInstance(
|
||||
null,
|
||||
specific.profile.handle,
|
||||
specific.latency,
|
||||
EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode),
|
||||
specific.displayName != null ? specific.displayName.handle : null
|
||||
);
|
||||
return result;
|
||||
Object gameMode = EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode);
|
||||
Object displayName = specific.displayName != null ? specific.displayName.handle : null;
|
||||
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
return constructor.newInstance(specific.profile.handle, specific.latency, gameMode, displayName);
|
||||
} else {
|
||||
return constructor.newInstance(null, specific.profile.handle, specific.latency, gameMode, displayName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to construct PlayerInfoData.", e);
|
||||
}
|
||||
@@ -171,19 +176,19 @@ public class PlayerInfoData {
|
||||
if (obj instanceof PlayerInfoData) {
|
||||
PlayerInfoData other = (PlayerInfoData) obj;
|
||||
return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode
|
||||
&& displayName.equals(other.displayName);
|
||||
&& Objects.equals(displayName, other.displayName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(latency, gameMode, profile, displayName);
|
||||
return Objects.hash(latency, gameMode, profile, displayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s",
|
||||
return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s]",
|
||||
latency, gameMode, profile, displayName);
|
||||
}
|
||||
}
|
||||
@@ -83,10 +83,10 @@ public class Vector3F {
|
||||
}
|
||||
|
||||
private static Constructor<?> constructor = null;
|
||||
private static Class<?> clazz = MinecraftReflection.getMinecraftClass("Vector3f");
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f","Vector3f");
|
||||
|
||||
public static Class<?> getMinecraftClass() {
|
||||
return clazz;
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Vector3F> getConverter() {
|
||||
@@ -100,7 +100,7 @@ public class Vector3F {
|
||||
public Object getGeneric(Vector3F specific) {
|
||||
if (constructor == null) {
|
||||
try {
|
||||
constructor = clazz.getConstructor(float.class, float.class, float.class);
|
||||
constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ package com.comphenix.protocol.wrappers;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
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 com.comphenix.protocol.utility.MinecraftVersion;
|
||||
@@ -34,9 +33,6 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
// The one constructor
|
||||
private static Constructor<?> ATTRIBUTE_CONSTRUCTOR;
|
||||
|
||||
private static Object REGISTRY = null;
|
||||
private static MethodAccessor REGISTRY_GET = null;
|
||||
|
||||
private static final Map<String, String> REMAP;
|
||||
|
||||
static {
|
||||
@@ -76,7 +72,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
|
||||
// Initialize modifier
|
||||
if (ATTRIBUTE_MODIFIER == null) {
|
||||
ATTRIBUTE_MODIFIER = new StructureModifier<Object>(MinecraftReflection.getAttributeSnapshotClass());
|
||||
ATTRIBUTE_MODIFIER = new StructureModifier<>(MinecraftReflection.getAttributeSnapshotClass());
|
||||
}
|
||||
this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle);
|
||||
}
|
||||
@@ -115,7 +111,9 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
public String key;
|
||||
}
|
||||
|
||||
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS("AttributeBase");
|
||||
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.ai.attributes.AttributeBase", "AttributeBase"
|
||||
);
|
||||
|
||||
private static final AutoWrapper<WrappedAttributeBase> ATTRIBUTE_BASE = AutoWrapper.wrap(
|
||||
WrappedAttributeBase.class, ATTRIBUTE_BASE_CLASS
|
||||
@@ -167,8 +165,14 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
/**
|
||||
* Retrieve the parent update attributes packet.
|
||||
* @return The parent packet.
|
||||
* @deprecated Removed in 1.17
|
||||
*/
|
||||
@Nullable
|
||||
public PacketContainer getParentPacket() {
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PacketContainer(
|
||||
PacketType.Play.Server.UPDATE_ATTRIBUTES,
|
||||
modifier.withType(MinecraftReflection.getPacketClass()).read(0)
|
||||
@@ -223,7 +227,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
}
|
||||
};
|
||||
|
||||
attributeModifiers = new CachedSet<WrappedAttributeModifier>(converted);
|
||||
attributeModifiers = new CachedSet<>(converted);
|
||||
}
|
||||
return Collections.unmodifiableSet(attributeModifiers);
|
||||
}
|
||||
@@ -246,9 +250,7 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
|
||||
if (getBaseValue() == other.getBaseValue() &&
|
||||
Objects.equal(getAttributeKey(), other.getAttributeKey())) {
|
||||
return getModifiers().stream()
|
||||
.filter((elem) -> !other.getModifiers().contains(elem))
|
||||
.count() == 0;
|
||||
return other.getModifiers().containsAll(getModifiers());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -411,45 +413,33 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
* @throws RuntimeException If anything went wrong with the reflection.
|
||||
*/
|
||||
public WrappedAttribute build() {
|
||||
Preconditions.checkNotNull(packet, "packet cannot be NULL.");
|
||||
Preconditions.checkNotNull(attributeKey, "attributeKey cannot be NULL.");
|
||||
|
||||
// Remember to set the base value
|
||||
if (Double.isNaN(baseValue)) {
|
||||
throw new IllegalStateException("Base value has not been set.");
|
||||
}
|
||||
|
||||
// Retrieve the correct constructor
|
||||
|
||||
boolean isStatic = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
|
||||
|
||||
if (ATTRIBUTE_CONSTRUCTOR == null) {
|
||||
ATTRIBUTE_CONSTRUCTOR = FuzzyReflection.fromClass(MinecraftReflection.getAttributeSnapshotClass(), true)
|
||||
.getConstructor(FuzzyMethodContract.newBuilder().parameterCount(4)
|
||||
.parameterDerivedOf(MinecraftReflection.getPacketClass(), 0)
|
||||
.parameterExactType(double.class, 2).parameterDerivedOf(Collection.class, 3)
|
||||
.build()
|
||||
);
|
||||
FuzzyReflection ref = FuzzyReflection.fromClass(MinecraftReflection.getAttributeSnapshotClass(), true);
|
||||
FuzzyMethodContract.Builder contract = FuzzyMethodContract.newBuilder().parameterCount(isStatic ? 3 : 4);
|
||||
if (!isStatic) {
|
||||
contract.parameterDerivedOf(MinecraftReflection.getPacketClass(), 0);
|
||||
}
|
||||
contract.parameterExactType(double.class).parameterDerivedOf(Collection.class);
|
||||
ATTRIBUTE_CONSTRUCTOR = ref.getConstructor(contract.build());
|
||||
|
||||
// Just in case
|
||||
ATTRIBUTE_CONSTRUCTOR.setAccessible(true);
|
||||
}
|
||||
|
||||
Object attributeKey;
|
||||
if (KEY_WRAPPED) {
|
||||
if (REGISTRY == null) {
|
||||
Class<?> iRegistry = MinecraftReflection.getMinecraftClass("IRegistry");
|
||||
try {
|
||||
REGISTRY = iRegistry.getDeclaredField("ATTRIBUTE").get(null);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to obtain ATTRIBUTE registry", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (REGISTRY_GET == null) {
|
||||
Class<?> keyClass = MinecraftReflection.getMinecraftKeyClass();
|
||||
REGISTRY_GET = Accessors.getMethodAccessor(REGISTRY.getClass(), "get", keyClass);
|
||||
}
|
||||
|
||||
WrappedRegistry registry = WrappedRegistry.getAttributeRegistry();
|
||||
String strKey = REMAP.getOrDefault(this.attributeKey, this.attributeKey);
|
||||
Object key = MinecraftKey.getConverter().getGeneric(new MinecraftKey(strKey));
|
||||
attributeKey = REGISTRY_GET.invoke(REGISTRY, key);
|
||||
attributeKey = registry.get(strKey);
|
||||
|
||||
if (attributeKey == null) {
|
||||
throw new IllegalArgumentException("Invalid attribute name: " + this.attributeKey);
|
||||
@@ -459,15 +449,14 @@ public class WrappedAttribute extends AbstractWrapper {
|
||||
}
|
||||
|
||||
try {
|
||||
Object handle = ATTRIBUTE_CONSTRUCTOR.newInstance(
|
||||
packet.getHandle(),
|
||||
attributeKey,
|
||||
baseValue,
|
||||
getUnwrappedModifiers());
|
||||
Object handle;
|
||||
if (isStatic) {
|
||||
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(attributeKey, baseValue, getUnwrappedModifiers());
|
||||
} else {
|
||||
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(packet.getHandle(), attributeKey, baseValue, getUnwrappedModifiers());
|
||||
}
|
||||
|
||||
// Create it
|
||||
return new WrappedAttribute(handle);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot construct AttributeSnapshot.", e);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,9 @@ public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
}
|
||||
|
||||
static {
|
||||
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass("AttributeModifier$Operation") : null;
|
||||
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass(
|
||||
"world.entity.ai.attributes.AttributeModifier$Operation", "AttributeModifier$Operation"
|
||||
) : null;
|
||||
OPERATION_CONVERTER = OPERATION_ENUM ? new IndexedEnumConverter<>(Operation.class, OPERATION_CLASS) : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
}
|
||||
|
||||
try {
|
||||
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getMinecraftClass("ChatDeserializer"), true)
|
||||
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getChatDeserializer(), true)
|
||||
.getMethodByParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// We'll handle it in the ComponentParser
|
||||
@@ -50,7 +50,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
}
|
||||
|
||||
// Get a component from a standard Minecraft message
|
||||
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
|
||||
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class, boolean.class);
|
||||
|
||||
// And the component text constructor
|
||||
CONSTRUCT_TEXT_COMPONENT = Accessors.getConstructorAccessor(MinecraftReflection.getChatComponentTextClass(), String.class);
|
||||
@@ -95,6 +95,9 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
|
||||
/**
|
||||
* Construct a wrapper around a new text chat component with the given text.
|
||||
* <p>
|
||||
* Note: {@link #fromLegacyText(String)} is preferred for text that contains
|
||||
* legacy formatting codes since it will translate them to the JSON equivalent.
|
||||
* @param text - the text of the text chat component.
|
||||
* @return The wrapper around the new chat component.
|
||||
*/
|
||||
@@ -111,7 +114,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
* @return The equivalent chat components.
|
||||
*/
|
||||
public static WrappedChatComponent[] fromChatMessage(String message) {
|
||||
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message);
|
||||
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message, false);
|
||||
WrappedChatComponent[] result = new WrappedChatComponent[components.length];
|
||||
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
@@ -120,6 +123,18 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a single chat component from a standard Minecraft message
|
||||
* (with legacy formatting codes), preserving multiple lines.
|
||||
* @param message - the message.
|
||||
* @return The equivalent chat component.
|
||||
*/
|
||||
public static WrappedChatComponent fromLegacyText(String message) {
|
||||
// With keepNewlines = true (second parameter), only one component is returned
|
||||
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message, true);
|
||||
return fromHandle(components[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a copy of this component as a JSON string.
|
||||
* <p>
|
||||
|
||||
@@ -129,8 +129,10 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
// We can create a fake egg without it affecting anything
|
||||
// Mojang added difficulty to lightning strikes, so this'll have to do
|
||||
if (eggConstructor == null) {
|
||||
eggConstructor = Accessors.getConstructorAccessor(MinecraftReflection.getMinecraftClass("EntityEgg"),
|
||||
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class);
|
||||
eggConstructor = Accessors.getConstructorAccessor(
|
||||
MinecraftReflection.getMinecraftClass("world.entity.projectile.EntityEgg", "EntityEgg"),
|
||||
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class
|
||||
);
|
||||
}
|
||||
|
||||
Object world = BukkitUnwrapper.getInstance().unwrapItem(Bukkit.getWorlds().get(0));
|
||||
@@ -493,7 +495,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
.build();
|
||||
List<Method> methods = fuzzy.getMethodList(contract);
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equals("set") || method.getName().equals("watch")) {
|
||||
if (method.getName().equals("set") || method.getName().equals("watch") || method.getName().equals("b")) {
|
||||
SETTER = Accessors.getMethodAccessor(method);
|
||||
} else {
|
||||
REGISTER = Accessors.getMethodAccessor(method);
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
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.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* Represents an entity used action used in the UseEntity packet sent by the client.
|
||||
* @author derklaro
|
||||
*/
|
||||
public class WrappedEnumEntityUseAction extends AbstractWrapper implements ClonableWrapper {
|
||||
|
||||
public static final EquivalentConverter<WrappedEnumEntityUseAction> CONVERTER = Converters.handle(AbstractWrapper::getHandle,
|
||||
WrappedEnumEntityUseAction::fromHandle, WrappedEnumEntityUseAction.class);
|
||||
|
||||
private static final Class<?> PACKET_CLASS = PacketType.Play.Client.USE_ENTITY.getPacketClass();
|
||||
private static final Class<?>[] DECLARED_CLASSES = PACKET_CLASS.getDeclaredClasses();
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getEnumEntityUseActionClass();
|
||||
private static final MethodAccessor ACTION_USE = MinecraftReflection.getEntityUseActionEnumMethodAccessor();
|
||||
|
||||
private static final ConstructorAccessor INTERACT = useAction(EnumWrappers.getHandClass());
|
||||
private static final ConstructorAccessor INTERACT_AT = useAction(EnumWrappers.getHandClass(),
|
||||
MinecraftReflection.getVec3DClass());
|
||||
|
||||
private static final Object ATTACK = Accessors.getFieldAccessor(FuzzyReflection.fromClass(PACKET_CLASS, true)
|
||||
.getField(FuzzyFieldContract.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.typeExact(MinecraftReflection.getEnumEntityUseActionClass())
|
||||
.build())
|
||||
).get(null);
|
||||
private static final WrappedEnumEntityUseAction ATTACK_WRAPPER = new WrappedEnumEntityUseAction(ATTACK);
|
||||
|
||||
private final EntityUseAction action;
|
||||
// these fields are only available for interact & interact_at
|
||||
private FieldAccessor handAccessor;
|
||||
private FieldAccessor positionAccessor;
|
||||
|
||||
/**
|
||||
* Construct a new wrapper for the entity use action class in the UseEntity packet.
|
||||
* @param handle - the NMS handle.
|
||||
*/
|
||||
private WrappedEnumEntityUseAction(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
setHandle(handle);
|
||||
|
||||
action = EnumWrappers.getEntityUseActionConverter().getSpecific(ACTION_USE.invoke(handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a constructor of a declared class in the UseEntity class. Used to find the action class implementations.
|
||||
* @param parameterTypes - the types the constructor of the class must have.
|
||||
* @return a constructor for a matching class.
|
||||
* @throws IllegalArgumentException if no constructor was found.
|
||||
*/
|
||||
private static ConstructorAccessor useAction(Class<?>... parameterTypes) {
|
||||
for (Class<?> subClass : DECLARED_CLASSES) {
|
||||
ConstructorAccessor accessor = Accessors.getConstructorAccessorOrNull(subClass, parameterTypes);
|
||||
if (accessor != null) {
|
||||
return accessor;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"No constructor with " + Arrays.toString(parameterTypes) + " in " + PACKET_CLASS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new wrapper for the entity use action class in the UseEntity packet.
|
||||
* @param handle - the NMS handle.
|
||||
* @return the created wrapper.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction fromHandle(Object handle) {
|
||||
return new WrappedEnumEntityUseAction(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the jvm static action for attacking an entity.
|
||||
* @return the action for an entity attack.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction attack() {
|
||||
return ATTACK_WRAPPER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an action for interacting with an entity.
|
||||
* @param hand - the hand used for the interact.
|
||||
* @return the action for an interact.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction interact(Hand hand) {
|
||||
Object handle = INTERACT.invoke(EnumWrappers.getHandConverter().getGeneric(hand));
|
||||
return new WrappedEnumEntityUseAction(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an action for interacting with an entity at a specific location.
|
||||
* @param hand - the hand used for the interact.
|
||||
* @param vector - the position of the interact.
|
||||
* @return the action for an interact_at.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction interactAt(Hand hand, Vector vector) {
|
||||
Object handle = INTERACT_AT.invoke(EnumWrappers.getHandConverter().getGeneric(hand),
|
||||
BukkitConverters.getVectorConverter().getGeneric(vector));
|
||||
return new WrappedEnumEntityUseAction(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action used for the interact.
|
||||
* @return the interact action.
|
||||
*/
|
||||
public EntityUseAction getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hand used for the interact. Only available if this represents interact or interact_at.
|
||||
* @return the hand used for the interact.
|
||||
* @throws IllegalArgumentException if called for attack.
|
||||
*/
|
||||
public Hand getHand() {
|
||||
return EnumWrappers.getHandConverter().getSpecific(getHandAccessor().get(handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hand used for the interact.
|
||||
* @param hand the used hand.
|
||||
* @throws IllegalArgumentException if called for attack.
|
||||
*/
|
||||
public void setHand(Hand hand) {
|
||||
getHandAccessor().set(handle, EnumWrappers.getHandConverter().getGeneric(hand));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position of the interact. Only available if this represents interact_at.
|
||||
* @return the position of the interact.
|
||||
* @throws IllegalArgumentException if called for attack or interact.
|
||||
*/
|
||||
public Vector getPosition() {
|
||||
return BukkitConverters.getVectorConverter().getSpecific(getPositionAccessor().get(handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the interact.
|
||||
* @param position the position.
|
||||
* @throws IllegalArgumentException if called for attack or interact.
|
||||
*/
|
||||
public void setPosition(Vector position) {
|
||||
getPositionAccessor().set(handle, BukkitConverters.getVectorConverter().getGeneric(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedEnumEntityUseAction deepClone() {
|
||||
switch (action) {
|
||||
case ATTACK:
|
||||
return WrappedEnumEntityUseAction.attack();
|
||||
case INTERACT:
|
||||
return WrappedEnumEntityUseAction.interact(getHand());
|
||||
case INTERACT_AT:
|
||||
return WrappedEnumEntityUseAction.interactAt(getHand(), getPosition());
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid EntityUseAction: " + action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field accessor for the hand in the interact and interact_at type.
|
||||
* @return a field accessor for the hand field.
|
||||
* @throws IllegalArgumentException if called for attack.
|
||||
*/
|
||||
private FieldAccessor getHandAccessor() {
|
||||
if (handAccessor == null) {
|
||||
handAccessor = MinecraftReflection.getHandEntityUseActionEnumFieldAccessor(handle);
|
||||
}
|
||||
return handAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field accessor for the position in the interact_at type.
|
||||
* @return a field accessor for the position field.
|
||||
* @throws IllegalArgumentException if called for attack or interact.
|
||||
*/
|
||||
public FieldAccessor getPositionAccessor() {
|
||||
if (positionAccessor == null) {
|
||||
positionAccessor = MinecraftReflection.getVec3EntityUseActionEnumFieldAccessor(handle);
|
||||
}
|
||||
return positionAccessor;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.mojang.math.Vector3fa;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -31,14 +33,14 @@ public class WrappedParticle<T> {
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(Particle.class)
|
||||
.parameterExactType(MinecraftReflection.getMinecraftClass("ParticleParam"))
|
||||
.parameterExactType(MinecraftReflection.getParticleParam())
|
||||
.build();
|
||||
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MinecraftReflection.getMinecraftClass("ParticleParam"))
|
||||
.returnTypeExact(MinecraftReflection.getParticleParam())
|
||||
.parameterCount(2)
|
||||
.build();
|
||||
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
@@ -130,12 +132,26 @@ public class WrappedParticle<T> {
|
||||
}
|
||||
|
||||
private static Object getRedstone(Object handle) {
|
||||
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
|
||||
return new Particle.DustOptions(Color.fromRGB(
|
||||
(int) (modifier.read(0) * 255),
|
||||
(int) (modifier.read(1) * 255),
|
||||
(int) (modifier.read(2) * 255)),
|
||||
modifier.read(3));
|
||||
int r, g, b;
|
||||
float alpha;
|
||||
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
|
||||
Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0);
|
||||
|
||||
r = (int) (rgb.a() * 255);
|
||||
g = (int) (rgb.b() * 255);
|
||||
b = (int) (rgb.c() * 255);
|
||||
alpha = (float) modifier.withType(float.class).read(0);
|
||||
} else {
|
||||
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
|
||||
r = (int) (modifier.read(0) * 255);
|
||||
g = (int) (modifier.read(1) * 255);
|
||||
b = (int) (modifier.read(2) * 255);
|
||||
alpha = modifier.read(3);
|
||||
}
|
||||
|
||||
return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha);
|
||||
}
|
||||
|
||||
public static <T> WrappedParticle<T> create(Particle particle, T data) {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
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 com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class WrappedRegistry {
|
||||
// map of NMS class to registry instance
|
||||
private static final Map<Class<?>, WrappedRegistry> REGISTRY;
|
||||
|
||||
private static final MethodAccessor GET;
|
||||
private static final MethodAccessor GET_KEY;
|
||||
|
||||
static {
|
||||
Map<Class<?>, WrappedRegistry> regMap = new HashMap<>();
|
||||
|
||||
Class<?> regClass = MinecraftReflection.getIRegistry();
|
||||
if (regClass != null) {
|
||||
for (Field field : regClass.getFields()) {
|
||||
try {
|
||||
// make sure it's actually a registry
|
||||
if (field.getType().isAssignableFrom(regClass)) {
|
||||
Type genType = field.getGenericType();
|
||||
if (genType instanceof ParameterizedType) {
|
||||
ParameterizedType par = (ParameterizedType) genType;
|
||||
Type paramType = par.getActualTypeArguments()[0];
|
||||
if (paramType instanceof Class) {
|
||||
regMap.put((Class<?>) paramType, new WrappedRegistry(field.get(null)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTRY = ImmutableMap.copyOf(regMap);
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(regClass, false);
|
||||
GET = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnDerivedOf(Object.class)
|
||||
.requireModifier(Modifier.ABSTRACT)
|
||||
.parameterExactType(MinecraftReflection.getMinecraftKeyClass())
|
||||
.build()));
|
||||
GET_KEY = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeExact(MinecraftReflection.getMinecraftKeyClass())
|
||||
.build()));
|
||||
}
|
||||
|
||||
private final Object handle;
|
||||
|
||||
private WrappedRegistry(Object handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public Object get(MinecraftKey key) {
|
||||
return GET.invoke(handle, MinecraftKey.getConverter().getGeneric(key));
|
||||
}
|
||||
|
||||
public Object get(String key) {
|
||||
return get(new MinecraftKey(key));
|
||||
}
|
||||
|
||||
public MinecraftKey getKey(Object generic) {
|
||||
return MinecraftKey.getConverter().getSpecific(GET_KEY.invoke(handle, generic));
|
||||
}
|
||||
|
||||
// TODO add more methods
|
||||
|
||||
public static WrappedRegistry getAttributeRegistry() {
|
||||
return REGISTRY.get(MinecraftReflection.getAttributeBase());
|
||||
}
|
||||
|
||||
public static WrappedRegistry getDimensionRegistry() {
|
||||
return REGISTRY.get(MinecraftReflection.getDimensionManager());
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe
|
||||
* @param message - the message.
|
||||
*/
|
||||
public void setMotD(String message) {
|
||||
setMotD(WrappedChatComponent.fromText(message));
|
||||
setMotD(WrappedChatComponent.fromLegacyText(message));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,12 @@ import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
public class WrappedVillagerData extends AbstractWrapper implements ClonableWrapper {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("VillagerData");
|
||||
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS("VillagerType");
|
||||
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS("VillagerProfession");
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerData","VillagerData");
|
||||
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerType", "VillagerType");
|
||||
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerProfession", "VillagerProfession");
|
||||
|
||||
private static EquivalentConverter<Type> TYPE_CONVERTER;
|
||||
private static EquivalentConverter<Profession> PROF_CONVERTER;
|
||||
|
||||
@@ -592,7 +592,7 @@ public class NbtFactory {
|
||||
Constructor<?> constructor = CONSTRUCTORS.get(type);
|
||||
if (constructor == null) {
|
||||
if (getTagType == null) {
|
||||
Class<?> tagTypes = MinecraftReflection.getMinecraftClass("NBTTagTypes");
|
||||
Class<?> tagTypes = MinecraftReflection.getNbtTagTypes();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(tagTypes, false);
|
||||
getTagType = fuzzy.getMethod(
|
||||
FuzzyMethodContract.newBuilder().parameterCount(1).parameterExactType(int.class).build());
|
||||
|
||||
@@ -35,7 +35,8 @@ import org.bukkit.block.BlockState;
|
||||
* @author Kristian
|
||||
*/
|
||||
class TileEntityAccessor<T extends BlockState> {
|
||||
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove();
|
||||
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove()
|
||||
&& !MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
|
||||
|
||||
/**
|
||||
* Token indicating that the given block state doesn't contain any tile entities.
|
||||
|
||||
@@ -3,6 +3,10 @@ package com.comphenix.integration.protocol;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
@@ -10,7 +14,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.simple.SimpleLogger;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -18,41 +21,25 @@ import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoadOrder;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
// TODO Migrate this to Gradle if necessary
|
||||
// Damn final classes ...
|
||||
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
|
||||
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
|
||||
@PrepareForTest(PluginDescriptionFile.class)
|
||||
public class SimpleCraftBukkitITCase {
|
||||
// The fake plugin
|
||||
private static volatile Plugin FAKE_PLUGIN = null;
|
||||
|
||||
|
||||
/**
|
||||
* The maximum amount of time to wait before a server has started.
|
||||
* <p>
|
||||
* We have to give it the ample time of 60 seconds, as a server may have to
|
||||
* generate the spawn area in three worlds.
|
||||
* We have to give it the ample time of 60 seconds, as a server may have to generate the spawn area in three worlds.
|
||||
*/
|
||||
private static final int TIMEOUT_MS = 60000;
|
||||
|
||||
// The fake plugin
|
||||
private static volatile Plugin FAKE_PLUGIN = null;
|
||||
|
||||
/**
|
||||
* Setup the CraftBukkit server for all the tests.
|
||||
* @throws IOException Unable to setup server.
|
||||
*
|
||||
* @throws IOException Unable to setup server.
|
||||
* @throws InterruptedException Thread interrupted.
|
||||
*/
|
||||
//@BeforeClass
|
||||
//@BeforeAll
|
||||
public static void setupCraftBukkit() throws Exception {
|
||||
setupPlugins();
|
||||
|
||||
@@ -63,17 +50,18 @@ public class SimpleCraftBukkitITCase {
|
||||
System.out.println("Loader of SimpleLogger: " + SimpleLogger.class.getClassLoader());
|
||||
System.out.println("Loader of Logger: " + Logger.class.getClassLoader());
|
||||
}
|
||||
|
||||
|
||||
// We need to wait until the server object is ready
|
||||
while (Bukkit.getServer() == null)
|
||||
while (Bukkit.getServer() == null) {
|
||||
Thread.sleep(1);
|
||||
|
||||
}
|
||||
|
||||
// Make it clear this plugin doesn't exist
|
||||
FAKE_PLUGIN = createPlugin("FakeTestPluginIntegration");
|
||||
|
||||
|
||||
// No need to look for updates
|
||||
FieldUtils.writeStaticField(ProtocolLibrary.class, "UPDATES_DISABLED", Boolean.TRUE, true);
|
||||
|
||||
|
||||
// Wait until the server and all the plugins have loaded
|
||||
Bukkit.getScheduler().callSyncMethod(FAKE_PLUGIN, new Callable<Object>() {
|
||||
@Override
|
||||
@@ -82,26 +70,22 @@ public class SimpleCraftBukkitITCase {
|
||||
return null;
|
||||
}
|
||||
}).get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
|
||||
|
||||
// Plugins are now ready
|
||||
ProtocolLibrary.getConfig().setDebug(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the CraftBukkit server when they're done.
|
||||
*/
|
||||
//@AfterClass
|
||||
//@AfterAll
|
||||
public static void shutdownCraftBukkit() {
|
||||
Bukkit.shutdown();
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testPingPacket() throws Throwable {
|
||||
TestPingPacket.newTest().startTest(FAKE_PLUGIN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy ProtocolLib into the plugins folder.
|
||||
*
|
||||
* @throws IOException If anything went wrong.
|
||||
*/
|
||||
private static void setupPlugins() throws IOException {
|
||||
@@ -109,27 +93,27 @@ public class SimpleCraftBukkitITCase {
|
||||
File srcDirectory = new File("../");
|
||||
File bestFile = null;
|
||||
int bestLength = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
for (File file : srcDirectory.listFiles()) {
|
||||
String name = file.getName();
|
||||
|
||||
|
||||
if (file.isFile() && name.startsWith("ProtocolLib") && name.length() < bestLength) {
|
||||
bestLength = name.length();
|
||||
bestFile = file;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bestFile == null) {
|
||||
throw new IllegalStateException("Cannot find ProtocolLib in " + srcDirectory);
|
||||
}
|
||||
|
||||
|
||||
// Copy the ProtocolLib plugin to the server
|
||||
if (pluginDirectory.exists()) {
|
||||
deleteFolder(pluginDirectory);
|
||||
}
|
||||
|
||||
|
||||
pluginDirectory.mkdirs();
|
||||
|
||||
|
||||
File destination = new File(pluginDirectory, bestFile.getName()).getAbsoluteFile();
|
||||
Files.copy(bestFile, destination);
|
||||
}
|
||||
@@ -148,46 +132,53 @@ public class SimpleCraftBukkitITCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a specific fake plugin.
|
||||
*
|
||||
* @param plugin - the plugin to load.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void initializePlugin(Plugin plugin) {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
|
||||
|
||||
try {
|
||||
List<Plugin> plugins = (List<Plugin>) FieldUtils.readField(manager, "plugins", true);
|
||||
Map<String, Plugin> lookupNames = (Map<String, Plugin>) FieldUtils.readField(manager, "lookupNames", true);
|
||||
|
||||
/// Associate this plugin
|
||||
plugins.add(plugin);
|
||||
lookupNames.put(plugin.getName(), plugin);
|
||||
|
||||
Map<String, Plugin> lookupNames = (Map<String, Plugin>) FieldUtils.readField(manager, "lookupNames", true);
|
||||
|
||||
/// Associate this plugin
|
||||
plugins.add(plugin);
|
||||
lookupNames.put(plugin.getName(), plugin);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to access the fields of " + manager, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a mockable plugin for all the tests.
|
||||
*
|
||||
* @param fakePluginName - the fake plugin name.
|
||||
* @return The plugin.
|
||||
*/
|
||||
private static Plugin createPlugin(String fakePluginName) {
|
||||
Plugin plugin = mock(Plugin.class);
|
||||
PluginDescriptionFile description = mock(PluginDescriptionFile.class);
|
||||
|
||||
|
||||
when(description.getDepend()).thenReturn(Lists.newArrayList("ProtocolLib"));
|
||||
when(description.getSoftDepend()).thenReturn(Collections.<String>emptyList());
|
||||
when(description.getLoadBefore()).thenReturn(Collections.<String>emptyList());
|
||||
when(description.getSoftDepend()).thenReturn(Collections.emptyList());
|
||||
when(description.getLoadBefore()).thenReturn(Collections.emptyList());
|
||||
when(description.getLoad()).thenReturn(PluginLoadOrder.POSTWORLD);
|
||||
|
||||
|
||||
when(plugin.getName()).thenReturn(fakePluginName);
|
||||
when(plugin.getServer()).thenReturn(Bukkit.getServer());
|
||||
when(plugin.isEnabled()).thenReturn(true);
|
||||
when(plugin.getDescription()).thenReturn(description);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testPingPacket() throws Throwable {
|
||||
TestPingPacket.newTest().startTest(FAKE_PLUGIN);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
package com.comphenix.integration.protocol;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.utility.StreamSerializer;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
@@ -10,84 +15,110 @@ import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.utility.StreamSerializer;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
public class SimpleMinecraftClient {
|
||||
private static final int CONNECT_TIMEOUT = 2500;
|
||||
private static final int READ_TIMEOUT = 15000;
|
||||
|
||||
// Current Minecraft version
|
||||
private final int protocolVersion;
|
||||
private static final int CONNECT_TIMEOUT = 2500;
|
||||
private static final int READ_TIMEOUT = 15000;
|
||||
// Typical Minecraft serializer
|
||||
private static final StreamSerializer serializer = StreamSerializer.getDefault();
|
||||
// Current Minecraft version
|
||||
private final int protocolVersion;
|
||||
|
||||
// Typical Minecraft serializer
|
||||
private static StreamSerializer serializer = StreamSerializer.getDefault();
|
||||
|
||||
public SimpleMinecraftClient(int protocolVersion) {
|
||||
public SimpleMinecraftClient(int protocolVersion) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the local server for ping information.
|
||||
* @return The server information.
|
||||
* @throws IOException
|
||||
*/
|
||||
public String queryLocalPing() throws IOException {
|
||||
return queryServerPing(new InetSocketAddress("localhost", 25565));
|
||||
|
||||
/**
|
||||
* Write a byte array to the output stream, prefixed by a length.
|
||||
*
|
||||
* @param output - the stream.
|
||||
* @param data - the data to write.
|
||||
*/
|
||||
private static void writeByteArray(DataOutputStream output, byte[] data) throws IOException {
|
||||
StreamSerializer.getDefault().serializeVarInt(output, data.length);
|
||||
|
||||
if (data.length > 0) {
|
||||
output.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a byte array from an input stream, prefixed by length.
|
||||
*
|
||||
* @param input - the input stream.
|
||||
* @return The read byte array.
|
||||
*/
|
||||
private static byte[] readByteArray(DataInputStream input) throws IOException {
|
||||
int length = serializer.deserializeVarInt(input);
|
||||
byte[] data = new byte[length];
|
||||
|
||||
ByteStreams.readFully(input, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the local server for ping information.
|
||||
*
|
||||
* @return The server information.
|
||||
* @throws IOException
|
||||
*/
|
||||
public String queryLocalPing() throws IOException {
|
||||
return this.queryServerPing(new InetSocketAddress("localhost", 25565));
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the given server for its list ping information.
|
||||
*
|
||||
* @param address - the server hostname and port.
|
||||
* @return The server information.
|
||||
* @throws IOException
|
||||
*/
|
||||
public String queryServerPing(InetSocketAddress address) throws IOException {
|
||||
Socket socket = null;
|
||||
OutputStream output = null;
|
||||
InputStream input = null;
|
||||
|
||||
try {
|
||||
socket = new Socket();
|
||||
socket.connect(address, CONNECT_TIMEOUT);
|
||||
Socket socket = null;
|
||||
OutputStream output = null;
|
||||
InputStream input = null;
|
||||
|
||||
// Shouldn't take that long
|
||||
socket.setSoTimeout(READ_TIMEOUT);
|
||||
|
||||
// Retrieve sockets
|
||||
output = socket.getOutputStream();
|
||||
input = socket.getInputStream();
|
||||
try {
|
||||
socket = new Socket();
|
||||
socket.connect(address, CONNECT_TIMEOUT);
|
||||
|
||||
// The output writer
|
||||
DataOutputStream data = new DataOutputStream(output);
|
||||
// Shouldn't take that long
|
||||
socket.setSoTimeout(READ_TIMEOUT);
|
||||
|
||||
// Request a server information packet
|
||||
writePacket(data, new HandshakePacket(protocolVersion, address.getHostName(), address.getPort(), 1));
|
||||
writePacket(data, new RequestPacket());
|
||||
data.flush();
|
||||
|
||||
// Read a single packet, and close the connection
|
||||
SimplePacket packet = readPacket(new DataInputStream(input), Protocol.STATUS);
|
||||
|
||||
socket.close();
|
||||
return ((ResponsePacket) packet).getPingJson();
|
||||
} finally {
|
||||
if (input != null)
|
||||
input.close();
|
||||
if (output != null)
|
||||
output.close();
|
||||
if (socket != null)
|
||||
socket.close();
|
||||
}
|
||||
// Retrieve sockets
|
||||
output = socket.getOutputStream();
|
||||
input = socket.getInputStream();
|
||||
|
||||
// The output writer
|
||||
DataOutputStream data = new DataOutputStream(output);
|
||||
|
||||
// Request a server information packet
|
||||
this.writePacket(data, new HandshakePacket(this.protocolVersion, address.getHostName(), address.getPort(), 1));
|
||||
this.writePacket(data, new RequestPacket());
|
||||
data.flush();
|
||||
|
||||
// Read a single packet, and close the connection
|
||||
SimplePacket packet = this.readPacket(new DataInputStream(input), Protocol.STATUS);
|
||||
|
||||
socket.close();
|
||||
return ((ResponsePacket) packet).getPingJson();
|
||||
} finally {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
}
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void writePacket(DataOutputStream output, SimplePacket packet) throws IOException {
|
||||
ByteArrayOutputStream packetBuffer = new ByteArrayOutputStream();
|
||||
DataOutputStream packetOutput = new DataOutputStream(packetBuffer);
|
||||
|
||||
|
||||
// Prefix the packet with a length field
|
||||
packet.write(packetOutput);
|
||||
writeByteArray(output, packetBuffer.toByteArray());
|
||||
@@ -96,14 +127,15 @@ public class SimpleMinecraftClient {
|
||||
private SimplePacket readPacket(DataInputStream input, Protocol protocol) throws IOException {
|
||||
while (true) {
|
||||
byte[] buffer = readByteArray(input);
|
||||
|
||||
|
||||
// Skip empty packets
|
||||
if (buffer.length == 0)
|
||||
if (buffer.length == 0) {
|
||||
continue;
|
||||
|
||||
DataInputStream data = getDataInput(buffer);
|
||||
}
|
||||
|
||||
DataInputStream data = this.getDataInput(buffer);
|
||||
PacketType type = PacketType.findCurrent(protocol, Sender.SERVER, serializer.deserializeVarInt(data));
|
||||
|
||||
|
||||
if (type == PacketType.Status.Server.SERVER_INFO) {
|
||||
ResponsePacket response = new ResponsePacket();
|
||||
response.read(type, data);
|
||||
@@ -116,69 +148,47 @@ public class SimpleMinecraftClient {
|
||||
|
||||
/**
|
||||
* Wrap an input stream around a byte array.
|
||||
*
|
||||
* @param bytes - the array.
|
||||
* @return The wrapped input stream.
|
||||
*/
|
||||
private DataInputStream getDataInput(byte[] bytes) {
|
||||
return new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a byte array to the output stream, prefixed by a length.
|
||||
* @param output - the stream.
|
||||
* @param data - the data to write.
|
||||
*/
|
||||
private static void writeByteArray(DataOutputStream output, byte[] data) throws IOException {
|
||||
StreamSerializer.getDefault().serializeVarInt(output, data.length);
|
||||
|
||||
if (data.length > 0) {
|
||||
output.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte array from an input stream, prefixed by length.
|
||||
* @param input - the input stream.
|
||||
* @return The read byte array.
|
||||
*/
|
||||
private static byte[] readByteArray(DataInputStream input) throws IOException {
|
||||
int length = serializer.deserializeVarInt(input);
|
||||
byte[] data = new byte[length];
|
||||
|
||||
ByteStreams.readFully(input, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static class RequestPacket extends SimplePacket {
|
||||
|
||||
public RequestPacket() {
|
||||
super(PacketType.Status.Client.START);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class ResponsePacket extends SimplePacket {
|
||||
|
||||
private String ping;
|
||||
|
||||
|
||||
public ResponsePacket() {
|
||||
super(PacketType.Status.Server.SERVER_INFO);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void read(PacketType type, DataInputStream input) throws IOException {
|
||||
super.read(type, input);
|
||||
ping = serializer.deserializeString(input, 32000);
|
||||
this.ping = this.serializer.deserializeString(input, 32000);
|
||||
}
|
||||
|
||||
|
||||
public String getPingJson() {
|
||||
return ping;
|
||||
return this.ping;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class HandshakePacket extends SimplePacket {
|
||||
private int protocol;
|
||||
private String host;
|
||||
private int port;
|
||||
private int nextState;
|
||||
|
||||
|
||||
private final int protocol;
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final int nextState;
|
||||
|
||||
public HandshakePacket(int protocol, String host, int port, int nextState) {
|
||||
super(PacketType.Handshake.Client.SET_PROTOCOL);
|
||||
this.protocol = protocol;
|
||||
@@ -190,25 +200,26 @@ public class SimpleMinecraftClient {
|
||||
@Override
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
super.write(output);
|
||||
serializer.serializeVarInt(output, protocol);
|
||||
serializer.serializeString(output, host);
|
||||
output.writeShort(port);
|
||||
serializer.serializeVarInt(output, nextState);
|
||||
this.serializer.serializeVarInt(output, this.protocol);
|
||||
this.serializer.serializeString(output, this.host);
|
||||
output.writeShort(this.port);
|
||||
this.serializer.serializeVarInt(output, this.nextState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SimplePacket {
|
||||
|
||||
protected final PacketType type;
|
||||
protected final StreamSerializer serializer = StreamSerializer.getDefault();
|
||||
|
||||
|
||||
public SimplePacket(PacketType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
serializer.serializeVarInt(output, type.getCurrentId());
|
||||
this.serializer.serializeVarInt(output, this.type.getCurrentId());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void read(PacketType type, DataInputStream input) throws IOException {
|
||||
// Note - we don't read the packet id
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
package com.comphenix.integration.protocol;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class TestPingPacket {
|
||||
|
||||
// Current versions
|
||||
private static final int PROTOCOL_VERSION = 4;
|
||||
|
||||
@@ -30,6 +29,7 @@ public class TestPingPacket {
|
||||
|
||||
/**
|
||||
* Create a new test ping packet test.
|
||||
*
|
||||
* @return The new test.
|
||||
*/
|
||||
public static TestPingPacket newTest() {
|
||||
@@ -38,17 +38,18 @@ public class TestPingPacket {
|
||||
|
||||
/**
|
||||
* Invoked when the test should be started.
|
||||
*
|
||||
* @param plugin - the current plugin.
|
||||
* @throws Throwable Anything went wrong.
|
||||
*/
|
||||
public void startTest(Plugin plugin) throws Throwable {
|
||||
try {
|
||||
String transmitted = testInterception(plugin).
|
||||
get(TIMEOUT_PING_MS, TimeUnit.MILLISECONDS);
|
||||
String transmitted = this.testInterception(plugin).
|
||||
get(TIMEOUT_PING_MS, TimeUnit.MILLISECONDS);
|
||||
|
||||
// Make sure it's the same
|
||||
System.out.println("Server string: " + transmitted);
|
||||
assertEquals(source, transmitted);
|
||||
assertEquals(this.source, transmitted);
|
||||
} catch (ExecutionException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
@@ -56,12 +57,12 @@ public class TestPingPacket {
|
||||
|
||||
private Future<String> testInterception(Plugin test) {
|
||||
ProtocolLibrary.getProtocolManager().addPacketListener(
|
||||
new PacketAdapter(test, PacketType.Status.Server.SERVER_INFO) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
source = event.getPacket().getServerPings().read(0).toJson();
|
||||
}
|
||||
});
|
||||
new PacketAdapter(test, PacketType.Status.Server.SERVER_INFO) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
TestPingPacket.this.source = event.getPacket().getServerPings().read(0).toJson();
|
||||
}
|
||||
});
|
||||
|
||||
// Invoke the client on a separate thread
|
||||
return Executors.newSingleThreadExecutor().submit(new Callable<String>() {
|
||||
@@ -71,8 +72,9 @@ public class TestPingPacket {
|
||||
String information = client.queryLocalPing();
|
||||
|
||||
// Wait for the listener to catch up
|
||||
for (int i = 0; i < 1000 && (source == null); i++)
|
||||
for (int i = 0; i < 1000 && (TestPingPacket.this.source == null); i++) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
|
||||
return information;
|
||||
}
|
||||
|
||||
@@ -1,47 +1,45 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.utility.Constants;
|
||||
|
||||
import net.minecraft.server.v1_16_R3.DispenserRegistry;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.server.DispenserRegistry;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.util.Versioning;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.util.Versioning;
|
||||
import org.spigotmc.SpigotWorldConfig;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Used to ensure that ProtocolLib and Bukkit is prepared to be tested.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class BukkitInitialization {
|
||||
|
||||
private static final BukkitInitialization instance = new BukkitInitialization();
|
||||
private boolean initialized;
|
||||
private boolean packaged;
|
||||
|
||||
private BukkitInitialization() {
|
||||
System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName());
|
||||
}
|
||||
|
||||
private boolean initialized;
|
||||
private boolean packaged;
|
||||
|
||||
public static synchronized void initializePackage() {
|
||||
instance.setPackage();
|
||||
}
|
||||
|
||||
public static synchronized void initializeItemMeta() {
|
||||
/**
|
||||
* Statically initializes the mock server for unit testing
|
||||
*/
|
||||
public static synchronized void initializeAll() {
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
@@ -49,11 +47,9 @@ public class BukkitInitialization {
|
||||
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing
|
||||
*/
|
||||
private void initialize() {
|
||||
if (!initialized) {
|
||||
if (!this.initialized) {
|
||||
// Denote that we're done
|
||||
initialized = true;
|
||||
|
||||
initializePackage();
|
||||
this.initialized = true;
|
||||
|
||||
try {
|
||||
LogManager.getLogger();
|
||||
@@ -62,14 +58,26 @@ public class BukkitInitialization {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
DispenserRegistry.init();
|
||||
instance.setPackage();
|
||||
|
||||
SharedConstants.a();
|
||||
DispenserRegistry.a();
|
||||
|
||||
try {
|
||||
IRegistry.class.getName();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
String releaseTarget = SharedConstants.b().getReleaseTarget();
|
||||
String serverVersion = CraftServer.class.getPackage().getImplementationVersion();
|
||||
|
||||
// Mock the server object
|
||||
Server mockedServer = mock(Server.class);
|
||||
|
||||
when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
|
||||
when(mockedServer.getName()).thenReturn("Mock Server");
|
||||
when(mockedServer.getVersion()).thenReturn(CraftServer.class.getPackage().getImplementationVersion());
|
||||
when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")");
|
||||
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion());
|
||||
|
||||
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
|
||||
@@ -100,8 +108,8 @@ public class BukkitInitialization {
|
||||
* Ensure that package names are correctly set up.
|
||||
*/
|
||||
private void setPackage() {
|
||||
if (!packaged) {
|
||||
packaged = true;
|
||||
if (!this.packaged) {
|
||||
this.packaged = true;
|
||||
|
||||
try {
|
||||
LogManager.getLogger();
|
||||
|
||||
@@ -2,39 +2,38 @@
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MinecraftVersionTest {
|
||||
|
||||
@Test
|
||||
public void testComparision() {
|
||||
MinecraftVersion within = new MinecraftVersion(1, 2, 5);
|
||||
MinecraftVersion outside = new MinecraftVersion(1, 7, 0);
|
||||
|
||||
|
||||
MinecraftVersion lower = new MinecraftVersion(1, 0, 0);
|
||||
MinecraftVersion highest = new MinecraftVersion(1, 4, 5);
|
||||
|
||||
|
||||
MinecraftVersion atLeast = new MinecraftVersion(1, 8, 8);
|
||||
|
||||
// Make sure this is valid
|
||||
@@ -54,8 +53,9 @@ public class MinecraftVersionTest {
|
||||
assertEquals(MinecraftVersion.extractVersion("CraftBukkit R3.0 (MC: 1.4.3)"), "1.4.3");
|
||||
assertEquals(MinecraftVersion.extractVersion("CraftBukkit Test Beta 1 (MC: 1.10.01 )"), "1.10.01");
|
||||
assertEquals(MinecraftVersion.extractVersion("Hello (MC: 2.3.4)"), "2.3.4");
|
||||
|
||||
assertEquals(MinecraftVersion.fromServerVersion("git-Cauldron-Reloaded-1.7.10-1.1388.1.0 (MC: 1.7.10)"), new MinecraftVersion(1, 7, 10));
|
||||
|
||||
assertEquals(MinecraftVersion.fromServerVersion("git-Cauldron-Reloaded-1.7.10-1.1388.1.0 (MC: 1.7.10)"),
|
||||
new MinecraftVersion(1, 7, 10));
|
||||
assertEquals(MinecraftVersion.fromServerVersion("git-Bukkit-18fbb24 (MC: 1.8.8)"), new MinecraftVersion(1, 8, 8));
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,63 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2016 dmulloy2
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 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.
|
||||
* 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.
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import 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.Constants;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import net.minecraft.server.v1_16_R3.EnumProtocol;
|
||||
import net.minecraft.server.v1_16_R3.EnumProtocolDirection;
|
||||
import net.minecraft.server.v1_16_R3.PacketLoginInStart;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import net.minecraft.network.EnumProtocol;
|
||||
import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||
import net.minecraft.network.protocol.login.PacketLoginInStart;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketTypeTest {
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
|
||||
// I'm well aware this is jank, but it does in fact work correctly and give the desired result
|
||||
PacketType.onDynamicCreate = className -> {
|
||||
throw new RuntimeException("Dynamically generated packet " + className);
|
||||
};
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@AfterAll
|
||||
public static void afterClass() {
|
||||
PacketType.onDynamicCreate = __ -> {};
|
||||
PacketType.onDynamicCreate = __ -> {
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -67,7 +71,7 @@ public class PacketTypeTest {
|
||||
for (EnumProtocol protocol : protocols) {
|
||||
System.out.println(WordUtils.capitalize(protocol.name().toLowerCase()));
|
||||
|
||||
Field field = EnumProtocol.class.getDeclaredField("h");
|
||||
Field field = EnumProtocol.class.getDeclaredField("j");
|
||||
field.setAccessible(true);
|
||||
|
||||
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
|
||||
@@ -144,17 +148,30 @@ public class PacketTypeTest {
|
||||
String fullName = clazz.getName();
|
||||
fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
|
||||
|
||||
List<String> classNames = new ArrayList<>(2);
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 3; i < split.size(); i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
String className;
|
||||
List<String> classNames = new ArrayList<>();
|
||||
|
||||
if (fullName.endsWith("Packet")) {
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 1; i < split.size() - 1; i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
} else {
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 3; i < split.size(); i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
|
||||
String className = classNames.get(classNames.size() - 1);
|
||||
className = classNames.get(classNames.size() - 1);
|
||||
|
||||
// Format it like SET_PROTOCOL
|
||||
StringBuilder fieldName = new StringBuilder();
|
||||
@@ -208,11 +225,13 @@ public class PacketTypeTest {
|
||||
try {
|
||||
PacketType type = PacketType.fromClass(packetClass);
|
||||
for (String alias : type.names) {
|
||||
alias = alias.substring(alias.lastIndexOf('.') + 1);
|
||||
if (!names.contains(alias)) {
|
||||
names.add(alias);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) { }
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
@@ -229,14 +248,15 @@ public class PacketTypeTest {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void initializeReflection() {
|
||||
BukkitInitialization.initializePackage();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCurrent() {
|
||||
assertEquals(PacketType.Play.Client.STEER_VEHICLE, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
|
||||
assertEquals(PacketType.Play.Client.STEER_VEHICLE,
|
||||
PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -247,12 +267,12 @@ public class PacketTypeTest {
|
||||
|
||||
@Test
|
||||
public void testDeprecation() {
|
||||
assertTrue("Packet isn't properly deprecated", PacketType.Status.Server.OUT_SERVER_INFO.isDeprecated());
|
||||
assertTrue("Deprecated packet isn't properly included",
|
||||
PacketRegistry.getServerPacketTypes().contains(PacketType.Status.Server.OUT_SERVER_INFO));
|
||||
assertFalse("Packet isn't properly deprecated", PacketType.Play.Server.CHAT.isDeprecated());
|
||||
assertEquals("Deprecated packets aren't equal", PacketType.Status.Server.OUT_SERVER_INFO,
|
||||
PacketType.Status.Server.SERVER_INFO);
|
||||
assertTrue(PacketType.Status.Server.OUT_SERVER_INFO.isDeprecated(), "Packet isn't properly deprecated");
|
||||
assertTrue(PacketRegistry.getServerPacketTypes().contains(PacketType.Status.Server.OUT_SERVER_INFO),
|
||||
"Deprecated packet isn't properly included");
|
||||
assertFalse(PacketType.Play.Server.CHAT.isDeprecated(), "Packet isn't properly deprecated");
|
||||
assertEquals(PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.SERVER_INFO,
|
||||
"Deprecated packets aren't equal");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -262,12 +282,12 @@ public class PacketTypeTest {
|
||||
|
||||
EnumProtocol[] protocols = EnumProtocol.values();
|
||||
for (EnumProtocol protocol : protocols) {
|
||||
Field field = EnumProtocol.class.getDeclaredField("h");
|
||||
Field field = EnumProtocol.class.getDeclaredField("j");
|
||||
field.setAccessible(true);
|
||||
|
||||
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
|
||||
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
|
||||
Field mapField = entry.getValue().getClass().getDeclaredField("a");
|
||||
Field mapField = entry.getValue().getClass().getDeclaredField("b");
|
||||
mapField.setAccessible(true);
|
||||
|
||||
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
|
||||
@@ -280,9 +300,11 @@ public class PacketTypeTest {
|
||||
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
|
||||
try {
|
||||
PacketType type = PacketType.fromClass(entry1.getValue());
|
||||
if (type.getCurrentId() != entry1.getKey())
|
||||
if (type.getCurrentId() != entry1.getKey()) {
|
||||
throw new IllegalStateException(
|
||||
"Packet ID for " + type + " is incorrect. Expected " + entry1.getKey() + ", but got " + type.getCurrentId());
|
||||
"Packet ID for " + type + " is incorrect. Expected " + entry1.getKey() + ", but got "
|
||||
+ type.getCurrentId());
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = true;
|
||||
@@ -291,6 +313,22 @@ public class PacketTypeTest {
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue("Packet type(s) were incorrect!", !fail);
|
||||
assertFalse(fail, "Packet type(s) were incorrect!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPacketCreation() {
|
||||
boolean fail = false;
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isSupported()) {
|
||||
try {
|
||||
new PacketContainer(type);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertFalse(fail, "Packet type(s) failed to instantiate");
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,28 @@
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 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.concurrency;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BlockingHashMapTest {
|
||||
|
||||
@@ -35,25 +33,21 @@ public class BlockingHashMapTest {
|
||||
final BlockingHashMap<Integer, String> map = BlockingHashMap.create();
|
||||
|
||||
ExecutorService service = Executors.newSingleThreadExecutor();
|
||||
|
||||
|
||||
// Create a reader
|
||||
Future<String> future = service.submit(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
// Combine for easy reading
|
||||
return map.get(0) + map.get(1);
|
||||
}
|
||||
Future<String> future = service.submit(() -> {
|
||||
// Combine for easy reading
|
||||
return map.get(0) + map.get(1);
|
||||
});
|
||||
|
||||
// Wait a bit
|
||||
Thread.sleep(50);
|
||||
|
||||
|
||||
// Insert values
|
||||
map.put(0, "hello ");
|
||||
map.put(1, "world");
|
||||
|
||||
|
||||
// Wait for the other thread to complete
|
||||
assertEquals(future.get(), "hello world");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,31 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2012 Kristian S.
|
||||
* Stangeland
|
||||
* <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.events;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemCollectionsEqual;
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static com.comphenix.protocol.utility.TestUtils.equivalentItem;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
@@ -28,20 +35,48 @@ import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.*;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.ComponentConverter;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
|
||||
import com.comphenix.protocol.wrappers.MovingObjectPositionBlock;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import com.comphenix.protocol.wrappers.WrappedBlockData;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.md_5.bungee.api.chat.*;
|
||||
import net.minecraft.server.v1_16_R3.*;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.resources.MinecraftKey;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectList;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.world.entity.npc.VillagerData;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
import net.minecraft.world.entity.npc.VillagerType;
|
||||
import org.apache.commons.lang.SerializationUtils;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -54,34 +89,26 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.*;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
// Ensure that the CraftItemFactory is mockable
|
||||
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
|
||||
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*", "javax.management.*", "javax.xml.parsers.*", "com.sun.org.apache.xerces.internal.jaxp.*" })
|
||||
//@PrepareForTest(CraftItemFactory.class)
|
||||
public class PacketContainerTest {
|
||||
// Helper converters
|
||||
private EquivalentConverter<WrappedDataWatcher> watchConvert = BukkitConverters.getDataWatcherConverter();
|
||||
private EquivalentConverter<ItemStack> itemConvert = BukkitConverters.getItemStackConverter();
|
||||
|
||||
private static BaseComponent[] TEST_COMPONENT;
|
||||
// Helper converters
|
||||
private final EquivalentConverter<WrappedDataWatcher> watchConvert = BukkitConverters.getDataWatcherConverter();
|
||||
private final EquivalentConverter<ItemStack> itemConvert = BukkitConverters.getItemStackConverter();
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeItemMeta();
|
||||
BukkitInitialization.initializePackage();
|
||||
BukkitInitialization.initializeAll();
|
||||
|
||||
TEST_COMPONENT =
|
||||
new ComponentBuilder("Hit or miss?")
|
||||
.event(new ClickEvent(ClickEvent.Action.OPEN_URL, "http://reddit.com"))
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new BaseComponent[] { new TextComponent("The \"front page\" of the internet") }))
|
||||
.append("I guess they never miss, huh?").create();
|
||||
TEST_COMPONENT = new ComponentBuilder("Hit or miss?")
|
||||
.event(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://reddit.com"))
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("The \"front page\" of the internet")))
|
||||
.append("I guess they never miss, huh?")
|
||||
.create();
|
||||
}
|
||||
|
||||
private <T> void testPrimitive(StructureModifier<T> modifier, int index, T initialValue, T testValue) {
|
||||
@@ -95,7 +122,7 @@ public class PacketContainerTest {
|
||||
|
||||
private <T> void testObjectArray(StructureModifier<T[]> modifier, int index, T[] initialValue, T[] testValue) {
|
||||
// Check initial value
|
||||
assertNull(modifier.read(index));
|
||||
assertEquals(modifier.read(index).length, initialValue.length);
|
||||
modifier.writeDefaults();
|
||||
|
||||
// Test initial
|
||||
@@ -111,7 +138,7 @@ public class PacketContainerTest {
|
||||
// Contains a byte array we will test
|
||||
PacketContainer customPayload = new PacketContainer(PacketType.Login.Client.ENCRYPTION_BEGIN);
|
||||
StructureModifier<byte[]> bytes = customPayload.getByteArrays();
|
||||
byte[] testArray = new byte[] { 1, 2, 3 };
|
||||
byte[] testArray = new byte[]{1, 2, 3};
|
||||
|
||||
// It's NULL at first
|
||||
// assertEquals(null, bytes.read(0));
|
||||
@@ -128,61 +155,61 @@ public class PacketContainerTest {
|
||||
@Test
|
||||
public void testGetBytes() {
|
||||
PacketContainer spawnMob = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY_LIVING);
|
||||
testPrimitive(spawnMob.getBytes(), 0, (byte)0, (byte)1);
|
||||
this.testPrimitive(spawnMob.getBytes(), 0, (byte) 0, (byte) 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShorts() {
|
||||
PacketContainer itemData = new PacketContainer(PacketType.Play.Server.TRANSACTION);
|
||||
testPrimitive(itemData.getShorts(), 0, (short)0, (short)1);
|
||||
PacketContainer itemData = new PacketContainer(PacketType.Play.Server.REL_ENTITY_MOVE);
|
||||
this.testPrimitive(itemData.getShorts(), 0, (short) 0, (short) 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIntegers() {
|
||||
PacketContainer updateSign = new PacketContainer(PacketType.Play.Client.CLOSE_WINDOW);
|
||||
testPrimitive(updateSign.getIntegers(), 0, 0, 1);
|
||||
this.testPrimitive(updateSign.getIntegers(), 0, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLongs() {
|
||||
PacketContainer updateTime = new PacketContainer(PacketType.Play.Server.UPDATE_TIME);
|
||||
testPrimitive(updateTime.getLongs(), 0, (long)0, (long)1);
|
||||
this.testPrimitive(updateTime.getLongs(), 0, (long) 0, (long) 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFloat() {
|
||||
PacketContainer explosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
|
||||
testPrimitive(explosion.getFloat(), 0, (float)0, (float)0.8);
|
||||
this.testPrimitive(explosion.getFloat(), 0, (float) 0, (float) 0.8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDoubles() {
|
||||
PacketContainer explosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
|
||||
testPrimitive(explosion.getDoubles(), 0, (double)0, 0.8);
|
||||
this.testPrimitive(explosion.getDoubles(), 0, (double) 0, 0.8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStrings() {
|
||||
PacketContainer explosion = new PacketContainer(PacketType.Play.Client.CHAT);
|
||||
testPrimitive(explosion.getStrings(), 0, null, "hello");
|
||||
this.testPrimitive(explosion.getStrings(), 0, "", "hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStringArrays() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Client.UPDATE_SIGN);
|
||||
testObjectArray(packet.getStringArrays(), 0, new String[0], new String[] { "hello", "world" });
|
||||
this.testObjectArray(packet.getStringArrays(), 0,
|
||||
new String[]{"", "", "", ""},
|
||||
new String[]{"hello", "world"}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIntegerArrays() {
|
||||
// Contains a byte array we will test
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.MOUNT);
|
||||
StructureModifier<int[]> integers = packet.getIntegerArrays();
|
||||
int[] testArray = new int[] { 1, 2, 3 };
|
||||
int[] testArray = new int[]{1, 2, 3};
|
||||
|
||||
// Pre and post conditions
|
||||
assertArrayEquals(null, integers.read(0));
|
||||
packet.getModifier().writeDefaults();
|
||||
assertArrayEquals(new int[0], integers.read(0));
|
||||
|
||||
integers.write(0, testArray);
|
||||
@@ -193,14 +220,14 @@ public class PacketContainerTest {
|
||||
public void testGetItemModifier() {
|
||||
PacketContainer windowClick = new PacketContainer(PacketType.Play.Client.WINDOW_CLICK);
|
||||
|
||||
ItemStack item = itemWithData();
|
||||
ItemStack item = this.itemWithData();
|
||||
|
||||
StructureModifier<ItemStack> items = windowClick.getItemModifier();
|
||||
// assertNull(items.read(0));
|
||||
|
||||
// Insert the item and check if it's there
|
||||
items.write(0, item);
|
||||
assertTrue("Item " + item + " != " + items.read(0), equivalentItem(item, items.read(0)));
|
||||
assertTrue(equivalentItem(item, items.read(0)), "Item " + item + " != " + items.read(0));
|
||||
}
|
||||
|
||||
private ItemStack itemWithData() {
|
||||
@@ -218,10 +245,10 @@ public class PacketContainerTest {
|
||||
StructureModifier<List<ItemStack>> itemAccess = windowItems.getItemListModifier();
|
||||
|
||||
List<ItemStack> items = new ArrayList<>();
|
||||
items.add(itemWithData());
|
||||
items.add(this.itemWithData());
|
||||
items.add(new ItemStack(Material.DIAMOND_AXE));
|
||||
|
||||
assertNull(itemAccess.read(0));
|
||||
assertEquals(itemAccess.read(0).size(), 0);
|
||||
|
||||
// Insert and check that it was succesful
|
||||
itemAccess.write(0, items);
|
||||
@@ -234,8 +261,9 @@ public class PacketContainerTest {
|
||||
@Test
|
||||
public void testGetWorldTypeModifier() {
|
||||
// Not used in Netty
|
||||
if (MinecraftReflection.isUsingNetty())
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PacketContainer loginPacket = new PacketContainer(PacketType.Play.Server.LOGIN);
|
||||
StructureModifier<WorldType> worldAccess = loginPacket.getWorldTypeModifier();
|
||||
@@ -307,7 +335,7 @@ public class PacketContainerTest {
|
||||
PacketContainer explosionPacket = new PacketContainer(PacketType.Play.Server.EXPLOSION);
|
||||
StructureModifier<List<BlockPosition>> positionAccessor = explosionPacket.getBlockPositionCollectionModifier();
|
||||
|
||||
assertNull(positionAccessor.read(0));
|
||||
assertEquals(positionAccessor.read(0).size(), 0);
|
||||
|
||||
List<BlockPosition> positions = Lists.newArrayList();
|
||||
positions.add(new BlockPosition(1, 2, 3));
|
||||
@@ -346,7 +374,8 @@ public class PacketContainerTest {
|
||||
@Test
|
||||
public void testGameProfiles() {
|
||||
PacketContainer spawnEntity = new PacketContainer(PacketType.Login.Server.SUCCESS);
|
||||
WrappedGameProfile profile = new WrappedGameProfile(UUID.fromString("d7047a08-3150-4aa8-a2f2-7c1e2b17e298"), "name");
|
||||
WrappedGameProfile profile = new WrappedGameProfile(UUID.fromString("d7047a08-3150-4aa8-a2f2-7c1e2b17e298"),
|
||||
"name");
|
||||
spawnEntity.getGameProfiles().write(0, profile);
|
||||
|
||||
assertEquals(profile, spawnEntity.getGameProfiles().read(0));
|
||||
@@ -359,7 +388,7 @@ public class PacketContainerTest {
|
||||
WrappedChatComponent.fromChatMessage("You shall not " + ChatColor.ITALIC + "pass!")[0]);
|
||||
|
||||
assertEquals("{\"extra\":[{\"text\":\"You shall not \"},{\"italic\":true,\"text\":\"pass!\"}],\"text\":\"\"}",
|
||||
chatPacket.getChatComponents().read(0).getJson());
|
||||
chatPacket.getChatComponents().read(0).getJson());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -373,6 +402,19 @@ public class PacketContainerTest {
|
||||
assertEquals("Test", copy.getStrings().read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntList() {
|
||||
PacketContainer destroy = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
|
||||
destroy.getIntLists().write(0, new ArrayList<Integer>() {{
|
||||
this.add(420);
|
||||
this.add(69);
|
||||
}});
|
||||
List<Integer> back = destroy.getIntLists().read(0);
|
||||
assertEquals(back.size(), 2);
|
||||
assertEquals((int) back.get(0), 420);
|
||||
assertEquals((int) back.get(1), 69);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeList() {
|
||||
PacketContainer attribute = new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES);
|
||||
@@ -380,18 +422,20 @@ public class PacketContainerTest {
|
||||
|
||||
// Initialize some test data
|
||||
List<AttributeModifier> modifiers = Lists.newArrayList(
|
||||
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10, AttributeModifier.Operation.ADDITION));
|
||||
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10,
|
||||
AttributeModifier.Operation.a));
|
||||
|
||||
// Obtain an AttributeSnapshot instance. This is complicated by the fact that AttributeSnapshots
|
||||
// are inner classes (which is ultimately pointless because AttributeSnapshots don't access any
|
||||
// members of the packet itself)
|
||||
PacketPlayOutUpdateAttributes packet = (PacketPlayOutUpdateAttributes) attribute.getHandle();
|
||||
AttributeBase base = IRegistry.ATTRIBUTE.get(MinecraftKey.a("generic.max_health"));
|
||||
AttributeSnapshot snapshot = packet.new AttributeSnapshot(base, 20.0D, modifiers);
|
||||
AttributeBase base = IRegistry.aj.a(MinecraftKey.a("generic.max_health"));
|
||||
AttributeSnapshot snapshot = new AttributeSnapshot(base, 20.0D, modifiers);
|
||||
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
|
||||
|
||||
PacketContainer cloned = attribute.deepClone();
|
||||
AttributeSnapshot clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
|
||||
AttributeSnapshot
|
||||
clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
|
||||
|
||||
// Compare the fields, because apparently the packet is a field in AttributeSnapshot
|
||||
for (Field field : AttributeSnapshot.class.getDeclaredFields()) {
|
||||
@@ -402,7 +446,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
assertEquals(field.get(snapshot), field.get(clonedSnapshot));
|
||||
this.testEquality(field.get(snapshot), field.get(clonedSnapshot));
|
||||
} catch (AssertionError e) {
|
||||
throw e;
|
||||
} catch (Throwable ex) {
|
||||
@@ -435,26 +479,33 @@ public class PacketContainerTest {
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testPotionEffect() {
|
||||
PotionEffect effect = new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 20 * 60, 1);
|
||||
MobEffect mobEffect = new MobEffect(MobEffectList.fromId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(),
|
||||
MobEffect mobEffect = new MobEffect(MobEffectList.a(effect.getType().getId()), effect.getDuration(),
|
||||
effect.getAmplifier(), effect.isAmbient(),
|
||||
effect.hasParticles());
|
||||
int entityId = 42;
|
||||
|
||||
|
||||
// The constructor we want to call
|
||||
PacketConstructor creator = PacketConstructor.DEFAULT.withPacket(
|
||||
PacketType.Play.Server.ENTITY_EFFECT, new Class<?>[] { int.class, MobEffect.class });
|
||||
PacketType.Play.Server.ENTITY_EFFECT, new Class<?>[]{int.class, MobEffect.class});
|
||||
PacketContainer packet = creator.createPacket(entityId, mobEffect);
|
||||
|
||||
assertEquals(entityId, (int) packet.getIntegers().read(0));
|
||||
assertEquals(effect.getType().getId(), (byte) packet.getBytes().read(0));
|
||||
assertEquals(effect.getAmplifier(), (byte) packet.getBytes().read(1));
|
||||
assertEquals(effect.getDuration(), (int) packet.getIntegers().read(1));
|
||||
assertEquals(entityId, packet.getIntegers().read(0));
|
||||
assertEquals(effect.getType().getId(), packet.getIntegers().read(1));
|
||||
assertEquals(effect.getAmplifier(), (byte) packet.getBytes().read(0));
|
||||
assertEquals(effect.getDuration(), packet.getIntegers().read(2));
|
||||
|
||||
int e = 0;
|
||||
if (effect.isAmbient()) e |= 1;
|
||||
if (effect.hasParticles()) e |= 2;
|
||||
if (effect.hasIcon()) e |= 4;
|
||||
if (effect.isAmbient()) {
|
||||
e |= 1;
|
||||
}
|
||||
if (effect.hasParticles()) {
|
||||
e |= 2;
|
||||
}
|
||||
if (effect.hasIcon()) {
|
||||
e |= 4;
|
||||
}
|
||||
|
||||
assertEquals(e, (byte) packet.getBytes().read(2));
|
||||
assertEquals(e, (byte) packet.getBytes().read(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -494,16 +545,35 @@ public class PacketContainerTest {
|
||||
assertEquals(container.getSoundEffects().read(0), Sound.ENTITY_CAT_HISS);
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Test
|
||||
public void testGenericEnums() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.BOSS);
|
||||
container.getEnumModifier(Action.class, 1).write(0, Action.UPDATE_PCT);
|
||||
|
||||
assertEquals(container.getEnumModifier(Action.class, PacketPlayOutBoss.Action.class).read(0), Action.UPDATE_PCT);
|
||||
// assertEquals(container.getEnumModifier(Action.class, PacketPlayOutBoss.d.class).read(0), Action.UPDATE_PCT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalStructures() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM);
|
||||
Optional<InternalStructure> optStruct = container.getOptionalStructures().read(0);
|
||||
assertTrue(optStruct.isPresent());
|
||||
InternalStructure struct = optStruct.get();
|
||||
struct.getChatComponents().write(0, WrappedChatComponent.fromText("hi there"));
|
||||
container.getOptionalStructures().write(0, Optional.of(struct));
|
||||
|
||||
optStruct = container.getOptionalStructures().read(0);
|
||||
assertTrue(optStruct.isPresent());
|
||||
struct = optStruct.get();
|
||||
this.testEquality(
|
||||
struct.getChatComponents().read(0),
|
||||
WrappedChatComponent.fromText("hi there")
|
||||
);
|
||||
}
|
||||
|
||||
// @Test
|
||||
public void testDimensions() {
|
||||
// TODO this won't work in testing, but hopefully will in live
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.RESPAWN);
|
||||
container.getDimensions().write(0, 1);
|
||||
assertEquals((Object) 1, container.getDimensions().read(0));
|
||||
@@ -546,14 +616,14 @@ public class PacketContainerTest {
|
||||
public void testMultiBlockChange() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.MULTI_BLOCK_CHANGE);
|
||||
|
||||
packet.getShortArrays().writeSafely(0, new short[] { 420, 69 });
|
||||
assertArrayEquals(new short[] { 420, 69}, packet.getShortArrays().readSafely(0));
|
||||
packet.getShortArrays().writeSafely(0, new short[]{420, 69});
|
||||
assertArrayEquals(new short[]{420, 69}, packet.getShortArrays().readSafely(0));
|
||||
|
||||
packet.getBlockDataArrays().writeSafely(0, new WrappedBlockData[] {
|
||||
packet.getBlockDataArrays().writeSafely(0, new WrappedBlockData[]{
|
||||
WrappedBlockData.createData(Material.IRON_BARS),
|
||||
WrappedBlockData.createData(Material.IRON_BLOCK)
|
||||
});
|
||||
assertArrayEquals(new WrappedBlockData[] {
|
||||
assertArrayEquals(new WrappedBlockData[]{
|
||||
WrappedBlockData.createData(Material.IRON_BARS),
|
||||
WrappedBlockData.createData(Material.IRON_BLOCK)
|
||||
}, packet.getBlockDataArrays().readSafely(0));
|
||||
@@ -565,23 +635,80 @@ public class PacketContainerTest {
|
||||
assertNotSame(clone, packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions from the outbound Boss packet. Used for testing generic enums.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public enum Action {
|
||||
ADD,
|
||||
REMOVE,
|
||||
UPDATE_PCT,
|
||||
UPDATE_NAME,
|
||||
UPDATE_STYLE,
|
||||
UPDATE_PROPERTIES
|
||||
@Test
|
||||
public void testGameStateChange() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.GAME_STATE_CHANGE);
|
||||
assertEquals(0, (int) packet.getGameStateIDs().read(0));
|
||||
|
||||
packet.getGameStateIDs().write(0, 2);
|
||||
assertEquals(2, (int) packet.getGameStateIDs().read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseEntity() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Client.USE_ENTITY);
|
||||
|
||||
WrappedEnumEntityUseAction action;
|
||||
WrappedEnumEntityUseAction clone;
|
||||
// test attack
|
||||
packet.getEnumEntityUseActions().write(0, WrappedEnumEntityUseAction.attack());
|
||||
action = packet.getEnumEntityUseActions().read(0);
|
||||
// attack's handle should always be the same
|
||||
assertEquals(WrappedEnumEntityUseAction.attack(), action);
|
||||
assertEquals(EntityUseAction.ATTACK, action.getAction());
|
||||
// hand & position should not be available
|
||||
assertThrows(IllegalArgumentException.class, action::getHand);
|
||||
assertThrows(IllegalArgumentException.class, action::getPosition);
|
||||
// test cloning
|
||||
clone = action.deepClone();
|
||||
assertSame(WrappedEnumEntityUseAction.attack(), clone);
|
||||
|
||||
// test interact
|
||||
packet.getEnumEntityUseActions().write(0, WrappedEnumEntityUseAction.interact(Hand.OFF_HAND));
|
||||
action = packet.getEnumEntityUseActions().read(0);
|
||||
assertEquals(EntityUseAction.INTERACT, action.getAction());
|
||||
assertEquals(Hand.OFF_HAND, action.getHand());
|
||||
// position should not be available
|
||||
assertThrows(IllegalArgumentException.class, action::getPosition);
|
||||
// test cloning
|
||||
clone = action.deepClone();
|
||||
assertEquals(EntityUseAction.INTERACT, clone.getAction());
|
||||
assertEquals(Hand.OFF_HAND, clone.getHand());
|
||||
|
||||
// test interact_at
|
||||
Vector position = new Vector(1, 199, 4);
|
||||
packet.getEnumEntityUseActions().write(0, WrappedEnumEntityUseAction.interactAt(Hand.MAIN_HAND, position));
|
||||
action = packet.getEnumEntityUseActions().read(0);
|
||||
assertEquals(EntityUseAction.INTERACT_AT, action.getAction());
|
||||
assertEquals(Hand.MAIN_HAND, action.getHand());
|
||||
assertEquals(position, action.getPosition());
|
||||
// test cloning
|
||||
clone = action.deepClone();
|
||||
assertEquals(EntityUseAction.INTERACT_AT, clone.getAction());
|
||||
assertEquals(Hand.MAIN_HAND, clone.getHand());
|
||||
assertEquals(position, clone.getPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSimulationDistance() {
|
||||
// first packet which is a record - set will fail if we missed something during patching
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.UPDATE_SIMULATION_DISTANCE);
|
||||
container.getIntegers().write(0, 1234);
|
||||
assertEquals(1234, (int) container.getIntegers().read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapChunk() {
|
||||
// this is a special case as we are generating a data serializer class (we only need to construct the packet)
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.MAP_CHUNK);
|
||||
// check if we can read an nbt compound from the class
|
||||
assertTrue(container.getStructures().read(0).getNbtModifier().optionRead(0).isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentArrays() {
|
||||
PacketContainer signChange = new PacketContainer(PacketType.Play.Server.TILE_ENTITY_DATA);
|
||||
WrappedChatComponent[] components = new WrappedChatComponent[] {
|
||||
WrappedChatComponent[] components = new WrappedChatComponent[]{
|
||||
WrappedChatComponent.fromText("hello world"), WrappedChatComponent.fromText(""),
|
||||
WrappedChatComponent.fromText(""), WrappedChatComponent.fromText("")
|
||||
};
|
||||
@@ -591,12 +718,33 @@ public class PacketContainerTest {
|
||||
assertArrayEquals(components, back);
|
||||
}
|
||||
|
||||
private void assertPacketsEqual(PacketContainer constructed, PacketContainer cloned) {
|
||||
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
|
||||
assertEquals(firstMod.size(), secondMod.size());
|
||||
|
||||
if (PacketType.Status.Server.SERVER_INFO.equals(constructed.getType())) {
|
||||
assertArrayEquals(SerializationUtils.serialize(constructed), SerializationUtils.serialize(cloned));
|
||||
} else {
|
||||
// Make sure all the fields are equivalent
|
||||
for (int i = 0; i < firstMod.size(); i++) {
|
||||
if (firstMod.getField(i).getType().isArray()) {
|
||||
assertArrayEquals(this.getArray(firstMod.read(i)), this.getArray(secondMod.read(i)));
|
||||
} else {
|
||||
this.testEquality(firstMod.read(i), secondMod.read(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepClone() {
|
||||
public void testCloning() {
|
||||
boolean failed = false;
|
||||
|
||||
// Try constructing all the packets
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isDeprecated() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("TAGS") || !type.isSupported()
|
||||
|| type == PacketType.Play.Server.RECIPES) {
|
||||
if (type.isDeprecated() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("TAGS")
|
||||
|| !type.isSupported()
|
||||
|| type == PacketType.Play.Server.RECIPES) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -615,64 +763,66 @@ public class PacketContainerTest {
|
||||
"String"),
|
||||
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.get(Float.class)), 1.0F),
|
||||
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.getChatComponentSerializer(true)),
|
||||
com.google.common.base.Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
|
||||
Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
|
||||
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.get(VillagerData.class)),
|
||||
new VillagerData(VillagerType.SNOW, VillagerProfession.ARMORER, 69))
|
||||
new VillagerData(VillagerType.b, VillagerProfession.c, 69))
|
||||
));
|
||||
} else if (type == PacketType.Play.Server.CHAT) {
|
||||
constructed.getChatComponents().write(0, ComponentConverter.fromBaseComponent(TEST_COMPONENT));
|
||||
//constructed.getModifier().write(1, TEST_COMPONENT);
|
||||
}
|
||||
|
||||
// Clone the packet
|
||||
PacketContainer cloned = constructed.deepClone();
|
||||
// Clone the packet both ways
|
||||
PacketContainer shallowCloned = constructed.shallowClone();
|
||||
this.assertPacketsEqual(constructed, shallowCloned);
|
||||
|
||||
// Make sure they're equivalent
|
||||
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
|
||||
assertEquals(firstMod.size(), secondMod.size());
|
||||
|
||||
if (PacketType.Status.Server.SERVER_INFO.equals(type)) {
|
||||
assertArrayEquals(SerializationUtils.serialize(constructed), SerializationUtils.serialize(cloned));
|
||||
} else {
|
||||
// Make sure all the fields are equivalent
|
||||
for (int i = 0; i < firstMod.size(); i++) {
|
||||
if (firstMod.getField(i).getType().isArray())
|
||||
assertArrayEquals(getArray(firstMod.read(i)), getArray(secondMod.read(i)));
|
||||
else
|
||||
testEquality(firstMod.read(i), secondMod.read(i));
|
||||
}
|
||||
}
|
||||
PacketContainer deepCloned = constructed.deepClone();
|
||||
this.assertPacketsEqual(constructed, deepCloned);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to serialize packet " + type, ex);
|
||||
ex.printStackTrace();
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
assertFalse(failed, "Packet(s) failed to clone");
|
||||
}
|
||||
|
||||
// Convert to objects that support equals()
|
||||
private void testEquality(Object a, Object b) {
|
||||
if (a != null && b != null) {
|
||||
if (MinecraftReflection.isDataWatcher(a)) {
|
||||
a = watchConvert.getSpecific(a);
|
||||
b = watchConvert.getSpecific(b);
|
||||
} else if (MinecraftReflection.isItemStack(a)) {
|
||||
a = itemConvert.getSpecific(a);
|
||||
b = itemConvert.getSpecific(b);
|
||||
if (a == null) {
|
||||
if (b == null) {
|
||||
return;
|
||||
} else {
|
||||
throw new AssertionError("a was null, but b was not");
|
||||
}
|
||||
} else if (b == null) {
|
||||
throw new AssertionError("a was not null, but b was null");
|
||||
}
|
||||
|
||||
if (a instanceof Optional) {
|
||||
if (b instanceof Optional) {
|
||||
this.testEquality(((Optional<?>) a).orElse(null), ((Optional<?>) b).orElse(null));
|
||||
return;
|
||||
} else {
|
||||
throw new AssertionError("a was optional, but b was not");
|
||||
}
|
||||
}
|
||||
|
||||
if (a instanceof ItemStack || b instanceof ItemStack) {
|
||||
assertItemsEqual((ItemStack) a, (ItemStack) b);
|
||||
if (a.equals(b) || Objects.equals(a, b) || this.stringEquality(a, b)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == null || b == null) {
|
||||
if (a == null && b == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (a.equals(b) || Objects.equals(a, b) || stringEquality(a, b)) {
|
||||
return;
|
||||
}
|
||||
if (MinecraftReflection.isDataWatcher(a)) {
|
||||
a = this.watchConvert.getSpecific(a);
|
||||
b = this.watchConvert.getSpecific(b);
|
||||
} else if (MinecraftReflection.isItemStack(a)) {
|
||||
a = this.itemConvert.getSpecific(a);
|
||||
b = this.itemConvert.getSpecific(b);
|
||||
}
|
||||
|
||||
if (a instanceof ItemStack && b instanceof ItemStack) {
|
||||
assertItemsEqual((ItemStack) a, (ItemStack) b);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EqualsBuilder.reflectionEquals(a, b)) {
|
||||
@@ -693,20 +843,38 @@ public class PacketContainerTest {
|
||||
|
||||
/**
|
||||
* Get the underlying array as an object array.
|
||||
*
|
||||
* @param val - array wrapped as an Object.
|
||||
* @return An object array.
|
||||
*/
|
||||
private Object[] getArray(Object val) {
|
||||
if (val instanceof Object[])
|
||||
if (val instanceof Object[]) {
|
||||
return (Object[]) val;
|
||||
if (val == null)
|
||||
}
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int arrlength = Array.getLength(val);
|
||||
Object[] outputArray = new Object[arrlength];
|
||||
|
||||
for (int i = 0; i < arrlength; ++i)
|
||||
for (int i = 0; i < arrlength; ++i) {
|
||||
outputArray[i] = Array.get(val, i);
|
||||
}
|
||||
return outputArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions from the outbound Boss packet. Used for testing generic enums.
|
||||
*
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public enum Action {
|
||||
ADD,
|
||||
REMOVE,
|
||||
UPDATE_PCT,
|
||||
UPDATE_NAME,
|
||||
UPDATE_STYLE,
|
||||
UPDATE_PROPERTIES
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,70 @@
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.UUID;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SerializedOfflinePlayerTest {
|
||||
|
||||
@Mock
|
||||
static OfflinePlayer offlinePlayer;
|
||||
private static final String name = "playerName";
|
||||
private static final long firstPlayed = 1000L;
|
||||
private static final long lastPlayed = firstPlayed + 100L;
|
||||
private static final boolean isOp = false;
|
||||
private static final boolean playedBefore = true;
|
||||
private static final boolean whitelisted = true;
|
||||
@Mock
|
||||
static OfflinePlayer offlinePlayer;
|
||||
private static UUID uuid;
|
||||
private static SerializedOfflinePlayer serializedOfflinePlayer;
|
||||
|
||||
private static final String name = "playerName";
|
||||
private static UUID uuid;
|
||||
private static final long firstPlayed = 1000L;
|
||||
private static final long lastPlayed = firstPlayed + 100L;
|
||||
private static final boolean isOp = false;
|
||||
private static final boolean playedBefore = true;
|
||||
private static final boolean whitelisted = true;
|
||||
@BeforeEach
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
|
||||
private static SerializedOfflinePlayer serializedOfflinePlayer;
|
||||
uuid = UUID.randomUUID();
|
||||
when(offlinePlayer.getName()).thenReturn(name);
|
||||
when(offlinePlayer.getUniqueId()).thenReturn(uuid);
|
||||
when(offlinePlayer.getFirstPlayed()).thenReturn(firstPlayed);
|
||||
when(offlinePlayer.getLastPlayed()).thenReturn(lastPlayed);
|
||||
when(offlinePlayer.isOp()).thenReturn(isOp);
|
||||
when(offlinePlayer.hasPlayedBefore()).thenReturn(playedBefore);
|
||||
when(offlinePlayer.isWhitelisted()).thenReturn(whitelisted);
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
serializedOfflinePlayer = new SerializedOfflinePlayer(offlinePlayer);
|
||||
}
|
||||
|
||||
uuid = UUID.randomUUID();
|
||||
when(offlinePlayer.getName()).thenReturn(name);
|
||||
when(offlinePlayer.getUniqueId()).thenReturn(uuid);
|
||||
when(offlinePlayer.getFirstPlayed()).thenReturn(firstPlayed);
|
||||
when(offlinePlayer.getLastPlayed()).thenReturn(lastPlayed);
|
||||
when(offlinePlayer.isOp()).thenReturn(isOp);
|
||||
when(offlinePlayer.hasPlayedBefore()).thenReturn(playedBefore);
|
||||
when(offlinePlayer.isWhitelisted()).thenReturn(whitelisted);
|
||||
@Test
|
||||
public void getProxyPlayer() {
|
||||
Player player = serializedOfflinePlayer.getProxyPlayer();
|
||||
assertNotNull(player);
|
||||
|
||||
serializedOfflinePlayer = new SerializedOfflinePlayer(offlinePlayer);
|
||||
}
|
||||
// getDisplayName only works for online players.
|
||||
assertThrows(UnsupportedOperationException.class, player::getDisplayName);
|
||||
|
||||
@Test
|
||||
public void getProxyPlayer() {
|
||||
Player player = serializedOfflinePlayer.getProxyPlayer();
|
||||
Assert.assertNotNull(player);
|
||||
assertEquals(uuid, player.getUniqueId());
|
||||
assertEquals(name, player.getName());
|
||||
assertEquals(firstPlayed, player.getFirstPlayed());
|
||||
assertEquals(lastPlayed, player.getLastPlayed());
|
||||
assertEquals(isOp, player.isOp());
|
||||
assertEquals(playedBefore, player.hasPlayedBefore());
|
||||
assertEquals(whitelisted, player.isWhitelisted());
|
||||
}
|
||||
|
||||
// getDisplayName only works for online players.
|
||||
assertThrows(UnsupportedOperationException.class, player::getDisplayName);
|
||||
@Test
|
||||
public void getSecondProxyPlayer() {
|
||||
// Make sure that the proxyPlayer generation doesn't work only once.
|
||||
Player player = serializedOfflinePlayer.getProxyPlayer();
|
||||
assertNotNull(player);
|
||||
|
||||
assertEquals(uuid, player.getUniqueId());
|
||||
assertEquals(name, player.getName());
|
||||
assertEquals(firstPlayed, player.getFirstPlayed());
|
||||
assertEquals(lastPlayed, player.getLastPlayed());
|
||||
assertEquals(isOp, player.isOp());
|
||||
assertEquals(playedBefore, player.hasPlayedBefore());
|
||||
assertEquals(whitelisted, player.isWhitelisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSecondProxyPlayer() {
|
||||
// Make sure that the proxyPlayer generation doesn't work only once.
|
||||
Player player = serializedOfflinePlayer.getProxyPlayer();
|
||||
Assert.assertNotNull(player);
|
||||
|
||||
assertEquals(uuid, player.getUniqueId());
|
||||
}
|
||||
assertEquals(uuid, player.getUniqueId());
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,31 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
|
||||
import net.minecraft.server.v1_16_R3.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunkMap.EntityTracker;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
|
||||
import org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static com.comphenix.protocol.utility.TestUtils.setFinalField;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.lang.reflect.Field;
|
||||
import net.minecraft.server.level.ChunkProviderServer;
|
||||
import net.minecraft.server.level.PlayerChunkMap;
|
||||
import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EntityUtilitiesTest {
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeItemMeta();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -34,21 +35,27 @@ public class EntityUtilitiesTest {
|
||||
when(bukkit.getHandle()).thenReturn(world);
|
||||
|
||||
ChunkProviderServer provider = mock(ChunkProviderServer.class);
|
||||
when(world.getChunkProvider()).thenReturn(provider);
|
||||
when(world.k()).thenReturn(provider);
|
||||
|
||||
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
|
||||
Accessors.getFieldAccessor(ChunkProviderServer.class, "playerChunkMap", true).set(provider, chunkMap);
|
||||
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
|
||||
setFinalField(provider, chunkMapField, chunkMap);
|
||||
|
||||
CraftEntity bukkitEntity = mock(CraftEntity.class);
|
||||
Entity fakeEntity = mock(Entity.class);
|
||||
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
|
||||
|
||||
EntityTracker tracker = mock(EntityTracker.class);
|
||||
Accessors.getFieldAccessor(EntityTracker.class, "tracker", true).set(tracker, fakeEntity);
|
||||
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
|
||||
setFinalField(tracker, trackerField, fakeEntity);
|
||||
|
||||
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
|
||||
trackerMap.put(1, tracker);
|
||||
Accessors.getFieldAccessor(PlayerChunkMap.class, "trackedEntities", true).set(chunkMap, trackerMap);
|
||||
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
|
||||
setFinalField(chunkMap, trackedEntitiesField, trackerMap);
|
||||
|
||||
assertEquals(bukkitEntity, EntityUtilities.getInstance().getEntityFromID(bukkit, 1));
|
||||
}
|
||||
|
||||
@@ -1,53 +1,46 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.injector.PluginVerifier.VerificationResult;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoadOrder;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
|
||||
import com.comphenix.protocol.injector.PluginVerifier.VerificationResult;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
// Damn final classes
|
||||
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
|
||||
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
|
||||
@PrepareForTest(PluginDescriptionFile.class)
|
||||
public class PluginVerifierTest {
|
||||
|
||||
@Test
|
||||
public void testDependecies() {
|
||||
List<Plugin> plugins = Lists.newArrayList();
|
||||
Server server = mockServer(plugins);
|
||||
|
||||
Plugin library = mockPlugin(server, "ProtocolLib", PluginLoadOrder.POSTWORLD);
|
||||
Plugin skillPlugin = mockPlugin(server, "SkillPlugin", "RaidCraft-API", "RCPermissions", "RCConversations");
|
||||
Plugin raidCraftAPI = mockPlugin(server, "RaidCraft-API", "WorldGuard", "WorldEdit");
|
||||
Plugin conversations = mockPlugin(server, "RCConversations", "RaidCraft-API");
|
||||
Plugin permissions = mockPlugin(server, "RCPermissions", "RaidCraft-API");
|
||||
|
||||
Server server = this.mockServer(plugins);
|
||||
|
||||
Plugin library = this.mockPlugin(server, "ProtocolLib", PluginLoadOrder.POSTWORLD);
|
||||
Plugin skillPlugin = this.mockPlugin(server, "SkillPlugin", "RaidCraft-API", "RCPermissions", "RCConversations");
|
||||
Plugin raidCraftAPI = this.mockPlugin(server, "RaidCraft-API", "WorldGuard", "WorldEdit");
|
||||
Plugin conversations = this.mockPlugin(server, "RCConversations", "RaidCraft-API");
|
||||
Plugin permissions = this.mockPlugin(server, "RCPermissions", "RaidCraft-API");
|
||||
|
||||
// Add the plugins
|
||||
plugins.addAll(Arrays.asList(library, skillPlugin, raidCraftAPI, conversations, permissions));
|
||||
PluginVerifier verifier = new PluginVerifier(library);
|
||||
|
||||
|
||||
// Verify the root - it should have no dependencies on ProtocolLib
|
||||
assertEquals(VerificationResult.NO_DEPEND, verifier.verify(skillPlugin));
|
||||
}
|
||||
|
||||
|
||||
private Server mockServer(final List<Plugin> plugins) {
|
||||
Server mockServer = mock(Server.class);
|
||||
PluginManager manager = mock(PluginManager.class);
|
||||
@@ -57,7 +50,7 @@ public class PluginVerifierTest {
|
||||
@Override
|
||||
public Plugin answer(InvocationOnMock invocation) throws Throwable {
|
||||
String name = (String) invocation.getArguments()[0];
|
||||
|
||||
|
||||
for (Plugin plugin : plugins) {
|
||||
if (Objects.equal(name, plugin.getName())) {
|
||||
return plugin;
|
||||
@@ -68,20 +61,20 @@ public class PluginVerifierTest {
|
||||
});
|
||||
return mockServer;
|
||||
}
|
||||
|
||||
private Plugin mockPlugin(Server server, String name,String... depend) {
|
||||
return mockPlugin(server, name, PluginLoadOrder.POSTWORLD, depend);
|
||||
|
||||
private Plugin mockPlugin(Server server, String name, String... depend) {
|
||||
return this.mockPlugin(server, name, PluginLoadOrder.POSTWORLD, depend);
|
||||
}
|
||||
|
||||
|
||||
private Plugin mockPlugin(Server server, String name, PluginLoadOrder order, String... depend) {
|
||||
Plugin plugin = mock(Plugin.class);
|
||||
PluginDescriptionFile file = mock(PluginDescriptionFile.class);
|
||||
|
||||
|
||||
when(plugin.getServer()).thenReturn(server);
|
||||
when(plugin.getName()).thenReturn(name);
|
||||
when(plugin.toString()).thenReturn(name);
|
||||
when(plugin.getDescription()).thenReturn(file);
|
||||
|
||||
|
||||
// This is the difficult part
|
||||
when(file.getLoad()).thenReturn(order);
|
||||
when(file.getDepend()).thenReturn(Arrays.asList(depend));
|
||||
|
||||
@@ -2,85 +2,84 @@
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 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.injector;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import com.comphenix.protocol.concurrency.SortedCopyOnWriteArray;
|
||||
import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.google.common.primitives.Ints;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SortedCopyOnWriteArrayTest {
|
||||
|
||||
@Test
|
||||
public void testInsertion() {
|
||||
|
||||
final int MAX_NUMBER = 50;
|
||||
|
||||
SortedCopyOnWriteArray<Integer> test = new SortedCopyOnWriteArray<Integer>();
|
||||
|
||||
|
||||
// Generate some numbers
|
||||
List<Integer> numbers = new ArrayList<Integer>();
|
||||
|
||||
|
||||
for (int i = 0; i < MAX_NUMBER; i++) {
|
||||
numbers.add(i);
|
||||
}
|
||||
|
||||
|
||||
// Random insertion to test it all
|
||||
Collections.shuffle(numbers);
|
||||
|
||||
|
||||
// O(n^2) of course, so don't use too large numbers
|
||||
for (int i = 0; i < MAX_NUMBER; i++) {
|
||||
test.add(numbers.get(i));
|
||||
}
|
||||
|
||||
|
||||
// Check that everything is correct
|
||||
for (int i = 0; i < MAX_NUMBER; i++) {
|
||||
assertEquals((Integer) i, test.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOrder() {
|
||||
PriorityStuff a = new PriorityStuff(ListenerPriority.HIGH, 1);
|
||||
PriorityStuff b = new PriorityStuff(ListenerPriority.NORMAL, 2);
|
||||
PriorityStuff c = new PriorityStuff(ListenerPriority.NORMAL, 3);
|
||||
SortedCopyOnWriteArray<PriorityStuff> test = new SortedCopyOnWriteArray<PriorityStuff>();
|
||||
|
||||
|
||||
test.add(a);
|
||||
test.add(b);
|
||||
test.add(c);
|
||||
|
||||
|
||||
// Make sure the normal's are in the right order
|
||||
assertEquals(2, test.get(0).id);
|
||||
assertEquals(3, test.get(1).id);
|
||||
|
||||
|
||||
// Test remove
|
||||
test.remove(b);
|
||||
assertEquals(2, test.size());
|
||||
assertFalse(test.contains(b));
|
||||
}
|
||||
|
||||
|
||||
private static class PriorityStuff implements Comparable<PriorityStuff> {
|
||||
|
||||
public ListenerPriority priority;
|
||||
public int id;
|
||||
|
||||
@@ -92,8 +91,8 @@ public class SortedCopyOnWriteArrayTest {
|
||||
@Override
|
||||
public int compareTo(PriorityStuff other) {
|
||||
// This ensures that lower priority listeners are executed first
|
||||
return Ints.compare(priority.getSlot(),
|
||||
other.priority.getSlot());
|
||||
return Ints.compare(this.priority.getSlot(),
|
||||
other.priority.getSlot());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,32 +3,27 @@
|
||||
*/
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.ChatType;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class WirePacketTest {
|
||||
|
||||
@BeforeClass
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializePackage();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
// @Test
|
||||
@@ -36,8 +31,9 @@ public class WirePacketTest {
|
||||
List<String> failures = new ArrayList<>();
|
||||
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isDeprecated())
|
||||
if (type.isDeprecated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
PacketContainer packet = new PacketContainer(type);
|
||||
@@ -57,7 +53,7 @@ public class WirePacketTest {
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
int id = 42;
|
||||
byte[] array = { 1, 3, 7, 21, 88, 67, 8 };
|
||||
byte[] array = {1, 3, 7, 21, 88, 67, 8};
|
||||
|
||||
WirePacket packet = new WirePacket(id, array);
|
||||
|
||||
|
||||
+26
-26
@@ -1,42 +1,42 @@
|
||||
package com.comphenix.protocol.injector.server;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class TemporaryPlayerFactoryTest {
|
||||
|
||||
private static final TemporaryPlayerFactory temporaryPlayerFactory = new TemporaryPlayerFactory();
|
||||
private static final TemporaryPlayerFactory temporaryPlayerFactory = new TemporaryPlayerFactory();
|
||||
|
||||
@Mock
|
||||
Server server;
|
||||
@Mock
|
||||
SocketInjector socketInjector;
|
||||
@Mock
|
||||
Server server;
|
||||
@Mock
|
||||
SocketInjector socketInjector;
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
@BeforeEach
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnavailableSocketInjector()
|
||||
{
|
||||
Player player = temporaryPlayerFactory.createTemporaryPlayer(server);
|
||||
assertThrows(IllegalStateException.class, player::getPlayer);
|
||||
}
|
||||
@Test
|
||||
public void testUnavailableSocketInjector() {
|
||||
Player player = temporaryPlayerFactory.createTemporaryPlayer(this.server);
|
||||
assertThrows(IllegalStateException.class, player::getPlayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTemporaryPlayer() {
|
||||
@Test
|
||||
public void createTemporaryPlayer() {
|
||||
|
||||
Player player = temporaryPlayerFactory.createTemporaryPlayer(server, socketInjector);
|
||||
assertEquals(server, player.getServer());
|
||||
Player player = temporaryPlayerFactory.createTemporaryPlayer(this.server, this.socketInjector);
|
||||
assertEquals(this.server, player.getServer());
|
||||
|
||||
// May seem dumb, but this makes sure that the .equals method is still instact.
|
||||
assertEquals(player, player);
|
||||
}
|
||||
// May seem dumb, but this makes sure that the .equals method is still instact.
|
||||
assertEquals(player, player);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,21 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AccessorsTest {
|
||||
// --- Some classes we can use for testing ---
|
||||
private static class Entity {
|
||||
private int id;
|
||||
|
||||
public Entity(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void setId(int value) {
|
||||
this.id = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Player extends Entity {
|
||||
private String name;
|
||||
|
||||
public Player(int id, String name) {
|
||||
super(id);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
// --- Test classes ---
|
||||
|
||||
@Test
|
||||
public void testField() {
|
||||
Player player = new Player(123, "ABC");
|
||||
|
||||
|
||||
Accessors.getFieldAccessor(player.getClass(), "id", true).set(player, 0);
|
||||
Accessors.getFieldAccessor(player.getClass(), "name", true).set(player, "MODIFIED");
|
||||
assertEquals(0, player.getId());
|
||||
assertEquals("MODIFIED", player.getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMethod() {
|
||||
Player player = new Player(123, "ABC");
|
||||
@@ -54,4 +23,37 @@ public class AccessorsTest {
|
||||
Accessors.getMethodAccessor(player.getClass(), "setId", int.class).invoke(player, 0);
|
||||
assertEquals(0, player.getId());
|
||||
}
|
||||
|
||||
// --- Some classes we can use for testing ---
|
||||
private static class Entity {
|
||||
|
||||
private int id;
|
||||
|
||||
public Entity(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void setId(int value) {
|
||||
this.id = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Player extends Entity {
|
||||
|
||||
private final String name;
|
||||
|
||||
public Player(int id, String name) {
|
||||
super(id);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,33 @@
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.server.v1_16_R3.ItemStack;
|
||||
import net.minecraft.server.v1_16_R3.NonNullList;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AggregateClonerTest {
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializePackage();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testArrays() {
|
||||
public void testArrays() {
|
||||
List<Integer> input = Arrays.asList(1, 2, 3);
|
||||
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Test
|
||||
// Usages of NonNullList were removed in 1.17.1
|
||||
public void testNonNullList() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||
|
||||
@@ -42,6 +40,6 @@ public class AggregateClonerTest {
|
||||
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
|
||||
|
||||
assertEquals(list.size(), list1.size());
|
||||
assertArrayEquals(list.toArray(), list1.toArray());
|
||||
Assertions.assertArrayEquals(list.toArray(), list1.toArray());
|
||||
}
|
||||
}
|
||||
@@ -3,46 +3,47 @@
|
||||
*/
|
||||
package com.comphenix.protocol.updater;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public class UpdaterTest {
|
||||
|
||||
private static final int BUKKIT_DEV_ID = 45564;
|
||||
private static Plugin plugin;
|
||||
|
||||
// @BeforeClass
|
||||
@BeforeAll
|
||||
public static void preparePlugin() {
|
||||
Server server = mock(Server.class);
|
||||
when(server.getUpdateFolder()).thenReturn(null);
|
||||
|
||||
plugin = mock(Plugin.class);
|
||||
String version = System.getProperty("projectVersion");
|
||||
if (version == null) version = "4.4.0";
|
||||
if (version == null) {
|
||||
version = "4.4.0";
|
||||
}
|
||||
when(plugin.getDescription()).thenReturn(new PluginDescriptionFile("ProtocolLib", version, null));
|
||||
when(plugin.getLogger()).thenReturn(Logger.getLogger("ProtocolLib"));
|
||||
when(plugin.getDataFolder()).thenReturn(null);
|
||||
when(plugin.getServer()).thenReturn(server);
|
||||
}
|
||||
|
||||
// @Test
|
||||
|
||||
@Test
|
||||
public void testUpdaterType() {
|
||||
assertEquals(Updater.create(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true).getClass(), SpigotUpdater.class);
|
||||
assertEquals(Updater.create(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true).getClass(),
|
||||
SpigotUpdater.class);
|
||||
}
|
||||
|
||||
// @Test
|
||||
@@ -54,23 +55,10 @@ public class UpdaterTest {
|
||||
try {
|
||||
remote = updater.getSpigotVersion();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail("Failed to check for updates");
|
||||
fail("Failed to check for updates", ex);
|
||||
}
|
||||
|
||||
System.out.println("Determined remote Spigot version: " + remote);
|
||||
System.out.println("Update available: " + updater.versionCheck(remote));
|
||||
}
|
||||
|
||||
// @Test
|
||||
public void testBukkitUpdater() {
|
||||
BukkitUpdater updater = new BukkitUpdater(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true);
|
||||
if (! updater.read()) {
|
||||
fail("Failed to check for updates");
|
||||
}
|
||||
|
||||
String remote = updater.getLatestName();
|
||||
System.out.println("Determined remote Bukkit Dev version: " + remote);
|
||||
System.out.println("Update available: " + updater.versionCheck(remote));
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MinecraftMethodsTest {
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void initializeReflection() {
|
||||
BukkitInitialization.initializePackage();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -30,10 +28,11 @@ public class MinecraftMethodsTest {
|
||||
|
||||
@Test
|
||||
public void initializePacket() throws NoSuchFieldException, IllegalAccessException {
|
||||
setNull("packetReadByteBuf");
|
||||
setNull("packetWriteByteBuf");
|
||||
this.setNull("packetReadByteBuf");
|
||||
this.setNull("packetWriteByteBuf");
|
||||
|
||||
assertNotNull(MinecraftMethods.getPacketWriteByteBufMethod());
|
||||
assertNotNull(MinecraftMethods.getPacketReadByteBufMethod());
|
||||
// TODO it's now a constructor
|
||||
// assertNotNull(MinecraftMethods.getPacketReadByteBufMethod());
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,42 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import net.minecraft.server.v1_16_R3.ChatComponentText;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.DataWatcher;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
|
||||
import net.minecraft.server.v1_16_R3.IChatBaseComponent.ChatSerializer;
|
||||
import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.server.v1_16_R3.PlayerConnection;
|
||||
import net.minecraft.server.v1_16_R3.ServerPing;
|
||||
import net.minecraft.server.v1_16_R3.ServerPing.ServerData;
|
||||
import net.minecraft.server.v1_16_R3.ServerPing.ServerPingPlayerSample;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.nbt.NBTCompressedStreamTools;
|
||||
import net.minecraft.network.chat.ChatComponentText;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.status.ServerPing;
|
||||
import net.minecraft.network.syncher.DataWatcher;
|
||||
import net.minecraft.server.network.PlayerConnection;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
|
||||
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
|
||||
public class MinecraftReflectionTest {
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeItemMeta();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
// Mocking objects
|
||||
private interface FakeEntity {
|
||||
Entity getBukkitEntity();
|
||||
}
|
||||
|
||||
private interface FakeBlock {
|
||||
Block getBukkitEntity();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@AfterAll
|
||||
public static void undoMocking() {
|
||||
// NOP
|
||||
MinecraftReflection.minecraftPackage = null;
|
||||
@@ -69,9 +54,9 @@ public class MinecraftReflectionTest {
|
||||
verify(block, times(1)).getBukkitEntity();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test
|
||||
public void testIllegalClass() {
|
||||
MinecraftReflection.getBukkitEntity("Hello");
|
||||
assertThrows(IllegalArgumentException.class, () -> MinecraftReflection.getBukkitEntity("Hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,7 +66,8 @@ public class MinecraftReflectionTest {
|
||||
|
||||
@Test
|
||||
public void testAttributeSnapshot() {
|
||||
assertEquals(AttributeSnapshot.class, MinecraftReflection.getAttributeSnapshotClass());
|
||||
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class,
|
||||
MinecraftReflection.getAttributeSnapshotClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -96,7 +82,7 @@ public class MinecraftReflectionTest {
|
||||
|
||||
@Test
|
||||
public void testChatSerializer() {
|
||||
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
|
||||
assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,12 +107,12 @@ public class MinecraftReflectionTest {
|
||||
|
||||
@Test
|
||||
public void testServerPingPlayerSample() {
|
||||
assertEquals(ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
|
||||
assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPingServerData() {
|
||||
assertEquals(ServerData.class, MinecraftReflection.getServerPingServerDataClass());
|
||||
assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -153,4 +139,21 @@ public class MinecraftReflectionTest {
|
||||
public void testGameProfile() {
|
||||
assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumEntityUseAction() {
|
||||
// this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval
|
||||
MinecraftReflection.getEnumEntityUseActionClass();
|
||||
}
|
||||
|
||||
// Mocking objects
|
||||
private interface FakeEntity {
|
||||
|
||||
Entity getBukkitEntity();
|
||||
}
|
||||
|
||||
private interface FakeBlock {
|
||||
|
||||
Block getBukkitEntity();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,38 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SnapshotVersionTest {
|
||||
|
||||
@Test
|
||||
public void testDates() {
|
||||
SnapshotVersion a = new SnapshotVersion("12w50b");
|
||||
SnapshotVersion b = new SnapshotVersion("13w05a");
|
||||
|
||||
expect(a.getSnapshotDate(), 12, 50);
|
||||
expect(b.getSnapshotDate(), 13, 5);
|
||||
|
||||
|
||||
this.expect(a.getSnapshotDate(), 12, 50);
|
||||
this.expect(b.getSnapshotDate(), 13, 5);
|
||||
|
||||
// Test equality
|
||||
assertEquals(a, new SnapshotVersion("12w50b"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
|
||||
@Test
|
||||
public void testDateParsingProblem() {
|
||||
// This date is not valid
|
||||
new SnapshotVersion("12w80a");
|
||||
assertThrows(IllegalArgumentException.class, () -> new SnapshotVersion("12w80a"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
|
||||
@Test
|
||||
public void testMissingWeekVersion() {
|
||||
new SnapshotVersion("13w05");
|
||||
assertThrows(IllegalArgumentException.class, () -> new SnapshotVersion("13w05"));
|
||||
}
|
||||
|
||||
|
||||
private void expect(Date date, int year, int week) {
|
||||
Calendar calendar = Calendar.getInstance(Locale.US);
|
||||
calendar.setTime(date);
|
||||
|
||||
@@ -1,38 +1,30 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
|
||||
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
|
||||
//@PrepareForTest(CraftItemFactory.class)
|
||||
public class StreamSerializerTest {
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeItemMeta();
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public void testMinecraftReflection() {
|
||||
assertEquals(IntHashMap.class, MinecraftReflection.getIntHashMapClass());
|
||||
}*/
|
||||
|
||||
@Test
|
||||
public void testStrings() throws IOException {
|
||||
StreamSerializer serializer = new StreamSerializer();
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static void assertItemCollectionsEqual(List<ItemStack> first, List<ItemStack> second) {
|
||||
@@ -42,4 +45,8 @@ public class TestUtils {
|
||||
return first.getType().equals(second.getType());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setFinalField(Object obj, Field field, Object newValue) {
|
||||
Accessors.getFieldAccessor(field, true).set(obj, newValue);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user