Compare commits

..
Author SHA1 Message Date
Dan Mulloy 5a7bd20806 Add wrapper for map icons, start lazy lists 2021-05-29 16:18:48 -04:00
114 changed files with 3833 additions and 5586 deletions

No files matched your search

-25
View File
@@ -1,25 +0,0 @@
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
+1 -2
View File
@@ -179,5 +179,4 @@ logs/
.gradle/
build/
logs/
.java-version
logs/
+11
View File
@@ -0,0 +1,11 @@
language: java
jdk:
- openjdk8
script: mvn clean test
install: true
notifications:
email:
recipients:
- "dmulloy2@live.com"
on_success: change
on_failure: always
+3 -3
View File
@@ -1,4 +1,4 @@
# ProtocolLib
# ProtocolLib [![Travis Status](https://travis-ci.org/dmulloy2/ProtocolLib.svg?branch=master)](https://travis-ci.org/dmulloy2/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.7.0</version>
<version>4.6.0</version>
</dependency>
</dependencies>
````
@@ -66,7 +66,7 @@ repositories {
}
dependencies {
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.7.0";
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.6.0";
}
```
-5
View File
@@ -1,5 +0,0 @@
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
+43 -80
View File
@@ -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.8.0</version>
<version>4.6.1-SNAPSHOT</version>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>https://github.com/dmulloy2/ProtocolLib</url>
@@ -16,10 +16,8 @@
<project.build.number></project.build.number>
<project.fullVersion>${project.version}</project.fullVersion>
<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>
<powermock.version>2.0.9</powermock.version>
<spigot.version>1.16.5-R0.1-SNAPSHOT</spigot.version>
</properties>
<build>
@@ -73,7 +71,7 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
@@ -83,7 +81,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<version>3.2.0</version>
<configuration>
<archive>
<manifestEntries>
@@ -101,14 +99,6 @@
<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>
@@ -118,26 +108,25 @@
<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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.2</version>
<version>3.2.0</version>
<configuration>
<failOnError>false</failOnError>
<encoding>ISO-8859-1</encoding>
<doctitle>ProtocolLib JavaDocs</doctitle>
<windowtitle>ProtocolLib JavaDocs</windowtitle>
<bottom>Copyright &#169; {inceptionYear}&#x2013;{currentYear}
Comphenix and dmulloy2. Licensed under the GNU GPL v2.
</bottom>
<additionalOptions>
<additionalOption>-Xdoclint:none</additionalOption>
</additionalOptions>
Comphenix and dmulloy2. Licensed under the GNU GPL v2.</bottom>
<source>8</source>
<doclint>none</doclint>
<quiet>true</quiet>
</configuration>
<!--
<executions>
<execution>
<phase>install</phase>
@@ -146,6 +135,7 @@
</goals>
</execution>
</executions>
-->
</plugin>
</plugins>
</build>
@@ -181,7 +171,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
@@ -195,7 +185,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.2</version>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
@@ -237,7 +227,7 @@
<licenses>
<license>
<name>GNU GENERAL PUBLIC LICENSE - Version 2, June 1991</name>
<url>https://www.gnu.org/licenses/gpl-2.0.txt</url>
<url>http://www.gnu.org/licenses/gpl-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
@@ -246,7 +236,7 @@
<developer>
<id>dmulloy2</id>
<name>Dan Mulloy</name>
<url>https://dmulloy2.net/</url>
<url>http://dmulloy2.net/</url>
<roles>
<role>developer</role>
<role>maintainer</role>
@@ -256,7 +246,7 @@
<id>aadnk</id>
<name>Kristian S. Stangeland</name>
<email>kr_stang@hotmail.com</email>
<url>https://comphenix.net/</url>
<url>http://comphenix.net/</url>
<roles>
<role>former author</role>
</roles>
@@ -287,88 +277,61 @@
</repositories>
<dependencies>
<!-- core minecraft dependencies -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>*</artifactId>
</exclusion>
</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>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId>
<version>4.9.3</version>
<version>4.5.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.12.8</version>
<version>1.11.0</version>
</dependency>
<!-- Testing dependencies -->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-common -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-transport -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${netty.version}</version>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -19,7 +19,6 @@ 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;
@@ -32,16 +31,13 @@ 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;
/**
@@ -51,8 +47,6 @@ 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<>();
@@ -205,13 +199,7 @@ public class PacketLogging implements CommandExecutor, PacketListener {
private static String hexDump(byte[] bytes) throws IOException {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
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);
HexDump.dump(bytes, 0, output, 0);
return new String(output.toByteArray(), Charsets.UTF_8);
}
}
@@ -11,7 +11,6 @@ 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;
@@ -108,105 +107,93 @@ 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 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");
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");
// ---- Removed in 1.9
@@ -269,7 +256,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @deprecated Removed in 1.14
*/
@Deprecated
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 251, "Bed", "SPacketUseBed");
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x33, "Bed", "SPacketUseBed");
/**
* @deprecated Renamed to {@link #BED}
@@ -281,37 +268,7 @@ 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, 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");
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x02, "SpawnEntityWeather", "SPacketSpawnGlobalEntity");
private final static Server INSTANCE = new Server();
@@ -340,29 +297,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 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 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 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");
@@ -382,18 +339,6 @@ 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
@@ -545,23 +490,15 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @author Kristian
*/
public enum Protocol {
HANDSHAKING("Handshaking", "handshake"),
PLAY("Play", "game"),
STATUS("Status", "status"),
LOGIN("Login", "login"),
HANDSHAKING,
PLAY,
STATUS,
LOGIN,
/**
* Only for packets removed in Minecraft 1.7.2
*/
LEGACY("", "");
private String packetName;
private String mojangName;
Protocol(String packetName, String mojangName) {
this.packetName = packetName;
this.mojangName = mojangName;
}
LEGACY;
/**
* Retrieve the correct protocol enum from a given vanilla enum instance.
@@ -583,11 +520,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
}
public String getPacketName() {
return packetName;
}
public String getMojangName() {
return mojangName;
return WordUtils.capitalize(name().toLowerCase(Locale.ENGLISH));
}
public String getMcpPacketName() {
@@ -604,22 +537,12 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
/**
* Indicates that packets of this type will be sent by connected clients.
*/
CLIENT("Serverbound", "In", "client"),
CLIENT,
/**
* Indicate that packets of this type will be sent by the current 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;
}
SERVER;
/**
* Retrieve the equivialent connection side.
@@ -630,15 +553,11 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
}
public String getPacketName() {
return packetName;
return this == CLIENT ? "In" : "Out";
}
public String getMcpPacketName() {
return mcpName;
}
public String getMojangName() {
return mojangName;
return name().toLowerCase(Locale.ENGLISH);
}
}
@@ -655,13 +574,13 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
/**
* Protocol version of all the current IDs.
*/
private static final MinecraftVersion PROTOCOL_VERSION = Constants.CURRENT_VERSION;
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.NETHER_UPDATE;
private final Protocol protocol;
private final Sender sender;
private final int currentId;
private final MinecraftVersion version;
private final List<String> classNames;
private final String[] classNames;
String[] names;
private String name;
@@ -791,17 +710,7 @@ 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;
@@ -901,8 +810,8 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
// Check any aliases
for (PacketType check : map.values()) {
List<String> aliases = check.getClassNames();
if (aliases.size() > 1) {
String[] aliases = check.getClassNames();
if (aliases.length > 1) {
for (String alias : aliases) {
if (alias.equals(clazz)) {
// We have a match!
@@ -943,9 +852,7 @@ 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;
}
@@ -1024,13 +931,12 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
this.currentId = currentId;
this.version = version;
this.classNames = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
this.classNames = new String[names.length];
for (int i = 0; i < classNames.length; i++) {
if (isMcpPacketName(names[i])) { // Minecraft MCP packets
classNames.add(formatMcpClassName(protocol, sender, names[i]));
classNames[i] = formatMcpClassName(protocol, sender, names[i]);
} else {
classNames.add(formatClassName(protocol, sender, names[i]));
classNames.add(formatMojangClassName(protocol, sender, names[i]));
classNames[i] = formatClassName(protocol, sender, names[i]);
}
}
@@ -1091,7 +997,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
return currentId;
}
public List<String> getClassNames() {
public String[] getClassNames() {
return classNames;
}
@@ -1100,7 +1006,11 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @return The packet class, or NULL if not found.
*/
public Class<?> getPacketClass() {
return PacketRegistry.tryGetPacketClass(this).orElse(null);
try {
return PacketRegistry.getPacketClassFromType(this);
} catch (Exception e) {
return null;
}
}
// Only used by Enum processor
@@ -1202,7 +1112,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
Class<?> clazz = getPacketClass();
if (clazz == null)
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + classNames + " (unregistered)]";
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + Arrays.toString(classNames) + " (unregistered)]";
else
return name() + "[class=" + clazz.getSimpleName() + ", id=" + currentId + "]";
}
@@ -110,6 +110,22 @@ 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().get(0), type);
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames()[0], type);
}
nameLookup.put(type.name(), type);
}
@@ -38,12 +38,12 @@ public class ProtocolLibrary {
/**
* The maximum version ProtocolLib has been tested with.
*/
public static final String MAXIMUM_MINECRAFT_VERSION = "1.18.2";
public static final String MAXIMUM_MINECRAFT_VERSION = "1.16.5";
/**
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.18.2) was released.
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.16.5) was released.
*/
public static final String MINECRAFT_LAST_RELEASE_DATE = "2022-02-28";
public static final String MINECRAFT_LAST_RELEASE_DATE = "2021-01-15";
/**
* Plugins that are currently incompatible with ProtocolLib.
@@ -20,7 +20,6 @@ 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;
/**
@@ -83,10 +82,4 @@ 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 = type.getPacketClass();
Class<?> packetClass = getPacketClass(type);
types.add(Preconditions.checkNotNull(type, "type cannot be NULL."));
if (packetClass != null) {
classes.add(type.getPacketClass());
classes.add(getPacketClass(type));
}
}
@@ -55,11 +55,11 @@ public class PacketTypeSet {
* @param type - the type to remove.
*/
public synchronized void removeType(PacketType type) {
Class<?> packetClass = type.getPacketClass();
Class<?> packetClass = getPacketClass(type);
types.remove(Preconditions.checkNotNull(type, "type cannot be NULL."));
if (packetClass != null) {
classes.remove(packetClass);
classes.remove(getPacketClass(type));
}
}
@@ -72,7 +72,16 @@ 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
@@ -1,45 +0,0 @@
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,7 +45,6 @@ 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;
@@ -177,12 +176,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
public UUID getUniqueId() {
return uuid;
}
@Override
public PlayerProfile getPlayerProfile() {
return null;
}
@Override
public String getName() {
return name;
@@ -17,7 +17,6 @@
package com.comphenix.protocol.injector;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -28,7 +27,6 @@ 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;
@@ -68,10 +66,7 @@ class EntityUtilities {
Collection<?> trackedPlayers = getTrackedPlayers(entity);
List<Object> nmsPlayers = unwrapBukkit(observers);
List<Object> removingEntries = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove() ?
getPlayerConnections(nmsPlayers) : nmsPlayers;
trackedPlayers.removeAll(removingEntries);
trackedPlayers.removeAll(nmsPlayers);
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
@@ -107,9 +102,7 @@ class EntityUtilities {
// Wrap every player - we also ensure that the underlying tracker list is immutable
for (Object tracker : trackedPlayers) {
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove() && MinecraftReflection.isServerHandler(tracker)) {
result.add(MinecraftReflection.getBukkitPlayerFromConnection(tracker));
} else if (MinecraftReflection.isMinecraftPlayer(tracker)) {
if (MinecraftReflection.isMinecraftPlayer(tracker)) {
result.add((Player) MinecraftReflection.getBukkitEntity(tracker));
}
}
@@ -146,7 +139,7 @@ class EntityUtilities {
@SuppressWarnings("unchecked")
private Object getNewEntityTracker(Object worldServer, int entityId) {
if (getChunkProvider == null) {
Class<?> chunkProviderClass = MinecraftReflection.getChunkProviderServer();
Class<?> chunkProviderClass = MinecraftReflection.getMinecraftClass("ChunkProviderServer");
getChunkProvider = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(worldServer.getClass(), false).getMethod(
FuzzyMethodContract.newBuilder().parameterCount(0).returnTypeExact(chunkProviderClass).build()));
@@ -155,7 +148,7 @@ class EntityUtilities {
Object chunkProvider = getChunkProvider.invoke(worldServer);
if (chunkMapField == null) {
Class<?> chunkMapClass = MinecraftReflection.getPlayerChunkMap();
Class<?> chunkMapClass = MinecraftReflection.getMinecraftClass("PlayerChunkMap");
chunkMapField = Accessors.getFieldAccessor(
FuzzyReflection.fromClass(chunkProvider.getClass(), false).getField(
FuzzyFieldContract.newBuilder().typeExact(chunkMapClass).build()));
@@ -164,21 +157,9 @@ class EntityUtilities {
Object playerChunkMap = chunkMapField.get(chunkProvider);
if (trackedEntitiesField == null) {
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(
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);
@@ -248,17 +229,14 @@ class EntityUtilities {
Object tracker = null;
if (trackerEntry != null) {
// plugins like citizens will use their own tracker class, so cache the result
// plugins like citizens will use their own tracker
FieldAccessor trackerField = trackerFields.computeIfAbsent(trackerEntry.getClass(), x -> {
// get the first entity field
try {
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()));
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()));
}
});
@@ -272,12 +250,6 @@ 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,6 +39,14 @@ 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,7 +20,6 @@ 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;
@@ -147,11 +146,13 @@ public class PacketConstructor {
types[i] = Object.class;
}
}
Class<?> packetClass = PacketRegistry.getPacketClassFromType(type);
Class<?> packetType = PacketRegistry.getPacketClassFromType(type, true);
if (packetType == null)
throw new IllegalArgumentException("Could not find a packet by the type " + type);
// Find the correct constructor
for (Constructor<?> constructor : packetClass.getConstructors()) {
for (Constructor<?> constructor : packetType.getConstructors()) {
Class<?>[] params = constructor.getParameterTypes();
if (isCompatible(types, params)) {
@@ -979,6 +979,12 @@ 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,29 +19,17 @@ 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.
@@ -49,42 +37,9 @@ import net.bytebuddy.matcher.ElementMatchers;
*/
public class StructureCache {
// Structure modifiers
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 ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
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;
}
private static Set<PacketType> compiling = new HashSet<>();
/**
* Creates an empty Minecraft packet of the given type.
@@ -92,7 +47,20 @@ public class StructureCache {
* @return Created packet.
*/
public static Object newPacket(PacketType type) {
return newPacket(PacketRegistry.getPacketClassFromType(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);
}
/**
@@ -123,9 +91,7 @@ public class StructureCache {
*/
public static StructureModifier<Object> getStructure(Class<?> packetType, boolean compile) {
// Get the ID from the class
PacketType type = PacketRegistry.getPacketType(packetType);
Preconditions.checkNotNull(type, "No packet type associated with " + packetType);
return getStructure(type, compile);
return getStructure(PacketRegistry.getPacketType(packetType), compile);
}
/**
@@ -135,14 +101,13 @@ 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<>(
PacketRegistry.getPacketClassFromType(type), MinecraftReflection.getPacketClass(), true);
final StructureModifier<Object> value = new StructureModifier<Object>(
PacketRegistry.getPacketClassFromType(type, true), MinecraftReflection.getPacketClass(), true);
result = structureModifiers.putIfAbsent(type, value);
@@ -159,42 +124,16 @@ public class StructureCache {
final BackgroundCompiler compiler = BackgroundCompiler.getInstance();
if (!compiling.contains(type) && compiler != null) {
compiler.scheduleCompilation(result,
compiledModifier -> structureModifiers.put(type, compiledModifier));
compiler.scheduleCompilation(result, new CompileListener<Object>() {
@Override
public void onCompiled(StructureModifier<Object> 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,7 +30,6 @@ 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;
@@ -45,6 +44,7 @@ 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,7 +57,6 @@ 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.*;
@@ -86,7 +85,6 @@ 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;
@@ -275,7 +273,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(packet);
ChannelInjector.this.finalWrite();
}
@Override
@@ -544,7 +542,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
/**
* Invoked when a packet has been written to the channel
*/
private void finalWrite(Object packet) {
private void finalWrite() {
PacketEvent event = finalEvent;
if (event != null) {
@@ -553,10 +551,6 @@ 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);
}
}
@@ -669,21 +663,15 @@ 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) PROTOCOL_VERSION_ACCESSOR.get(packet);
int protocol = (int) fuzzy.invokeMethod(packet, "getProtocol", int.class);
originalChannel.attr(PROTOCOL_KEY).set(protocol);
} catch (Throwable ex) {
// Oh well
@@ -963,7 +951,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
@Override
public Socket getSocket() {
return SocketAdapter.adapt(injector.originalChannel);
return SocketAdapter.adapt((SocketChannel) injector.originalChannel);
}
@Override
@@ -1001,11 +989,6 @@ 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 = Integer.MAX_VALUE;
private static final int CAPACITY = Short.MAX_VALUE;
private NettyByteBufAdapter(DataInputStream input, DataOutputStream output) {
// Just pick a figure
@@ -0,0 +1,222 @@
/**
* 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();
}
*/
}
}
@@ -0,0 +1,125 @@
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,11 +43,8 @@ public class SocketAdapter extends Socket {
this.ch = ch;
}
public static SocketAdapter adapt(Channel ch) {
if (!(ch instanceof SocketChannel)) {
return null;
}
return new SocketAdapter((SocketChannel) ch);
public static SocketAdapter adapt(SocketChannel ch) {
return new SocketAdapter(ch);
}
@Override
@@ -17,275 +17,42 @@
package com.comphenix.protocol.injector.packet;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
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.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.Lists;
import com.google.common.base.Function;
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) {
INITIALIZED = true;
if (MinecraftVersion.BEE_UPDATE.atOrAbove()) {
REGISTER = createNewRegister();
} else {
REGISTER = createOldRegister();
if (INITIALIZED) {
if (NETTY == null) {
throw new IllegalStateException("Failed to initialize packet registry.");
}
return;
}
NETTY = new NettyProtocolRegistry();
INITIALIZED = true;
}
/**
@@ -295,7 +62,35 @@ public class PacketRegistry {
*/
public static boolean isSupported(PacketType type) {
initialize();
return tryGetPacketClass(type).isPresent();
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;
}
/**
@@ -304,9 +99,9 @@ public class PacketRegistry {
*/
public static Set<PacketType> getServerPacketTypes() {
initialize();
synchronize();
NETTY.synchronize();
return Collections.unmodifiableSet(REGISTER.serverPackets);
return NETTY.getServerPackets();
}
/**
@@ -315,68 +110,88 @@ public class PacketRegistry {
*/
public static Set<PacketType> getClientPacketTypes() {
initialize();
synchronize();
NETTY.synchronize();
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;
return NETTY.getClientPackets();
}
/**
* 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
*/
@Deprecated
public static Class<?> getPacketClassFromType(PacketType type, boolean forceVanilla) {
return getPacketClassFromType(type);
}
public static Optional<Class<?>> tryGetPacketClass(PacketType type) {
public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) {
initialize();
// Try the lookup first (may be null, so check contains)
Optional<Class<?>> res = REGISTER.typeToClass.get(type);
if (res != null) {
return res;
// Try the lookup first
Class<?> clazz = NETTY.getPacketTypeLookup().get(type);
if (clazz != null) {
return clazz;
}
// Then try looking up the class names
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);
for (String name : type.getClassNames()) {
try {
clazz = MinecraftReflection.getMinecraftClass(name);
break;
} catch (Exception ignored) { }
}
// cache it for next time
associate(type, clazz);
return Optional.ofNullable(clazz);
// TODO Cache the result?
return clazz;
}
/**
* 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
* 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.
*/
public static Class<?> getPacketClassFromType(PacketType type) {
return tryGetPacketClass(type)
.orElseThrow(() -> new IllegalArgumentException("Could not find packet for type " + type.name()));
@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();
}
/**
@@ -385,8 +200,7 @@ public class PacketRegistry {
* @return The packet type, or NULL if not found.
*/
public static PacketType getPacketType(Class<?> packet) {
initialize();
return REGISTER.classToType.get(packet);
return getPacketType(packet, null);
}
/**
@@ -394,10 +208,9 @@ 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) {
return getPacketType(packet);
initialize();
return NETTY.getPacketClassLookup().get(packet);
}
}
@@ -80,9 +80,4 @@ public class BukkitSocketInjector implements SocketInjector {
public void setUpdatedPlayer(Player updatedPlayer) {
this.player = updatedPlayer;
}
@Override
public boolean isConnected() {
return player.isOnline();
}
}
@@ -18,24 +18,22 @@ 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.
*/
@Deprecated
Socket getSocket() throws IllegalAccessException;
public abstract 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.
*/
SocketAddress getAddress() throws IllegalAccessException;
public abstract SocketAddress getAddress() throws IllegalAccessException;
/**
* Attempt to disconnect the current client.
* @param message - the message to display.
* @throws InvocationTargetException If disconnection failed.
*/
void disconnect(String message) throws InvocationTargetException;
public abstract void disconnect(String message) throws InvocationTargetException;
/**
* Send a packet to the client.
@@ -44,36 +42,30 @@ 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.
*/
void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
throws InvocationTargetException;
/**
* Retrieve the hooked player.
* @return The hooked player.
*/
Player getPlayer();
public abstract 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.
*/
Player getUpdatedPlayer();
public abstract Player getUpdatedPlayer();
/**
* Invoked when a delegated socket injector transfers the state of one injector to the next.
* @param delegate - the new injector.
*/
void transferState(SocketInjector delegate);
public abstract void transferState(SocketInjector delegate);
/**
* Set the real Bukkit player that we will use.
* @param updatedPlayer - the real Bukkit player.
*/
void setUpdatedPlayer(Player updatedPlayer);
/**
* Determines if the player is currently connected.
* @return true if the player is connected.
*/
boolean isConnected();
public abstract void setUpdatedPlayer(Player updatedPlayer);
}
@@ -157,9 +157,9 @@ public class TemporaryPlayerFactory {
// Methods that are supported in the fallback instance
if (methodName.equals("isOnline"))
return injector.isConnected();
return injector.getSocket() != null && injector.getSocket().isConnected();
else if (methodName.equals("getName"))
return "UNKNOWN[" + injector.getAddress() + "]";
return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]";
// Ignore all other methods
throw new UnsupportedOperationException(
@@ -2,6 +2,7 @@ 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,6 +24,7 @@ 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;
@@ -86,7 +87,13 @@ public class Statistics {
for (PacketListener listener : ProtocolLibrary.getProtocolManager().getPacketListeners()) {
String name = PacketAdapter.getPluginName(listener);
users.put(name, 1);
// Increment occurence
if (!users.containsKey(name)) {
users.put(name, 1);
} else {
users.put(name, users.get(name) + 1);
}
}
return users;
@@ -17,7 +17,6 @@ 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;
@@ -395,12 +394,20 @@ 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 {
writeStaticField(clazz, fieldName, value, forceAccess);
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);
}
/**
@@ -435,8 +442,12 @@ public class FieldUtils {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
Accessors.getFieldAccessor(field, forceAccess).set(target, value);
if (forceAccess && !field.isAccessible()) {
field.setAccessible(true);
} else {
MemberUtils.setAccessibleWorkaround(field);
}
field.set(target, value);
}
/**
@@ -117,11 +117,12 @@ 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,9 +308,7 @@ 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() + ")");
@@ -327,9 +325,7 @@ 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,7 +289,6 @@ 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,28 +1,14 @@
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 {
@@ -33,25 +19,18 @@ final class DefaultFieldAccessor implements FieldAccessor {
throw new IllegalStateException("Cannot use reflection.", e);
}
}
@Override
public void set(Object instance, Object value) {
try {
if (setter == null) {
field.set(instance, value);
} else {
setter.invoke(instance, value);
}
} catch (IllegalArgumentException | ClassCastException e) {
field.set(instance, value);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Cannot set field " + field + " to value " + value, e);
} catch (IllegalAccessException | WrongMethodTypeException e) {
} catch (IllegalAccessException 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;
@@ -64,17 +43,16 @@ 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 + "]";
@@ -1,48 +0,0 @@
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
@@ -62,29 +62,29 @@ public class ImmutableDetector implements Cloner {
add(MinecraftReflection::getDataWatcherSerializerClass);
add(MinecraftReflection::getBlockClass);
add(MinecraftReflection::getItemClass);
add("sounds.SoundEffect", "SoundEffect");
add("SoundEffect");
if (MinecraftVersion.AQUATIC_UPDATE.atOrAbove()) {
add(MinecraftReflection::getFluidTypeClass);
add(MinecraftReflection::getParticleTypeClass);
add("core.particles.Particle", "Particle");
add("Particle");
}
if (MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) {
add(MinecraftReflection::getEntityTypes);
add("world.entity.npc.VillagerType", "VillagerType");
add("world.entity.npc.VillagerProfession", "VillagerProfession");
add("EntityTypes");
add("VillagerType");
add("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("core.IRegistry", "IRegistry");
add("IRegistry");
}
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
add(MinecraftReflection::getResourceKey);
add("ResourceKey");
}
}
@@ -97,11 +97,13 @@ public class ImmutableDetector implements Cloner {
} catch (RuntimeException ignored) { }
}
private static void add(String className, String... aliases) {
Class<?> clazz = MinecraftReflection.getNullableNMS(className, aliases);
if (clazz != null) {
immutableNMS.add(clazz);
}
private static void add(String className) {
try {
Class<?> clazz = MinecraftReflection.getMinecraftClass(className);
if (clazz != null) {
immutableNMS.add(clazz);
}
} catch (RuntimeException ignored) { }
}
@Override
@@ -58,6 +58,8 @@ 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
@@ -17,31 +17,32 @@
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,
MinecraftGenerator.INSTANCE
);
PrimitiveGenerator.INSTANCE, CollectionGenerator.INSTANCE, UUID_GENERATOR);
/**
* The maximum height of the heirarchy of creates types. Used to prevent cycles.
@@ -187,7 +188,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) && !contains(types, MinecraftReflection.getPacketDataSerializerClass())) {
if (!contains(types, type)) {
if (nonNull) {
// Make sure all of these types are non-null
if (isAnyNull(types, providers, recursionLevel)) {
@@ -272,6 +273,7 @@ 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) {
@@ -1,77 +0,0 @@
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_18_R2";
public static final String NMS = "net.minecraft";
public static final String PACKAGE_VERSION = "v1_16_R3";
public static final String NMS = "net.minecraft.server." + PACKAGE_VERSION;
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
public static final MinecraftVersion CURRENT_VERSION = MinecraftVersion.CAVES_CLIFFS_2;
public static final MinecraftVersion CURRENT_VERSION = MinecraftVersion.NETHER_UPDATE_2;
public static void init() {
MinecraftReflection.setMinecraftPackage(NMS, OBC);
@@ -15,16 +15,15 @@ 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 manager associated with a particular player.
* Retrieve the network mananger associated with a particular player.
* @param player - the player.
* @return The network manager, or NULL if no network manager has been associated yet.
* @return The network manager, or NULL if no network manager has been asssociated yet.
*/
public static Object getNetworkManager(Player player) {
Object nmsPlayer = BukkitUnwrapper.getInstance().unwrapItem(player);
@@ -51,13 +50,9 @@ public class MinecraftFields {
Preconditions.checkNotNull(player, "player cannot be null!");
return getPlayerConnection(BukkitUnwrapper.getInstance().unwrapItem(player));
}
/**
* Retrieve the PlayerConnection (or NetServerHandler) associated with a player.
* @param nmsPlayer - the NMS player.
* @return The player connection.
*/
public static Object getPlayerConnection(Object nmsPlayer) {
// Retrieve player connection from a native instance
private static Object getPlayerConnection(Object nmsPlayer) {
Preconditions.checkNotNull(nmsPlayer, "nmsPlayer cannot be null!");
if (CONNECTION_ACCESSOR == null) {
@@ -66,21 +61,4 @@ 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,15 +72,6 @@ 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,8 +27,10 @@ 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;
@@ -41,7 +43,6 @@ 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;
@@ -56,7 +57,6 @@ 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,7 +65,6 @@ 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;
@@ -223,35 +222,30 @@ public class MinecraftReflection {
Class<?> craftEntity = getCraftEntityClass();
Method getHandle = craftEntity.getMethod("getHandle");
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 + ")");
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 {
// Use the standard matcher
setDynamicPackageMatcher(MINECRAFT_OBJECT);
// 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;
@@ -377,21 +371,6 @@ 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.
@@ -601,7 +580,7 @@ public class MinecraftReflection {
*/
public static Class<?> getEntityPlayerClass() {
try {
return getMinecraftClass("server.level.EntityPlayer","EntityPlayer");
return getMinecraftClass("EntityPlayer");
} catch (RuntimeException e) {
try {
// Grab CraftPlayer's handle
@@ -658,7 +637,7 @@ public class MinecraftReflection {
*/
public static Class<?> getEntityClass() {
try {
return getMinecraftClass("server.world.Entity", "Entity");
return getMinecraftClass("Entity");
} catch (RuntimeException e) {
return fallbackMethodReturn("Entity", "entity.CraftEntity", "getHandle");
}
@@ -678,7 +657,7 @@ public class MinecraftReflection {
*/
public static Class<?> getWorldServerClass() {
try {
return getMinecraftClass("server.level.WorldServer", "WorldServer");
return getMinecraftClass("WorldServer");
} catch (RuntimeException e) {
return fallbackMethodReturn("WorldServer", "CraftWorld", "getHandle");
}
@@ -690,7 +669,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNmsWorldClass() {
try {
return getMinecraftClass("world.level.World", "World");
return getMinecraftClass("World");
} catch (RuntimeException e) {
return setMinecraftClass("World", getWorldServerClass().getSuperclass());
}
@@ -717,7 +696,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPacketClass() {
try {
return getMinecraftClass("network.protocol.Packet", "Packet");
return getMinecraftClass("Packet");
} catch (RuntimeException e) {
FuzzyClassContract paketContract = null;
@@ -773,10 +752,8 @@ public class MinecraftReflection {
* @return The Enum protocol class.
*/
public static Class<?> getEnumProtocolClass() {
return getMinecraftClass("network.EnumProtocol", "EnumProtocol");
/* try {
return getMinecraftClass("network.EnumProtocol", "EnumProtocol");
try {
return getMinecraftClass("EnumProtocol");
} catch (RuntimeException e) {
Method protocolMethod = FuzzyReflection.fromClass(getNetworkManagerClass()).getMethod(
FuzzyMethodContract.newBuilder().
@@ -785,7 +762,7 @@ public class MinecraftReflection {
build()
);
return setMinecraftClass("EnumProtocol", protocolMethod.getParameterTypes()[0]);
} */
}
}
/**
@@ -794,7 +771,7 @@ public class MinecraftReflection {
*/
public static Class<?> getIChatBaseComponentClass() {
try {
return getMinecraftClass("network.chat.IChatbaseComponent", "IChatBaseComponent");
return getMinecraftClass("IChatBaseComponent");
} catch (RuntimeException e) {
return setMinecraftClass("IChatBaseComponent",
Accessors.getMethodAccessor(getCraftChatMessage(), "fromString", String.class).
@@ -813,7 +790,7 @@ public class MinecraftReflection {
*/
public static Class<?> getChatComponentTextClass() {
try {
return getMinecraftClass("network.chat.ChatComponentText", "ChatComponentText");
return getMinecraftClass("ChatComponentText");
} catch (RuntimeException e) {
try {
Method getScoreboardDisplayName = FuzzyReflection.fromClass(getEntityClass()).
@@ -841,8 +818,7 @@ public class MinecraftReflection {
*/
public static Class<?> getChatSerializerClass() {
try {
return getMinecraftClass("network.chat.IChatBaseComponent$ChatSerializer",
"ChatSerializer", "IChatBaseComponent$ChatSerializer");
return getMinecraftClass("ChatSerializer", "IChatBaseComponent$ChatSerializer");
} catch (RuntimeException e) {
// TODO: Figure out a functional fallback
throw new IllegalStateException("Could not find ChatSerializer class.", e);
@@ -854,8 +830,11 @@ 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("network.protocol.status.ServerPing", "ServerPing");
return getMinecraftClass("ServerPing");
} catch (RuntimeException e) {
Class<?> statusServerInfo = PacketType.Status.Server.SERVER_INFO.getPacketClass();
@@ -877,9 +856,11 @@ 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("network.protocol.status.ServerPing$ServerData",
"ServerPingServerData", "ServerPing$ServerData");
return getMinecraftClass("ServerPingServerData", "ServerPing$ServerData");
} catch (RuntimeException e) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(getServerPingClass(), true);
return setMinecraftClass("ServerPingServerData", fuzzy.getFieldByType("(.*)(ServerData)(.*)").getType());
@@ -891,9 +872,11 @@ 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("network.protocol.status.ServerPing$ServerPingPlayerSample",
"ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
return getMinecraftClass("ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
} catch (RuntimeException e) {
Class<?> serverPing = getServerPingClass();
@@ -959,7 +942,7 @@ public class MinecraftReflection {
*/
public static Class<?> getMinecraftServerClass() {
try {
return getMinecraftClass("server.MinecraftServer","MinecraftServer");
return getMinecraftClass("MinecraftServer");
} catch (RuntimeException e) {
useFallbackServer();
@@ -975,7 +958,7 @@ public class MinecraftReflection {
*/
public static Class<?> getStatisticClass() {
// TODO: Implement fallback
return getMinecraftClass("stats.Statistic", "Statistic");
return getMinecraftClass("Statistic");
}
/**
@@ -984,7 +967,7 @@ public class MinecraftReflection {
*/
public static Class<?> getStatisticListClass() {
// TODO: Implement fallback
return getMinecraftClass("stats.StatisticList", "StatisticList");
return getMinecraftClass("StatisticList");
}
/**
@@ -1011,8 +994,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPlayerListClass() {
try {
return getMinecraftClass("server.players.PlayerList",
"ServerConfigurationManager", "PlayerList");
return getMinecraftClass("ServerConfigurationManager", "PlayerList");
} catch (RuntimeException e) {
useFallbackServer();
@@ -1051,7 +1033,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPlayerConnectionClass() {
try {
return getMinecraftClass("server.network.PlayerConnection","PlayerConnection", "NetServerHandler");
return getMinecraftClass("PlayerConnection", "NetServerHandler");
} catch (RuntimeException e) {
try {
// Use the player connection field
@@ -1095,7 +1077,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNetworkManagerClass() {
try {
return getMinecraftClass("network.NetworkManager", "INetworkManager", "NetworkManager");
return getMinecraftClass("INetworkManager", "NetworkManager");
} catch (RuntimeException e) {
Constructor<?> selected = FuzzyReflection.fromClass(getPlayerConnectionClass()).
getConstructor(FuzzyMethodContract.newBuilder().
@@ -1128,7 +1110,7 @@ public class MinecraftReflection {
*/
public static Class<?> getItemStackClass() {
try {
return getMinecraftClass("world.item.ItemStack", "ItemStack");
return getMinecraftClass("ItemStack");
} catch (RuntimeException e) {
// Use the handle reference
return setMinecraftClass("ItemStack",
@@ -1142,7 +1124,7 @@ public class MinecraftReflection {
*/
public static Class<?> getBlockClass() {
try {
return getMinecraftClass("world.level.block.Block", "Block");
return getMinecraftClass("Block");
} catch (RuntimeException e) {
FuzzyReflection reflect = FuzzyReflection.fromClass(getItemStackClass());
Set<Class<?>> candidates = new HashSet<Class<?>>();
@@ -1167,15 +1149,15 @@ public class MinecraftReflection {
}
public static Class<?> getItemClass() {
return getNullableNMS("world.item.Item", "Item");
return getNullableNMS("Item");
}
public static Class<?> getFluidTypeClass() {
return getNullableNMS("world.level.material.FluidType", "FluidType");
return getNullableNMS("FluidType");
}
public static Class<?> getParticleTypeClass() {
return getNullableNMS("core.particles.ParticleType", "ParticleType");
return getNullableNMS("ParticleType");
}
/**
@@ -1206,7 +1188,7 @@ public class MinecraftReflection {
*/
public static Class<?> getDataWatcherClass() {
try {
return getMinecraftClass("network.syncher.DataWatcher", "DataWatcher");
return getMinecraftClass("DataWatcher");
} catch (RuntimeException e) {
// Describe the DataWatcher
FuzzyClassContract dataWatcherContract = FuzzyClassContract.newBuilder().
@@ -1254,7 +1236,7 @@ public class MinecraftReflection {
*/
public static Class<?> getBlockPositionClass() {
try {
return getMinecraftClass("core.BlockPosition", "BlockPosition");
return getMinecraftClass("BlockPosition");
} catch (RuntimeException e) {
try {
Class<?> normalChunkGenerator = getCraftBukkitClass("generator.NormalChunkGenerator");
@@ -1281,7 +1263,7 @@ public class MinecraftReflection {
*/
public static Class<?> getVec3DClass() {
try {
return getMinecraftClass("world.phys.Vec3D", "Vec3D");
return getMinecraftClass("Vec3D");
} catch (RuntimeException e) {
// TODO: Figure out a fuzzy field contract
return null;
@@ -1306,10 +1288,13 @@ 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("world.level.ChunkCoordIntPair", "ChunkCoordIntPair");
return getMinecraftClass("ChunkCoordIntPair");
} catch (RuntimeException e) {
Class<?> packet = PacketType.Play.Server.MULTI_BLOCK_CHANGE.getPacketClass();
Class<?> packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.MULTI_BLOCK_CHANGE);
AbstractFuzzyMatcher<Class<?>> chunkCoordIntContract = FuzzyClassContract.newBuilder().
field(FuzzyFieldContract.newBuilder().
@@ -1341,8 +1326,7 @@ public class MinecraftReflection {
*/
public static Class<?> getDataWatcherItemClass() {
try {
return getMinecraftClass("network.syncher.DataWatcher$Item",
"DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
return getMinecraftClass("DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
} catch (RuntimeException e) {
Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true).
getMethod(FuzzyMethodContract.newBuilder().
@@ -1358,7 +1342,7 @@ public class MinecraftReflection {
public static Class<?> getDataWatcherObjectClass() {
try {
return getMinecraftClass("network.syncher.DataWatcherObject", "DataWatcherObject");
return getMinecraftClass("DataWatcherObject");
} catch (RuntimeException ex) {
return null;
}
@@ -1378,27 +1362,27 @@ public class MinecraftReflection {
public static Class<?> getDataWatcherSerializerClass() {
// TODO Implement a fallback
return getNullableNMS("network.syncher.DataWatcherSerializer", "DataWatcherSerializer");
return getNullableNMS("DataWatcherSerializer");
}
public static Class<?> getDataWatcherRegistryClass() {
// TODO Implement a fallback
return getMinecraftClass("network.syncher.DataWatcherRegistry", "DataWatcherRegistry");
return getMinecraftClass("DataWatcherRegistry");
}
public static Class<?> getMinecraftKeyClass() {
// TODO Implement a fallback
return getMinecraftClass("resources.MinecraftKey", "MinecraftKey");
return getMinecraftClass("MinecraftKey");
}
public static Class<?> getMobEffectListClass() {
// TODO Implement a fallback
return getMinecraftClass("world.effect.MobEffectList", "MobEffectList");
return getMinecraftClass("MobEffectList");
}
public static Class<?> getSoundEffectClass() {
try {
return getMinecraftClass("sounds.SoundEffect", "SoundEffect");
return getMinecraftClass("SoundEffect");
} catch (RuntimeException ex) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(PacketType.Play.Server.NAMED_SOUND_EFFECT.getPacketClass(), true);
Field field = fuzzy.getFieldByType("(.*)(Sound)(.*)");
@@ -1412,7 +1396,7 @@ public class MinecraftReflection {
*/
public static Class<?> getServerConnectionClass() {
try {
return getMinecraftClass("server.network.ServerConnection", "ServerConnection");
return getMinecraftClass("ServerConnection");
} catch (RuntimeException e) {
Method selected = null;
FuzzyClassContract.Builder serverConnectionContract = FuzzyClassContract.newBuilder().
@@ -1457,7 +1441,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNBTBaseClass() {
try {
return getMinecraftClass("nbt.NBTBase", "NBTBase");
return getMinecraftClass("NBTBase");
} catch (RuntimeException e) {
Class<?> nbtBase = null;
@@ -1517,7 +1501,7 @@ public class MinecraftReflection {
* @return The NBT read limiter.
*/
public static Class<?> getNBTReadLimiterClass() {
return getMinecraftClass("nbt.NBTReadLimiter", "NBTReadLimiter");
return getMinecraftClass("NBTReadLimiter");
}
/**
@@ -1526,7 +1510,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNBTCompoundClass() {
try {
return getMinecraftClass("nbt.NBTTagCompound","NBTTagCompound");
return getMinecraftClass("NBTTagCompound");
} catch (RuntimeException e) {
return setMinecraftClass(
"NBTTagCompound",
@@ -1541,8 +1525,7 @@ public class MinecraftReflection {
*/
public static Class<?> getEntityTrackerClass() {
try {
return getMinecraftClass("server.level.PlayerChunkMap$EntityTracker",
"EntityTracker", "PlayerChunkMap$EntityTracker");
return getMinecraftClass("EntityTracker", "PlayerChunkMap$EntityTracker");
} catch (RuntimeException e) {
FuzzyClassContract entityTrackerContract = FuzzyClassContract.newBuilder().
field(FuzzyFieldContract.newBuilder().
@@ -1570,6 +1553,38 @@ 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>
@@ -1578,8 +1593,7 @@ public class MinecraftReflection {
*/
public static Class<?> getAttributeSnapshotClass() {
try {
return getMinecraftClass("network.protocol.game.PacketPlayOutUpdateAttributes$AttributeSnapshot",
"AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
return getMinecraftClass("AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
} catch (RuntimeException ex) {
try {
// It should be the parameter of a list in the update attributes packet
@@ -1638,7 +1652,7 @@ public class MinecraftReflection {
*/
public static Class<?> getAttributeModifierClass() {
try {
return getMinecraftClass("world.entity.ai.attributes.AttributeModifier", "AttributeModifier");
return getMinecraftClass("AttributeModifier");
} catch (RuntimeException e) {
getAttributeSnapshotClass();
@@ -1654,10 +1668,10 @@ public class MinecraftReflection {
*/
public static Class<?> getMobEffectClass() {
try {
return getMinecraftClass("world.effect.MobEffect", "MobEffect");
return getMinecraftClass("MobEffect");
} catch (RuntimeException e) {
// It is the second parameter in Packet41MobEffect
Class<?> packet = PacketType.Play.Server.ENTITY_EFFECT.getPacketClass();
Class<?> packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.ENTITY_EFFECT);
Constructor<?> constructor = FuzzyReflection.fromClass(packet).getConstructor(
FuzzyMethodContract.newBuilder().
parameterCount(2).
@@ -1675,7 +1689,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPacketDataSerializerClass() {
try {
return getMinecraftClass("network.PacketDataSerializer", "PacketDataSerializer");
return getMinecraftClass("PacketDataSerializer");
} catch (RuntimeException e) {
Class<?> packet = getPacketClass();
Method method = FuzzyReflection.fromClass(packet).getMethod(
@@ -1695,7 +1709,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNbtCompressedStreamToolsClass() {
try {
return getMinecraftClass("nbt.NBTCompressedStreamTools", "NBTCompressedStreamTools");
return getMinecraftClass("NBTCompressedStreamTools");
} catch (RuntimeException e) {
Class<?> packetSerializer = getPacketDataSerializerClass();
@@ -1724,7 +1738,7 @@ public class MinecraftReflection {
* @return The tile entity class.
*/
public static Class<?> getTileEntityClass() {
return getMinecraftClass("world.level.block.entity.TileEntity", "TileEntity");
return getMinecraftClass("TileEntity");
}
/**
@@ -1806,54 +1820,7 @@ public class MinecraftReflection {
* @return The PlayerInfoData class
*/
public static Class<?> getPlayerInfoDataClass() {
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()));
return getMinecraftClass("PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
}
/**
@@ -1870,7 +1837,7 @@ public class MinecraftReflection {
* @return The IBlockData class
*/
public static Class<?> getIBlockDataClass() {
return getMinecraftClass("world.level.block.state.IBlockData", "IBlockData");
return getMinecraftClass("IBlockData");
}
/**
@@ -1900,24 +1867,15 @@ public class MinecraftReflection {
}
public static boolean signUpdateExists() {
return getNullableNMS("PacketPlayOutUpdateSign") != null;
try {
return getMinecraftClass("PacketPlayOutUpdateSign") != null;
} catch (RuntimeException ex) {
return false;
}
}
public static Class<?> getNonNullListClass() {
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;
}
return getMinecraftClass("NonNullList");
}
public static Class<?> getCraftSoundClass() {
@@ -1925,7 +1883,7 @@ public class MinecraftReflection {
}
public static Class<?> getSectionPositionClass() {
return getMinecraftClass("core.SectionPosition", "SectionPosition");
return getMinecraftClass("SectionPosition");
}
// ---- ItemStack conversions
@@ -2079,12 +2037,10 @@ public class MinecraftReflection {
.orElseThrow(() -> new RuntimeException("Failed to find NMS class: " + className));
}
public static Class<?> getNullableNMS(String className, String... aliases) {
try {
return getMinecraftClass(className, aliases);
} catch (RuntimeException ex) {
return null;
}
public static Class<?> getNullableNMS(String className) {
if (minecraftPackage == null)
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
return minecraftPackage.getPackageClass(className).orElse(null);
}
/**
@@ -2217,74 +2173,4 @@ 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,16 +44,6 @@ 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
*/
@@ -6,8 +6,7 @@ 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 final static String NETTY_ARTIFACT_ID = "netty-common";
private static NettyVersion version;
public static NettyVersion getVersion() {
@@ -19,10 +18,7 @@ public class NettyVersion {
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);
}
Version version = nettyArtifacts.get(NETTY_ARTIFACT_ID);
if(version != null) {
return new NettyVersion(version.artifactVersion());
}
@@ -1,741 +0,0 @@
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;
}
}
@@ -16,12 +16,6 @@
*/
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;
@@ -47,18 +41,9 @@ 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;
@@ -94,77 +79,75 @@ public class AutoWrapper<T> implements EquivalentConverter<T> {
throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex);
}
// ensures that all accessors are present
computeFieldAccessors();
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 = nmsAccessors[i];
FieldAccessor target = wrapperAccessors[i];
for (int i = 0; i < wrapperFields.length; i++) {
try {
Field wrapperField = wrapperFields[i];
Object value = source.get(nmsObject);
if (wrappers.containsKey(i))
value = wrappers.get(i).apply(value);
Field nmsField = nmsFields[i];
if (!nmsField.isAccessible())
nmsField.setAccessible(true);
target.set(instance, 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);
}
}
return instance;
}
public Object unwrap(Object wrapper) {
// ensures that all accessors are present
computeFieldAccessors();
computeNmsConstructorAccess();
Object instance;
Object instance = nmsInstanceCreator.invoke(nmsDefaultArgs);
try {
instance = nmsClass.newInstance();
} catch (ReflectiveOperationException ex) {
throw new InvalidWrapperException("Failed to construct new " + nmsClass.getSimpleName(), ex);
}
for (int i = 0; i < wrapperAccessors.length; i++) {
FieldAccessor source = wrapperAccessors[i];
FieldAccessor target = nmsAccessors[i];
Field[] wrapperFields = wrapperClass.getDeclaredFields();
Field[] nmsFields = Arrays
.stream(nmsClass.getDeclaredFields())
.filter(field -> !Modifier.isStatic(field.getModifiers()))
.toArray(Field[]::new);
Object value = source.get(wrapper);
if (unwrappers.containsKey(i))
value = unwrappers.get(i).apply(value);
for (int i = 0; i < wrapperFields.length; i++) {
try {
Field wrapperField = wrapperFields[i];
target.set(instance, 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);
}
}
return instance;
}
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);
}
}
private void unsetFinal(Field field) throws ReflectiveOperationException {
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
// ---- Equivalent conversion
@@ -18,15 +18,8 @@ package com.comphenix.protocol.wrappers;
import java.lang.ref.WeakReference;
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.*;
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;
@@ -54,17 +47,12 @@ 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.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.*;
import org.bukkit.advancement.Advancement;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@@ -267,87 +255,6 @@ 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
@@ -359,12 +266,46 @@ public class BukkitConverters {
return ignoreNull(new EquivalentConverter<List<T>>() {
@Override
public List<T> getSpecific(Object generic) {
return getSpecificList(generic, 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;
}
@Override
public Object getGeneric(List<T> specific) {
return getGenericList(specific.getClass(), specific, itemConverter);
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;
}
@Override
@@ -406,6 +347,20 @@ 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
@@ -717,7 +672,7 @@ public class BukkitConverters {
ProtocolManager manager = managerRef.get();
// Use the entity ID to get a reference to the entity
if (id != null && id >= 0 && manager != null) {
if (id != null && manager != null) {
return manager.getEntityFromID(world, id);
} else {
return null;
@@ -743,7 +698,7 @@ public class BukkitConverters {
@Override
public Object getGeneric(EntityType specific) {
if (entityTypeFromName == null) {
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
Class<?> entityTypesClass = MinecraftReflection.getMinecraftClass("EntityTypes");
entityTypeFromName = Accessors.getMethodAccessor(
FuzzyReflection
.fromClass(entityTypesClass, false)
@@ -761,7 +716,7 @@ public class BukkitConverters {
@Override
public EntityType getSpecific(Object generic) {
if (getEntityTypeName == null) {
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
Class<?> entityTypesClass = MinecraftReflection.getMinecraftClass("EntityTypes");
getEntityTypeName = Accessors.getMethodAccessor(
FuzzyReflection
.fromClass(entityTypesClass, false)
@@ -1118,7 +1073,7 @@ public class BukkitConverters {
public Advancement getSpecific(Object generic) {
try {
return (Advancement) getCraftBukkitClass("advancement.CraftAdvancement")
.getConstructor(getMinecraftClass("advancements.Advancement", "Advancement"))
.getConstructor(getMinecraftClass("Advancement"))
.newInstance(generic);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
@@ -1237,12 +1192,7 @@ public class BukkitConverters {
public Object getGeneric(PotionEffectType specific) {
Class<?> clazz = MinecraftReflection.getMobEffectListClass();
if (getMobEffect == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
getMobEffect = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
.parameterExactArray(int.class)
.returnTypeExact(clazz)
.requireModifier(Modifier.STATIC)
.build()));
getMobEffect = Accessors.getMethodAccessor(clazz, "fromId", int.class);
}
int id = specific.getId();
@@ -1253,12 +1203,7 @@ public class BukkitConverters {
public PotionEffectType getSpecific(Object generic) {
Class<?> clazz = MinecraftReflection.getMobEffectListClass();
if (getMobEffectId == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
getMobEffectId = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
.parameterExactArray(clazz)
.returnTypeExact(int.class)
.requireModifier(Modifier.STATIC)
.build()));
getMobEffectId = Accessors.getMethodAccessor(clazz, "getId", clazz);
}
int id = (int) getMobEffectId.invoke(null, generic);
@@ -1287,7 +1232,7 @@ public class BukkitConverters {
if (worldKeyField == null) {
Class<?> worldClass = MinecraftReflection.getNmsWorldClass();
Class<?> resourceKeyClass = MinecraftReflection.getResourceKey();
Class<?> resourceKeyClass = MinecraftReflection.getMinecraftClass("ResourceKey");
FuzzyReflection fuzzy = FuzzyReflection.fromClass(nmsWorld.getClass(), true);
worldKeyField = Accessors.getFieldAccessor(fuzzy.getParameterizedField(resourceKeyClass, worldClass));
@@ -1347,95 +1292,14 @@ 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.getDimensionManager();
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
}
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);
@@ -1469,31 +1333,9 @@ public class BukkitConverters {
@Override
public Integer getSpecific(Object generic) {
if (dimensionManager == null) {
dimensionManager = MinecraftReflection.getDimensionManager();
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
}
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);
@@ -1549,7 +1391,7 @@ public class BukkitConverters {
@Override
public Object getGeneric(List<MerchantRecipe> specific) {
if (merchantRecipeListConstructor == null) {
Class<?> merchantRecipeListClass = MinecraftReflection.getMerchantRecipeList();
Class<?> merchantRecipeListClass = MinecraftReflection.getMinecraftClass("MerchantRecipeList");
merchantRecipeListConstructor = Accessors.getConstructorAccessor(merchantRecipeListClass);
Class<?> craftMerchantRecipeClass = MinecraftReflection.getCraftBukkitClass("inventory.CraftMerchantRecipe");
FuzzyReflection reflection = FuzzyReflection.fromClass(craftMerchantRecipeClass, false);
@@ -1563,9 +1405,7 @@ public class BukkitConverters {
@Override
public List<MerchantRecipe> getSpecific(Object generic) {
if (nmsMerchantRecipeToBukkit == null) {
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass(
"world.item.trading.MerchantRecipe","MerchantRecipe"
);
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass("MerchantRecipe");
FuzzyReflection reflection = FuzzyReflection.fromClass(merchantRecipeClass, false);
nmsMerchantRecipeToBukkit = Accessors.getMethodAccessor(reflection.getMethodByName("asBukkit"));
}
@@ -1590,7 +1430,7 @@ public class BukkitConverters {
@Override
public Object getGeneric(BlockPosition specific) {
if (sectionPositionClass == null) {
sectionPositionClass = MinecraftReflection.getSectionPosition();
sectionPositionClass = MinecraftReflection.getMinecraftClass("SectionPosition");
}
if (sectionPositionCreate == null) {
@@ -1,18 +1,12 @@
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
@@ -85,14 +79,9 @@ public class ChunkCoordIntPair {
public ChunkCoordIntPair getSpecific(Object generic) {
if (MinecraftReflection.isChunkCoordIntPair(generic)) {
if (COORD_X == null || COORD_Z == null) {
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));
FieldAccessor[] ints = Accessors.getFieldAccessorArray(COORD_PAIR_CLASS, int.class, true);
COORD_X = ints[0];
COORD_Z = ints[1];
}
return new ChunkCoordIntPair((Integer) COORD_X.get(generic), (Integer) COORD_Z.get(generic));
}
@@ -17,12 +17,15 @@
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Array;
import java.util.Optional;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.utility.MinecraftReflection;
import org.jetbrains.annotations.NotNull;
/**
* Utility class for converters
* @author dmulloy2
@@ -108,6 +111,34 @@ public class Converters {
};
}
/**
* Creates a generic lazy array converter. Similar to the regular array converter, but conversion happens
* on an as-needed basis.
*
* @param nmsClass
* @param converter
* @param <T>
* @return
*/
public static <T> EquivalentConverter<List<T>> lazyArray(final Class<?> nmsClass, final EquivalentConverter<T> converter) {
return new EquivalentConverter<List<T>>() {
@Override
public Object getGeneric(List<T> specific) {
return null;
}
@Override
public List<T> getSpecific(Object generic) {
return null;
}
@Override
public Class<List<T>> getSpecificType() {
return null;
}
};
}
/**
* Creates a generic array converter. Converts a NMS object array to and from a wrapper array by converting
* each element individually.
@@ -151,24 +182,4 @@ 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,7 +10,6 @@ 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;
@@ -384,7 +383,6 @@ public abstract class EnumWrappers {
SWIMMING,
SPIN_ATTACK,
CROUCHING,
LONG_JUMPING,
DYING;
private final static EquivalentConverter<EntityPose> POSE_CONVERTER = EnumWrappers.getEntityPoseConverter();
@@ -483,6 +481,7 @@ 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);
@@ -497,29 +496,21 @@ public abstract class EnumWrappers {
try {
// TODO enum names are more stable than their packet associations
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("world.entity.EnumItemSlot", "EnumItemSlot");
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("EnumItemSlot");
} catch (Exception ex) {
ITEM_SLOT_CLASS = getEnum(PacketType.Play.Server.ENTITY_EQUIPMENT.getPacketClass(), 0);
}
// 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);
}
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
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("world.entity.EntityPose", "EntityPose");
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("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());
@@ -532,14 +523,15 @@ 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) {
@@ -558,19 +550,12 @@ public abstract class EnumWrappers {
* @return The type of the enum field.
*/
private static Class<?> getEnum(Class<?> clazz, int index) {
if (clazz == null) {
// not supported in the current version
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);
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() {
@@ -787,17 +772,22 @@ 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 final Class<?> genericType;
private final Class<T> specificType;
private Class<?> genericType;
private 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;
}
@@ -816,6 +806,10 @@ public abstract class EnumWrappers {
public Class<T> getSpecificType() {
return specificType;
}
void setGenericType(Class<?> genericType) {
this.genericType = genericType;
}
}
public interface AliasedEnum {
@@ -10,8 +10,7 @@ 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(
"world.phys.MovingObjectPositionBlock", "MovingObjectPositionBlock");
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("MovingObjectPositionBlock");
private BlockPosition position;
private Vector posVector;
@@ -17,16 +17,12 @@
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.
@@ -98,17 +94,14 @@ public class PlayerInfoData {
public Object getGeneric(PlayerInfoData specific) {
if (constructor == null) {
try {
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]));
// public PlayerInfoData(Packet, GameProfile, int, GameMode, ChatComponent)
constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor(
MinecraftReflection.getMinecraftClass("PacketPlayOutPlayerInfo"),
MinecraftReflection.getGameProfileClass(),
int.class,
EnumWrappers.getGameModeClass(),
MinecraftReflection.getIChatBaseComponentClass()
);
} catch (Exception e) {
throw new RuntimeException("Cannot find PlayerInfoData constructor.", e);
}
@@ -117,14 +110,16 @@ public class PlayerInfoData {
// Attempt to construct the underlying PlayerInfoData
try {
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);
}
// 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;
} catch (Exception e) {
throw new RuntimeException("Failed to construct PlayerInfoData.", e);
}
@@ -176,19 +171,19 @@ public class PlayerInfoData {
if (obj instanceof PlayerInfoData) {
PlayerInfoData other = (PlayerInfoData) obj;
return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode
&& Objects.equals(displayName, other.displayName);
&& displayName.equals(other.displayName);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(latency, gameMode, profile, displayName);
return Objects.hashCode(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 final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f","Vector3f");
private static Class<?> clazz = MinecraftReflection.getMinecraftClass("Vector3f");
public static Class<?> getMinecraftClass() {
return NMS_CLASS;
return clazz;
}
public static EquivalentConverter<Vector3F> getConverter() {
@@ -100,7 +100,7 @@ public class Vector3F {
public Object getGeneric(Vector3F specific) {
if (constructor == null) {
try {
constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class);
constructor = clazz.getConstructor(float.class, float.class, float.class);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
}
@@ -3,12 +3,13 @@ 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;
@@ -33,6 +34,9 @@ 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 {
@@ -72,7 +76,7 @@ public class WrappedAttribute extends AbstractWrapper {
// Initialize modifier
if (ATTRIBUTE_MODIFIER == null) {
ATTRIBUTE_MODIFIER = new StructureModifier<>(MinecraftReflection.getAttributeSnapshotClass());
ATTRIBUTE_MODIFIER = new StructureModifier<Object>(MinecraftReflection.getAttributeSnapshotClass());
}
this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle);
}
@@ -111,9 +115,7 @@ public class WrappedAttribute extends AbstractWrapper {
public String key;
}
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.ai.attributes.AttributeBase", "AttributeBase"
);
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS("AttributeBase");
private static final AutoWrapper<WrappedAttributeBase> ATTRIBUTE_BASE = AutoWrapper.wrap(
WrappedAttributeBase.class, ATTRIBUTE_BASE_CLASS
@@ -165,14 +167,8 @@ 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)
@@ -227,7 +223,7 @@ public class WrappedAttribute extends AbstractWrapper {
}
};
attributeModifiers = new CachedSet<>(converted);
attributeModifiers = new CachedSet<WrappedAttributeModifier>(converted);
}
return Collections.unmodifiableSet(attributeModifiers);
}
@@ -250,7 +246,9 @@ public class WrappedAttribute extends AbstractWrapper {
if (getBaseValue() == other.getBaseValue() &&
Objects.equal(getAttributeKey(), other.getAttributeKey())) {
return other.getModifiers().containsAll(getModifiers());
return getModifiers().stream()
.filter((elem) -> !other.getModifiers().contains(elem))
.count() == 0;
}
}
return false;
@@ -413,33 +411,45 @@ 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.");
}
boolean isStatic = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
// Retrieve the correct constructor
if (ATTRIBUTE_CONSTRUCTOR == null) {
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());
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()
);
// Just in case
ATTRIBUTE_CONSTRUCTOR.setAccessible(true);
}
Object attributeKey;
if (KEY_WRAPPED) {
WrappedRegistry registry = WrappedRegistry.getAttributeRegistry();
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);
}
String strKey = REMAP.getOrDefault(this.attributeKey, this.attributeKey);
attributeKey = registry.get(strKey);
Object key = MinecraftKey.getConverter().getGeneric(new MinecraftKey(strKey));
attributeKey = REGISTRY_GET.invoke(REGISTRY, key);
if (attributeKey == null) {
throw new IllegalArgumentException("Invalid attribute name: " + this.attributeKey);
@@ -449,14 +459,15 @@ public class WrappedAttribute extends AbstractWrapper {
}
try {
Object handle;
if (isStatic) {
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(attributeKey, baseValue, getUnwrappedModifiers());
} else {
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(packet.getHandle(), attributeKey, baseValue, getUnwrappedModifiers());
}
Object 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,9 +66,7 @@ public class WrappedAttributeModifier extends AbstractWrapper {
}
static {
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass(
"world.entity.ai.attributes.AttributeModifier$Operation", "AttributeModifier$Operation"
) : null;
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass("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.getChatDeserializer(), true)
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getMinecraftClass("ChatDeserializer"), 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
@@ -129,10 +129,8 @@ 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("world.entity.projectile.EntityEgg", "EntityEgg"),
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class
);
eggConstructor = Accessors.getConstructorAccessor(MinecraftReflection.getMinecraftClass("EntityEgg"),
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class);
}
Object world = BukkitUnwrapper.getInstance().unwrapItem(Bukkit.getWorlds().get(0));
@@ -495,7 +493,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") || method.getName().equals("b")) {
if (method.getName().equals("set") || method.getName().equals("watch")) {
SETTER = Accessors.getMethodAccessor(method);
} else {
REGISTER = Accessors.getMethodAccessor(method);
@@ -1,200 +0,0 @@
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;
}
}
@@ -0,0 +1,241 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2021 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 java.lang.reflect.Constructor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.EnumWrappers.EnumConverter;
/**
* Represents a nms MapIcon as part of the Map Data packet.
* @author dmulloy2
*/
public class WrappedMapIcon {
public static Class<?> NMS_CLASS = MinecraftReflection.getMinecraftClass("MapIcon");
private static Class<?> TYPE_CLASS = MinecraftReflection.getMinecraftClass("MapIcon$Type");
private static EnumConverter<MapIconType> TYPE_CONVERTER = new EnumConverter<>(TYPE_CLASS, MapIconType.class);
public enum MapIconType {
PLAYER,
FRAME,
RED_MARKER,
BLUE_MARKER,
TARGET_X,
TARGET_POINT,
PLAYER_OFF_MAP,
PLAYER_OFF_LIMITS,
MANSION,
MONUMENT,
BANNER_WHITE,
BANNER_ORANGE,
BANNER_MAGENTA,
BANNER_LIGHT_BLUE,
BANNER_YELLOW,
BANNER_LIME,
BANNER_PINK,
BANNER_GRAY,
BANNER_LIGHT_GRAY,
BANNER_CYAN,
BANNER_PURPLE,
BANNER_BLUE,
BANNER_BROWN,
BANNER_GREEN,
BANNER_RED,
BANNER_BLACK,
RED_X
}
private MapIconType type;
private byte x;
private byte y;
private byte rotation;
private WrappedChatComponent name;
/**
* Constructs a Map Icon with default values
*/
public WrappedMapIcon() {
this.type = MapIconType.PLAYER;
this.x = 0;
this.y = 0;
this.rotation = 0;
this.name = null;
}
/**
* Constructs a new Map Icon
*
* @param type Icon type
* @param x X position [-128,127]
* @param y Y position [-128,127]
* @param rotation Rotation, in degrees [0,360]
* @param name Display name, may be null
*/
public WrappedMapIcon(@Nonnull MapIconType type, byte x, byte y, double rotation,
@Nullable WrappedChatComponent name) {
this.type = type;
this.x = x;
this.y = y;
this.setRotation(rotation);
this.name = name;
}
/**
* Gets the type of this icon. Icon types change the display
* @return Map Icon Type
*/
public MapIconType getType() {
return type;
}
/**
* @param type New MapIconType
*/
public void setType(MapIconType type) {
this.type = type;
}
/**
* Gets the X coordinate of this icon on the map.
* -128 for furthest left, 127 for furthest right
*
* @return The X coordinate
*/
public byte getX() {
return x;
}
/**
* @param x New X value [-128,127]
*/
public void setX(byte x) {
this.x = x;
}
/**
* Gets the Y coordinate of this icon on the map.
* -128 for furthest left, 127 for furthest right
*
* @return The Y coordinate
*/
public byte getY() {
return y;
}
/**
* @param y New Y value [-128,127]
*/
public void setY(byte y) {
this.y = y;
}
/**
* Gets the rotation of this icon on the map from 0-360
* Note that internally the rotation is a byte from 0-15 and is scaled by 22.5 deg.
* @return The rotation
*/
public double getRotation() {
return rotation * 22.5;
}
/**
* Set the new rotation. Rotation may be from 0-360 degrees
* @param rot New rotation value in degrees.
*/
public void setRotation(double rot) {
this.rotation = (byte) (rot / 22.5);
}
/**
* Gets the display name of this icon. Note that it may be null.
* @return Display name
*/
@Nullable
public WrappedChatComponent getName() {
return name;
}
/**
* @param name New display name. May be null, in which case no name is displayed.
*/
public void setName(@Nullable WrappedChatComponent name) {
this.name = name;
}
private static Constructor<?> constructor = null;
/**
* Converts nms Map Icons to and from this ProtocolLib representation.
* @return The converter
*/
public static EquivalentConverter<WrappedMapIcon> getConverter() {
return new EquivalentConverter<WrappedMapIcon>() {
@Override
public Object getGeneric(WrappedMapIcon specific) {
if (constructor == null) {
constructor = FuzzyReflection.fromClass(NMS_CLASS)
.getConstructor(FuzzyMethodContract.newBuilder()
.requirePublic()
.returnTypeExact(NMS_CLASS)
.parameterCount(5)
.build()
);
}
try {
return constructor.newInstance(
TYPE_CONVERTER.getGeneric(specific.type),
specific.x,
specific.y,
specific.rotation,
specific.name != null ? specific.name.getHandle() : null
);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to construct nms Map Icon", ex);
}
}
@Override
public WrappedMapIcon getSpecific(Object generic) {
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass());
StructureModifier<Byte> bytes = modifier.withType(byte.class);
Object nmsComponent = modifier.withType(MinecraftReflection.getIChatBaseComponentClass()).read(0);
return new WrappedMapIcon(
modifier.withType(TYPE_CLASS, TYPE_CONVERTER).read(0),
bytes.read(0),
bytes.read(1),
bytes.read(2) * 22.5,
nmsComponent != null ? WrappedChatComponent.fromHandle(nmsComponent) : null
);
}
@Override
public Class<WrappedMapIcon> getSpecificType() {
return WrappedMapIcon.class;
}
};
}
}
@@ -9,8 +9,6 @@ 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;
@@ -33,14 +31,14 @@ public class WrappedParticle<T> {
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(Particle.class)
.parameterExactType(MinecraftReflection.getParticleParam())
.parameterExactType(MinecraftReflection.getMinecraftClass("ParticleParam"))
.build();
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
contract = FuzzyMethodContract
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(MinecraftReflection.getParticleParam())
.returnTypeExact(MinecraftReflection.getMinecraftClass("ParticleParam"))
.parameterCount(2)
.build();
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
@@ -132,26 +130,12 @@ public class WrappedParticle<T> {
}
private static Object getRedstone(Object handle) {
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);
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));
}
public static <T> WrappedParticle<T> create(Particle particle, T data) {
@@ -1,91 +0,0 @@
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());
}
}
@@ -7,12 +7,9 @@ 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(
"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 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 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.getNbtTagTypes();
Class<?> tagTypes = MinecraftReflection.getMinecraftClass("NBTTagTypes");
FuzzyReflection fuzzy = FuzzyReflection.fromClass(tagTypes, false);
getTagType = fuzzy.getMethod(
FuzzyMethodContract.newBuilder().parameterCount(1).parameterExactType(int.class).build());
@@ -35,8 +35,7 @@ import org.bukkit.block.BlockState;
* @author Kristian
*/
class TileEntityAccessor<T extends BlockState> {
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove()
&& !MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove();
/**
* Token indicating that the given block state doesn't contain any tile entities.
@@ -3,10 +3,6 @@ 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;
@@ -14,6 +10,7 @@ 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;
@@ -21,25 +18,41 @@ 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.
*/
//@BeforeAll
//@BeforeClass
public static void setupCraftBukkit() throws Exception {
setupPlugins();
@@ -50,18 +63,17 @@ 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
@@ -70,22 +82,26 @@ 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.
*/
//@AfterAll
//@AfterClass
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 {
@@ -93,27 +109,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);
}
@@ -132,53 +148,46 @@ 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.emptyList());
when(description.getLoadBefore()).thenReturn(Collections.emptyList());
when(description.getSoftDepend()).thenReturn(Collections.<String>emptyList());
when(description.getLoadBefore()).thenReturn(Collections.<String>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,10 +1,5 @@
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;
@@ -15,110 +10,84 @@ 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;
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;
// Current Minecraft version
private final int protocolVersion;
public SimpleMinecraftClient(int protocolVersion) {
// Typical Minecraft serializer
private static StreamSerializer serializer = StreamSerializer.getDefault();
public SimpleMinecraftClient(int protocolVersion) {
this.protocolVersion = protocolVersion;
}
/**
* 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
*/
/**
* 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));
return 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;
Socket socket = null;
OutputStream output = null;
InputStream input = null;
try {
socket = new Socket();
socket.connect(address, CONNECT_TIMEOUT);
try {
socket = new Socket();
socket.connect(address, CONNECT_TIMEOUT);
// Shouldn't take that long
socket.setSoTimeout(READ_TIMEOUT);
// Retrieve sockets
output = socket.getOutputStream();
input = socket.getInputStream();
// Shouldn't take that long
socket.setSoTimeout(READ_TIMEOUT);
// The output writer
DataOutputStream data = new DataOutputStream(output);
// 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();
}
}
// 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();
}
}
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());
@@ -127,15 +96,14 @@ 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 = this.getDataInput(buffer);
DataInputStream data = 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);
@@ -148,47 +116,69 @@ 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);
this.ping = this.serializer.deserializeString(input, 32000);
ping = serializer.deserializeString(input, 32000);
}
public String getPingJson() {
return this.ping;
return ping;
}
}
private static class HandshakePacket extends SimplePacket {
private final int protocol;
private final String host;
private final int port;
private final int nextState;
private int protocol;
private String host;
private int port;
private int nextState;
public HandshakePacket(int protocol, String host, int port, int nextState) {
super(PacketType.Handshake.Client.SET_PROTOCOL);
this.protocol = protocol;
@@ -200,26 +190,25 @@ public class SimpleMinecraftClient {
@Override
public void write(DataOutputStream output) throws IOException {
super.write(output);
this.serializer.serializeVarInt(output, this.protocol);
this.serializer.serializeString(output, this.host);
output.writeShort(this.port);
this.serializer.serializeVarInt(output, this.nextState);
serializer.serializeVarInt(output, protocol);
serializer.serializeString(output, host);
output.writeShort(port);
serializer.serializeVarInt(output, 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 {
this.serializer.serializeVarInt(output, this.type.getCurrentId());
serializer.serializeVarInt(output, type.getCurrentId());
}
@SuppressWarnings("unused")
public void read(PacketType type, DataInputStream input) throws IOException {
// Note - we don't read the packet id
@@ -1,20 +1,21 @@
package com.comphenix.integration.protocol;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.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 {
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
public class TestPingPacket {
// Current versions
private static final int PROTOCOL_VERSION = 4;
@@ -29,7 +30,6 @@ public class TestPingPacket {
/**
* Create a new test ping packet test.
*
* @return The new test.
*/
public static TestPingPacket newTest() {
@@ -38,18 +38,17 @@ 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 = this.testInterception(plugin).
get(TIMEOUT_PING_MS, TimeUnit.MILLISECONDS);
String transmitted = testInterception(plugin).
get(TIMEOUT_PING_MS, TimeUnit.MILLISECONDS);
// Make sure it's the same
System.out.println("Server string: " + transmitted);
assertEquals(this.source, transmitted);
assertEquals(source, transmitted);
} catch (ExecutionException e) {
throw e.getCause();
}
@@ -57,12 +56,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) {
TestPingPacket.this.source = event.getPacket().getServerPings().read(0).toJson();
}
});
new PacketAdapter(test, PacketType.Status.Server.SERVER_INFO) {
@Override
public void onPacketSending(PacketEvent event) {
source = event.getPacket().getServerPings().read(0).toJson();
}
});
// Invoke the client on a separate thread
return Executors.newSingleThreadExecutor().submit(new Callable<String>() {
@@ -72,9 +71,8 @@ public class TestPingPacket {
String information = client.queryLocalPing();
// Wait for the listener to catch up
for (int i = 0; i < 1000 && (TestPingPacket.this.source == null); i++) {
for (int i = 0; i < 1000 && (source == null); i++)
Thread.sleep(1);
}
return information;
}
@@ -1,45 +1,47 @@
package com.comphenix.protocol;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.utility.Constants;
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 net.minecraft.server.v1_16_R3.DispenserRegistry;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
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.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.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());
}
/**
* Statically initializes the mock server for unit testing
*/
public static synchronized void initializeAll() {
private boolean initialized;
private boolean packaged;
public static synchronized void initializePackage() {
instance.setPackage();
}
public static synchronized void initializeItemMeta() {
instance.initialize();
}
@@ -47,9 +49,11 @@ public class BukkitInitialization {
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing
*/
private void initialize() {
if (!this.initialized) {
if (!initialized) {
// Denote that we're done
this.initialized = true;
initialized = true;
initializePackage();
try {
LogManager.getLogger();
@@ -58,26 +62,14 @@ public class BukkitInitialization {
ex.printStackTrace();
}
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();
DispenserRegistry.init();
// 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(serverVersion + " (MC: " + releaseTarget + ")");
when(mockedServer.getVersion()).thenReturn(CraftServer.class.getPackage().getImplementationVersion());
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion());
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
@@ -108,8 +100,8 @@ public class BukkitInitialization {
* Ensure that package names are correctly set up.
*/
private void setPackage() {
if (!this.packaged) {
this.packaged = true;
if (!packaged) {
packaged = true;
try {
LogManager.getLogger();
@@ -2,38 +2,39 @@
* 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.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.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
@@ -53,9 +54,8 @@ 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,63 +1,59 @@
/**
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;
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 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 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 org.apache.commons.lang.WordUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @author dmulloy2
*/
public class PacketTypeTest {
@BeforeAll
@BeforeClass
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);
};
}
@AfterAll
@AfterClass
public static void afterClass() {
PacketType.onDynamicCreate = __ -> {
};
PacketType.onDynamicCreate = __ -> {};
}
@SuppressWarnings("unchecked")
@@ -71,7 +67,7 @@ public class PacketTypeTest {
for (EnumProtocol protocol : protocols) {
System.out.println(WordUtils.capitalize(protocol.name().toLowerCase()));
Field field = EnumProtocol.class.getDeclaredField("j");
Field field = EnumProtocol.class.getDeclaredField("h");
field.setAccessible(true);
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
@@ -148,30 +144,17 @@ public class PacketTypeTest {
String fullName = clazz.getName();
fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
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());
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));
}
classNames.add(nameBuilder.toString());
}
className = classNames.get(classNames.size() - 1);
String className = classNames.get(classNames.size() - 1);
// Format it like SET_PROTOCOL
StringBuilder fieldName = new StringBuilder();
@@ -225,13 +208,11 @@ 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;
}
@@ -248,15 +229,14 @@ public class PacketTypeTest {
return builder.toString();
}
@BeforeAll
@BeforeClass
public static void initializeReflection() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializePackage();
}
@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
@@ -267,12 +247,12 @@ public class PacketTypeTest {
@Test
public void testDeprecation() {
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");
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);
}
@Test
@@ -282,12 +262,12 @@ public class PacketTypeTest {
EnumProtocol[] protocols = EnumProtocol.values();
for (EnumProtocol protocol : protocols) {
Field field = EnumProtocol.class.getDeclaredField("j");
Field field = EnumProtocol.class.getDeclaredField("h");
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("b");
Field mapField = entry.getValue().getClass().getDeclaredField("a");
mapField.setAccessible(true);
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
@@ -300,11 +280,9 @@ 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;
@@ -313,22 +291,6 @@ public class PacketTypeTest {
}
}
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");
assertTrue("Packet type(s) were incorrect!", !fail);
}
}
@@ -2,28 +2,30 @@
* 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.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.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.jupiter.api.Test;
import org.junit.Test;
public class BlockingHashMapTest {
@@ -33,21 +35,25 @@ public class BlockingHashMapTest {
final BlockingHashMap<Integer, String> map = BlockingHashMap.create();
ExecutorService service = Executors.newSingleThreadExecutor();
// Create a reader
Future<String> future = service.submit(() -> {
// Combine for easy reading
return map.get(0) + map.get(1);
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);
}
});
// 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,31 +1,24 @@
/**
* 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
* 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
*/
package com.comphenix.protocol.events;
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 java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType;
@@ -35,48 +28,20 @@ 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.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.*;
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 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 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 org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.bukkit.ChatColor;
@@ -89,26 +54,34 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
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.*;
// 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 {
private static BaseComponent[] TEST_COMPONENT;
// Helper converters
private final EquivalentConverter<WrappedDataWatcher> watchConvert = BukkitConverters.getDataWatcherConverter();
private final EquivalentConverter<ItemStack> itemConvert = BukkitConverters.getItemStackConverter();
private EquivalentConverter<WrappedDataWatcher> watchConvert = BukkitConverters.getDataWatcherConverter();
private EquivalentConverter<ItemStack> itemConvert = BukkitConverters.getItemStackConverter();
private static BaseComponent[] TEST_COMPONENT;
@BeforeAll
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializeItemMeta();
BukkitInitialization.initializePackage();
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();
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();
}
private <T> void testPrimitive(StructureModifier<T> modifier, int index, T initialValue, T testValue) {
@@ -122,7 +95,7 @@ public class PacketContainerTest {
private <T> void testObjectArray(StructureModifier<T[]> modifier, int index, T[] initialValue, T[] testValue) {
// Check initial value
assertEquals(modifier.read(index).length, initialValue.length);
assertNull(modifier.read(index));
modifier.writeDefaults();
// Test initial
@@ -138,7 +111,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));
@@ -155,61 +128,61 @@ public class PacketContainerTest {
@Test
public void testGetBytes() {
PacketContainer spawnMob = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY_LIVING);
this.testPrimitive(spawnMob.getBytes(), 0, (byte) 0, (byte) 1);
testPrimitive(spawnMob.getBytes(), 0, (byte)0, (byte)1);
}
@Test
public void testGetShorts() {
PacketContainer itemData = new PacketContainer(PacketType.Play.Server.REL_ENTITY_MOVE);
this.testPrimitive(itemData.getShorts(), 0, (short) 0, (short) 1);
PacketContainer itemData = new PacketContainer(PacketType.Play.Server.TRANSACTION);
testPrimitive(itemData.getShorts(), 0, (short)0, (short)1);
}
@Test
public void testGetIntegers() {
PacketContainer updateSign = new PacketContainer(PacketType.Play.Client.CLOSE_WINDOW);
this.testPrimitive(updateSign.getIntegers(), 0, 0, 1);
testPrimitive(updateSign.getIntegers(), 0, 0, 1);
}
@Test
public void testGetLongs() {
PacketContainer updateTime = new PacketContainer(PacketType.Play.Server.UPDATE_TIME);
this.testPrimitive(updateTime.getLongs(), 0, (long) 0, (long) 1);
testPrimitive(updateTime.getLongs(), 0, (long)0, (long)1);
}
@Test
public void testGetFloat() {
PacketContainer explosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
this.testPrimitive(explosion.getFloat(), 0, (float) 0, (float) 0.8);
testPrimitive(explosion.getFloat(), 0, (float)0, (float)0.8);
}
@Test
public void testGetDoubles() {
PacketContainer explosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
this.testPrimitive(explosion.getDoubles(), 0, (double) 0, 0.8);
testPrimitive(explosion.getDoubles(), 0, (double)0, 0.8);
}
@Test
public void testGetStrings() {
PacketContainer explosion = new PacketContainer(PacketType.Play.Client.CHAT);
this.testPrimitive(explosion.getStrings(), 0, "", "hello");
testPrimitive(explosion.getStrings(), 0, null, "hello");
}
@Test
public void testGetStringArrays() {
PacketContainer packet = new PacketContainer(PacketType.Play.Client.UPDATE_SIGN);
this.testObjectArray(packet.getStringArrays(), 0,
new String[]{"", "", "", ""},
new String[]{"hello", "world"}
);
testObjectArray(packet.getStringArrays(), 0, new String[0], new String[] { "hello", "world" });
}
@Test
public void testGetIntegerArrays() {
// Contains a byte array we will test
PacketContainer packet = new PacketContainer(PacketType.Play.Server.MOUNT);
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
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);
@@ -220,14 +193,14 @@ public class PacketContainerTest {
public void testGetItemModifier() {
PacketContainer windowClick = new PacketContainer(PacketType.Play.Client.WINDOW_CLICK);
ItemStack item = this.itemWithData();
ItemStack item = itemWithData();
StructureModifier<ItemStack> items = windowClick.getItemModifier();
// assertNull(items.read(0));
// Insert the item and check if it's there
items.write(0, item);
assertTrue(equivalentItem(item, items.read(0)), "Item " + item + " != " + items.read(0));
assertTrue("Item " + item + " != " + items.read(0), equivalentItem(item, items.read(0)));
}
private ItemStack itemWithData() {
@@ -245,10 +218,10 @@ public class PacketContainerTest {
StructureModifier<List<ItemStack>> itemAccess = windowItems.getItemListModifier();
List<ItemStack> items = new ArrayList<>();
items.add(this.itemWithData());
items.add(itemWithData());
items.add(new ItemStack(Material.DIAMOND_AXE));
assertEquals(itemAccess.read(0).size(), 0);
assertNull(itemAccess.read(0));
// Insert and check that it was succesful
itemAccess.write(0, items);
@@ -261,9 +234,8 @@ 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();
@@ -335,7 +307,7 @@ public class PacketContainerTest {
PacketContainer explosionPacket = new PacketContainer(PacketType.Play.Server.EXPLOSION);
StructureModifier<List<BlockPosition>> positionAccessor = explosionPacket.getBlockPositionCollectionModifier();
assertEquals(positionAccessor.read(0).size(), 0);
assertNull(positionAccessor.read(0));
List<BlockPosition> positions = Lists.newArrayList();
positions.add(new BlockPosition(1, 2, 3));
@@ -374,8 +346,7 @@ 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));
@@ -388,7 +359,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
@@ -402,19 +373,6 @@ 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);
@@ -422,20 +380,18 @@ public class PacketContainerTest {
// Initialize some test data
List<AttributeModifier> modifiers = Lists.newArrayList(
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10,
AttributeModifier.Operation.a));
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10, AttributeModifier.Operation.ADDITION));
// 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.aj.a(MinecraftKey.a("generic.max_health"));
AttributeSnapshot snapshot = new AttributeSnapshot(base, 20.0D, modifiers);
AttributeBase base = IRegistry.ATTRIBUTE.get(MinecraftKey.a("generic.max_health"));
AttributeSnapshot snapshot = packet.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()) {
@@ -446,7 +402,7 @@ public class PacketContainerTest {
}
field.setAccessible(true);
this.testEquality(field.get(snapshot), field.get(clonedSnapshot));
assertEquals(field.get(snapshot), field.get(clonedSnapshot));
} catch (AssertionError e) {
throw e;
} catch (Throwable ex) {
@@ -479,33 +435,26 @@ public class PacketContainerTest {
@SuppressWarnings("deprecation")
public void testPotionEffect() {
PotionEffect effect = new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 20 * 60, 1);
MobEffect mobEffect = new MobEffect(MobEffectList.a(effect.getType().getId()), effect.getDuration(),
effect.getAmplifier(), effect.isAmbient(),
MobEffect mobEffect = new MobEffect(MobEffectList.fromId(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, 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));
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));
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(1));
assertEquals(e, (byte) packet.getBytes().read(2));
}
@Test
@@ -545,35 +494,16 @@ 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.d.class).read(0), Action.UPDATE_PCT);
assertEquals(container.getEnumModifier(Action.class, PacketPlayOutBoss.Action.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));
@@ -616,14 +546,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));
@@ -638,77 +568,28 @@ public class PacketContainerTest {
@Test
public void testGameStateChange() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.GAME_STATE_CHANGE);
assertEquals(0, (int) packet.getGameStateIDs().read(0));
assertTrue(packet.getGameStateIDs().read(0) == 0);
packet.getGameStateIDs().write(0, 2);
assertEquals(2, (int) packet.getGameStateIDs().read(0));
assertTrue(packet.getGameStateIDs().read(0) == 2);
}
@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());
/**
* 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 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("")
};
@@ -718,33 +599,12 @@ 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 testCloning() {
boolean failed = false;
public void testDeepClone() {
// 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;
}
@@ -763,68 +623,66 @@ public class PacketContainerTest {
"String"),
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.get(Float.class)), 1.0F),
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.getChatComponentSerializer(true)),
Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
com.google.common.base.Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.get(VillagerData.class)),
new VillagerData(VillagerType.b, VillagerProfession.c, 69))
new VillagerData(VillagerType.SNOW, VillagerProfession.ARMORER, 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 both ways
PacketContainer shallowCloned = constructed.shallowClone();
this.assertPacketsEqual(constructed, shallowCloned);
// Clone the packet
PacketContainer cloned = constructed.deepClone();
PacketContainer deepCloned = constructed.deepClone();
this.assertPacketsEqual(constructed, deepCloned);
// 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));
}
}
} catch (Exception ex) {
ex.printStackTrace();
failed = true;
throw new RuntimeException("Failed to serialize packet " + type, ex);
}
}
assertFalse(failed, "Packet(s) failed to clone");
}
// Convert to objects that support equals()
private void testEquality(Object a, Object 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 != 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.equals(b) || Objects.equals(a, b) || this.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) {
if (a instanceof ItemStack || b instanceof ItemStack) {
assertItemsEqual((ItemStack) a, (ItemStack) 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 (EqualsBuilder.reflectionEquals(a, b)) {
return;
}
@@ -843,38 +701,20 @@ 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,70 +1,72 @@
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.Assert;
import org.junit.Before;
import org.junit.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 {
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;
@Mock
static OfflinePlayer offlinePlayer;
@BeforeEach
public void initMocks() {
MockitoAnnotations.openMocks(this);
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;
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);
private static SerializedOfflinePlayer serializedOfflinePlayer;
serializedOfflinePlayer = new SerializedOfflinePlayer(offlinePlayer);
}
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
@Test
public void getProxyPlayer() {
Player player = serializedOfflinePlayer.getProxyPlayer();
assertNotNull(player);
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);
// getDisplayName only works for online players.
assertThrows(UnsupportedOperationException.class, player::getDisplayName);
serializedOfflinePlayer = new SerializedOfflinePlayer(offlinePlayer);
}
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 getProxyPlayer() {
Player player = serializedOfflinePlayer.getProxyPlayer();
Assert.assertNotNull(player);
@Test
public void getSecondProxyPlayer() {
// Make sure that the proxyPlayer generation doesn't work only once.
Player player = serializedOfflinePlayer.getProxyPlayer();
assertNotNull(player);
// getDisplayName only works for online players.
assertThrows(UnsupportedOperationException.class, player::getDisplayName);
assertEquals(uuid, player.getUniqueId());
}
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());
}
}
@@ -1,31 +1,30 @@
package com.comphenix.protocol.injector;
import static com.comphenix.protocol.utility.TestUtils.setFinalField;
import static org.junit.jupiter.api.Assertions.assertEquals;
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 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 {
@BeforeAll
@BeforeClass
public static void beforeClass() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -35,27 +34,21 @@ public class EntityUtilitiesTest {
when(bukkit.getHandle()).thenReturn(world);
ChunkProviderServer provider = mock(ChunkProviderServer.class);
when(world.k()).thenReturn(provider);
when(world.getChunkProvider()).thenReturn(provider);
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
setFinalField(provider, chunkMapField, chunkMap);
Accessors.getFieldAccessor(ChunkProviderServer.class, "playerChunkMap", true).set(provider, chunkMap);
CraftEntity bukkitEntity = mock(CraftEntity.class);
Entity fakeEntity = mock(Entity.class);
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
EntityTracker tracker = mock(EntityTracker.class);
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
setFinalField(tracker, trackerField, fakeEntity);
Accessors.getFieldAccessor(EntityTracker.class, "tracker", true).set(tracker, fakeEntity);
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
trackerMap.put(1, tracker);
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
setFinalField(chunkMap, trackedEntitiesField, trackerMap);
Accessors.getFieldAccessor(PlayerChunkMap.class, "trackedEntities", true).set(chunkMap, trackerMap);
assertEquals(bukkitEntity, EntityUtilities.getInstance().getEntityFromID(bukkit, 1));
}
@@ -1,46 +1,53 @@
package com.comphenix.protocol.injector;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.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.jupiter.api.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
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 = 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");
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");
// 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);
@@ -50,7 +57,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;
@@ -61,20 +68,20 @@ public class PluginVerifierTest {
});
return mockServer;
}
private Plugin mockPlugin(Server server, String name, String... depend) {
return this.mockPlugin(server, name, PluginLoadOrder.POSTWORLD, depend);
private Plugin mockPlugin(Server server, String name,String... depend) {
return 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,84 +2,85 @@
* 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.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
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 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;
@@ -91,8 +92,8 @@ public class SortedCopyOnWriteArrayTest {
@Override
public int compareTo(PriorityStuff other) {
// This ensures that lower priority listeners are executed first
return Ints.compare(this.priority.getSlot(),
other.priority.getSlot());
return Ints.compare(priority.getSlot(),
other.priority.getSlot());
}
}
}
@@ -3,27 +3,32 @@
*/
package com.comphenix.protocol.injector;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
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 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 {
@BeforeAll
@BeforeClass
public static void beforeClass() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializePackage();
}
// @Test
@@ -31,9 +36,8 @@ 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);
@@ -53,7 +57,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);
@@ -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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.Before;
import org.junit.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;
@BeforeEach
public void initMocks() {
MockitoAnnotations.openMocks(this);
}
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testUnavailableSocketInjector() {
Player player = temporaryPlayerFactory.createTemporaryPlayer(this.server);
assertThrows(IllegalStateException.class, player::getPlayer);
}
@Test
public void testUnavailableSocketInjector()
{
Player player = temporaryPlayerFactory.createTemporaryPlayer(server);
assertThrows(IllegalStateException.class, player::getPlayer);
}
@Test
public void createTemporaryPlayer() {
@Test
public void createTemporaryPlayer() {
Player player = temporaryPlayerFactory.createTemporaryPlayer(this.server, this.socketInjector);
assertEquals(this.server, player.getServer());
Player player = temporaryPlayerFactory.createTemporaryPlayer(server, socketInjector);
assertEquals(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,51 +1,30 @@
package com.comphenix.protocol.reflect.accessors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.Test;
public class AccessorsTest {
@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");
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;
return id;
}
@SuppressWarnings("unused")
private void setId(int value) {
this.id = value;
}
}
private static class Player extends Entity {
private final String name;
private String name;
public Player(int id, String name) {
super(id);
@@ -53,7 +32,26 @@ public class AccessorsTest {
}
public String getName() {
return this.name;
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");
Accessors.getMethodAccessor(player.getClass(), "setId", int.class).invoke(player, 0);
assertEquals(0, player.getId());
}
}
@@ -1,33 +1,35 @@
package com.comphenix.protocol.reflect.cloning;
import static org.junit.jupiter.api.Assertions.assertEquals;
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 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 {
@BeforeAll
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializePackage();
}
@Test
public void testArrays() {
public void testArrays() {
List<Integer> input = Arrays.asList(1, 2, 3);
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
}
// @Test
// Usages of NonNullList were removed in 1.17.1
@Test
public void testNonNullList() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
@@ -40,6 +42,6 @@ public class AggregateClonerTest {
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
assertEquals(list.size(), list1.size());
Assertions.assertArrayEquals(list.toArray(), list1.toArray());
assertArrayEquals(list.toArray(), list1.toArray());
}
}
@@ -3,47 +3,46 @@
*/
package com.comphenix.protocol.updater;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.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.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.updater.Updater.UpdateType;
/**
* @author dmulloy2
*/
public class UpdaterTest {
public class UpdaterTest {
private static final int BUKKIT_DEV_ID = 45564;
private static Plugin plugin;
@BeforeAll
// @BeforeClass
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
@@ -55,10 +54,23 @@ public class UpdaterTest {
try {
remote = updater.getSpigotVersion();
} catch (Throwable ex) {
fail("Failed to check for updates", ex);
ex.printStackTrace();
fail("Failed to check for updates");
}
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,17 +1,19 @@
package com.comphenix.protocol.utility;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNotNull;
import org.junit.BeforeClass;
import org.junit.Test;
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 {
@BeforeAll
@BeforeClass
public static void initializeReflection() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializePackage();
}
@Test
@@ -28,11 +30,10 @@ public class MinecraftMethodsTest {
@Test
public void initializePacket() throws NoSuchFieldException, IllegalAccessException {
this.setNull("packetReadByteBuf");
this.setNull("packetWriteByteBuf");
setNull("packetReadByteBuf");
setNull("packetWriteByteBuf");
assertNotNull(MinecraftMethods.getPacketWriteByteBufMethod());
// TODO it's now a constructor
// assertNotNull(MinecraftMethods.getPacketReadByteBufMethod());
assertNotNull(MinecraftMethods.getPacketReadByteBufMethod());
}
}
@@ -1,42 +1,57 @@
package com.comphenix.protocol.utility;
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
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 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_18_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_16_R3.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;
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;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
public class MinecraftReflectionTest {
@BeforeAll
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializeItemMeta();
}
@AfterAll
// Mocking objects
private interface FakeEntity {
Entity getBukkitEntity();
}
private interface FakeBlock {
Block getBukkitEntity();
}
@AfterClass
public static void undoMocking() {
// NOP
MinecraftReflection.minecraftPackage = null;
@@ -54,9 +69,9 @@ public class MinecraftReflectionTest {
verify(block, times(1)).getBukkitEntity();
}
@Test
@Test(expected = IllegalArgumentException.class)
public void testIllegalClass() {
assertThrows(IllegalArgumentException.class, () -> MinecraftReflection.getBukkitEntity("Hello"));
MinecraftReflection.getBukkitEntity("Hello");
}
@Test
@@ -66,8 +81,7 @@ public class MinecraftReflectionTest {
@Test
public void testAttributeSnapshot() {
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class,
MinecraftReflection.getAttributeSnapshotClass());
assertEquals(AttributeSnapshot.class, MinecraftReflection.getAttributeSnapshotClass());
}
@Test
@@ -82,7 +96,7 @@ public class MinecraftReflectionTest {
@Test
public void testChatSerializer() {
assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
}
@Test
@@ -107,12 +121,12 @@ public class MinecraftReflectionTest {
@Test
public void testServerPingPlayerSample() {
assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
assertEquals(ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
}
@Test
public void testServerPingServerData() {
assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass());
assertEquals(ServerData.class, MinecraftReflection.getServerPingServerDataClass());
}
@Test
@@ -139,21 +153,4 @@ 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,38 +1,37 @@
package com.comphenix.protocol.utility;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertEquals;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import org.junit.Test;
public class SnapshotVersionTest {
@Test
public void testDates() {
SnapshotVersion a = new SnapshotVersion("12w50b");
SnapshotVersion b = new SnapshotVersion("13w05a");
this.expect(a.getSnapshotDate(), 12, 50);
this.expect(b.getSnapshotDate(), 13, 5);
expect(a.getSnapshotDate(), 12, 50);
expect(b.getSnapshotDate(), 13, 5);
// Test equality
assertEquals(a, new SnapshotVersion("12w50b"));
}
@Test
@Test(expected=IllegalArgumentException.class)
public void testDateParsingProblem() {
// This date is not valid
assertThrows(IllegalArgumentException.class, () -> new SnapshotVersion("12w80a"));
new SnapshotVersion("12w80a");
}
@Test
@Test(expected=IllegalArgumentException.class)
public void testMissingWeekVersion() {
assertThrows(IllegalArgumentException.class, () -> new SnapshotVersion("13w05"));
new SnapshotVersion("13w05");
}
private void expect(Date date, int year, int week) {
Calendar calendar = Calendar.getInstance(Locale.US);
calendar.setTime(date);
@@ -1,30 +1,38 @@
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.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
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 {
@BeforeAll
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializeItemMeta();
}
/*@Test
public void testMinecraftReflection() {
assertEquals(IntHashMap.class, MinecraftReflection.getIntHashMapClass());
}*/
@Test
public void testStrings() throws IOException {
StreamSerializer serializer = new StreamSerializer();
@@ -1,16 +1,13 @@
package com.comphenix.protocol.utility;
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) {
@@ -45,8 +42,4 @@ 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);
}
}
@@ -1,112 +0,0 @@
package com.comphenix.protocol.wrappers;
import static com.comphenix.protocol.utility.MinecraftReflection.getMinecraftClass;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import com.comphenix.protocol.BukkitInitialization;
import net.minecraft.advancements.AdvancementDisplay;
import net.minecraft.advancements.AdvancementFrameType;
import net.minecraft.network.chat.ChatComponentText;
import net.minecraft.world.item.Items;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class AutoWrapperTest {
@BeforeAll
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
}
@Test
public void testToNms() {
WrappedAdvancementDisplay display = new WrappedAdvancementDisplay();
display.title = WrappedChatComponent.fromText("Test123");
display.description = WrappedChatComponent.fromText("Test567");
display.item = new ItemStack(Material.SAND);
display.background = new MinecraftKey("test");
display.frameType = WrappedFrameType.CHALLENGE;
display.announceChat = false;
display.showToast = true;
display.hidden = true;
display.x = 5f;
display.y = 67f;
AdvancementDisplay nms = (AdvancementDisplay) displayWrapper().unwrap(display);
assertTrue(nms.h());
assertTrue(nms.j());
assertFalse(nms.i());
assertEquals("test", nms.d().a());
assertEquals("Test123", nms.a().a());
assertEquals("Test567", nms.b().a());
assertSame(AdvancementFrameType.b, nms.e());
assertSame(Items.L, nms.c().c());
assertEquals(5f, nms.f(), 0f);
assertEquals(67f, nms.g(), 0f);
}
@Test
public void testFromNms() {
AdvancementDisplay display = new AdvancementDisplay(
new net.minecraft.world.item.ItemStack(Items.L),
new ChatComponentText("Test123"),
new ChatComponentText("Test567"),
new net.minecraft.resources.MinecraftKey("minecraft", "test"),
AdvancementFrameType.b,
true,
false,
true
);
display.a(5f, 67f);
WrappedAdvancementDisplay wrapped = displayWrapper().wrap(display);
assertTrue(wrapped.showToast);
assertTrue(wrapped.hidden);
assertFalse(wrapped.announceChat);
assertEquals("test", wrapped.background.getKey());
assertEquals("{\"text\":\"Test123\"}", wrapped.title.getJson());
assertEquals("{\"text\":\"Test567\"}", wrapped.description.getJson());
assertSame(WrappedFrameType.CHALLENGE, wrapped.frameType);
assertSame(Material.SAND, wrapped.item.getType());
assertEquals(5f, wrapped.x, 0f);
assertEquals(67f, wrapped.y, 0f);
}
private AutoWrapper<WrappedAdvancementDisplay> displayWrapper() {
return AutoWrapper
.wrap(WrappedAdvancementDisplay.class, "advancements.AdvancementDisplay")
.field(0, BukkitConverters.getWrappedChatComponentConverter())
.field(1, BukkitConverters.getWrappedChatComponentConverter())
.field(2, BukkitConverters.getItemStackConverter())
.field(3, MinecraftKey.getConverter())
.field(4, EnumWrappers.getGenericConverter(getMinecraftClass("advancements.AdvancementFrameType"),
WrappedFrameType.class));
}
public enum WrappedFrameType {
TASK,
CHALLENGE,
GOAL
}
public static final class WrappedAdvancementDisplay {
public WrappedChatComponent title;
public WrappedChatComponent description;
public ItemStack item;
public MinecraftKey background;
public WrappedFrameType frameType;
public boolean showToast;
public boolean announceChat;
public boolean hidden;
public float x;
public float y;
}
}
@@ -1,24 +1,25 @@
package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.EquivalentConverter;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.BeforeClass;
import org.junit.Test;
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class BukkitConvertersTest {
@BeforeAll
@BeforeClass
public static void beforeClass() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -1,31 +1,32 @@
package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class ChunkCoordIntPairTest {
@BeforeAll
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializePackage();
}
@Test
public void test() {
net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2);
net.minecraft.server.v1_16_R3.ChunkCoordIntPair pair = new net.minecraft.server.v1_16_R3.ChunkCoordIntPair(1, 2);
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
assertEquals(1, specific.getChunkX());
assertEquals(2, specific.getChunkZ());
net.minecraft.world.level.ChunkCoordIntPair roundtrip =
(net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
getGeneric(specific);
net.minecraft.server.v1_16_R3.ChunkCoordIntPair roundtrip =
(net.minecraft.server.v1_16_R3.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
getGeneric(specific);
assertEquals(1, roundtrip.c);
assertEquals(2, roundtrip.d);
assertEquals(1, roundtrip.x);
assertEquals(2, roundtrip.z);
}
}
@@ -1,26 +1,27 @@
package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.cloning.AggregateCloner;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class CloningTest {
@BeforeAll
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializePackage();
}
@Test
public void cloneGameProfile() {
WrappedGameProfile profile = new WrappedGameProfile("8817d9ec-72e6-4abe-a496-cda667c3efe1", "name");
WrappedGameProfile copy = WrappedGameProfile.fromHandle(
AggregateCloner.DEFAULT.clone(profile.getHandle())
AggregateCloner.DEFAULT.clone(profile.getHandle())
);
assertEquals(profile, copy);
}
}
@@ -1,75 +1,73 @@
package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals;
import com.google.common.collect.Sets;
import net.minecraft.server.v1_16_R3.EnumChatVisibility;
import net.minecraft.server.v1_16_R3.EnumDifficulty;
import net.minecraft.server.v1_16_R3.EnumGamemode;
import net.minecraft.server.v1_16_R3.EnumProtocol;
import net.minecraft.server.v1_16_R3.PacketPlayInClientCommand.EnumClientCommand;
import net.minecraft.server.v1_16_R3.PacketPlayInUseEntity.EnumEntityUseAction;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.network.EnumProtocol;
import net.minecraft.network.protocol.game.PacketPlayInClientCommand.EnumClientCommand;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.EnumHand;
import net.minecraft.world.entity.player.EnumChatVisibility;
import net.minecraft.world.level.EnumGamemode;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class EnumWrappersTest {
private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
"Particle", "WorldBorderAction", "CombatEventType", "TitleAction"
);
@BeforeAll
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
private static class EnumClass {
public EnumProtocol protocol;
public EnumClientCommand command;
public EnumChatVisibility visibility;
public EnumDifficulty difficulty;
public EnumEntityUseAction action;
public EnumGamemode mode;
}
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
}
@Test
public void testEnum() {
EnumClass obj = new EnumClass();
obj.protocol = EnumProtocol.a;
obj.command = EnumClientCommand.b;
obj.visibility = EnumChatVisibility.c;
obj.difficulty = EnumDifficulty.d;
obj.hand = EnumHand.b;
// obj.action = EnumEntityUseAction.INTERACT;
obj.mode = EnumGamemode.e;
assertEquals(obj.protocol, this.roundtrip(obj, "protocol", EnumWrappers.getProtocolConverter()));
assertEquals(obj.command, this.roundtrip(obj, "command", EnumWrappers.getClientCommandConverter()));
assertEquals(obj.visibility, this.roundtrip(obj, "visibility", EnumWrappers.getChatVisibilityConverter()));
assertEquals(obj.difficulty, this.roundtrip(obj, "difficulty", EnumWrappers.getDifficultyConverter()));
assertEquals(obj.hand, this.roundtrip(obj, "hand", EnumWrappers.getHandConverter()));
// assertEquals(obj.action, roundtrip(obj, "action", EnumWrappers.getEntityUseActionConverter()) );
assertEquals(obj.mode, this.roundtrip(obj, "mode", EnumWrappers.getGameModeConverter()));
obj.protocol = EnumProtocol.LOGIN;
obj.command = EnumClientCommand.PERFORM_RESPAWN;
obj.visibility = EnumChatVisibility.FULL;
obj.difficulty = EnumDifficulty.PEACEFUL;
obj.action = EnumEntityUseAction.INTERACT;
obj.mode = EnumGamemode.CREATIVE;
assertEquals(obj.protocol, roundtrip(obj, "protocol", EnumWrappers.getProtocolConverter()) );
assertEquals(obj.command, roundtrip(obj, "command", EnumWrappers.getClientCommandConverter()) );
assertEquals(obj.visibility, roundtrip(obj, "visibility", EnumWrappers.getChatVisibilityConverter()) );
assertEquals(obj.difficulty, roundtrip(obj, "difficulty", EnumWrappers.getDifficultyConverter()) );
assertEquals(obj.action, roundtrip(obj, "action", EnumWrappers.getEntityUseActionConverter()) );
assertEquals(obj.mode, roundtrip(obj, "mode", EnumWrappers.getGameModeConverter()) );
}
@SuppressWarnings("unchecked")
public <T extends Enum<T>> T roundtrip(Object target, String fieldName, EquivalentConverter<T> converter) {
FieldAccessor accessor = Accessors.getFieldAccessor(target.getClass(), fieldName, true);
return (T) converter.getGeneric(
converter.getSpecific(accessor.get(target))
converter.getSpecific(accessor.get(target))
);
}
private static final Set<String> KNOWN_INVALID = Sets.newHashSet("Particle");
@Test
public void testValidity() {
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID);
}
private static class EnumClass {
public EnumProtocol protocol;
public EnumClientCommand command;
public EnumChatVisibility visibility;
public EnumDifficulty difficulty;
public EnumHand hand;
// public EnumEntityUseAction action; // moved to PacketPlayInUseEntity but is private
public EnumGamemode mode;
}
}
@@ -1,35 +1,44 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals;
import org.bukkit.Location;
import org.bukkit.Material;
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.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.utility.MinecraftReflection;
import org.bukkit.Location;
import org.bukkit.Material;
/**
* @author dmulloy2
*/
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
public class MultiBlockChangeTest {
// @BeforeAll
// @BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializeAll();
BukkitInitialization.initializeItemMeta();
}
// @Test
@@ -46,7 +55,7 @@ public class MultiBlockChangeTest {
// Make sure the location is correct
assertEquals(loc, info.getLocation(null));
MultiBlockChangeInfo[] array = {info, info};
MultiBlockChangeInfo[] array = { info, info };
EquivalentConverter<MultiBlockChangeInfo[]> converter = Converters.array(
MinecraftReflection.getMultiBlockChangeInfoClass(),
Loaded 100 of 114 files, more files were not shown because too many files have changed in this diff. Show more