Compare commits

..
41 Commits
Author SHA1 Message Date
Dan Mulloy 95a884974a Only set chat UUID if not already set
Fixes #1310
2021-07-08 23:33:17 -04:00
Dan Mulloy 153dd61994 Update to 1.17.1
Fixes #1315
2021-07-08 23:22:56 -04:00
Dan Mulloy 263ec8a36e Add FLYING packet back for backwards compat
Fixes #1275
2021-06-27 18:13:40 -04:00
Julian af46ba4d1a Fix support for Minecraft versions under the bee update (#1276) 2021-06-27 17:57:14 -04:00
Dan Mulloy dd85904642 Metrics: only track each plugin once 2021-06-26 21:22:52 -04:00
Dan Mulloy 7a8fce224e Set mc object regex in 1.17
Fixes #1271
2021-06-26 20:57:39 -04:00
Dan Mulloy 9ca7c91a76 Simplify packet registry 2021-06-24 17:14:00 -04:00
Dan Mulloy 466354cd2c Cache list constructors to save on exceptions 2021-06-24 17:13:40 -04:00
Dan Mulloy 99504dab8f Abstract out structure modifiers to allow internal structures to be read 2021-06-24 17:13:05 -04:00
Dan Mulloy 9b6603e2eb Use fuzzy reflection for effect types 2021-06-21 16:10:58 -04:00
Dan Mulloy 4fc476a125 Use right int 2 object map class for Paper
Addresses #1217
2021-06-20 12:42:41 -04:00
Dan Mulloy 583ed4b58a Update scoreboard team class
Addresses #1232
2021-06-20 12:35:03 -04:00
Dan Mulloy 638e81b9ce Merge branch 'master' of https://github.com/dmulloy2/ProtocolLib 2021-06-20 12:08:52 -04:00
Dan Mulloy 9a0703d05d Fix attribute builder in 1.17
Addresses #1224
2021-06-20 12:08:47 -04:00
Pasqual Koschmieder 9de096f783 Fix sdk command for jitpack builds (#1241) 2021-06-20 11:51:55 -04:00
Dan Mulloy c54a99945d Try fixing some of the unit tests 2021-06-19 22:45:17 -04:00
Pasqual Koschmieder 90a38cc15c Restore backwards compatibility (#1235)
* Remove usages of net.minecraft and craftbukkit
* Restore packet type backward compatibility (tested on 1.8)
* Re-add last removed packets
* Fix sub class naming for newer minecraft versions
2021-06-19 22:20:54 -04:00
Dan Mulloy 76930ae6e8 Remove travis
It's gonna be a lot of work to build, so we're just gonna use GitHub actions
2021-06-19 22:15:03 -04:00
Pasqual Koschmieder d745cfb184 Switch to GH-Workflow & use java 16 on jitpack builds (#1236)
* Add github actions workflow
* Add jitpack.yml to configure java version
2021-06-19 22:11:12 -04:00
Dan Mulloy 4be2bf38ff Switch from travis-ci.org to .com 2021-06-18 10:53:17 -04:00
Pasqual Koschmieder 0a32f24f08 Fix EntityUseAction & Hand read for minecraft 1.17 (#1230) 2021-06-18 10:47:48 -04:00
Dan Mulloy 1c2bc274dd Fix differently mapped fastutil classes in Paper
Fixes #1228
2021-06-16 18:22:53 -04:00
Dan Mulloy 9b54794f6b Fix cloning in 1.17
Addresses #1222
2021-06-15 23:58:40 -04:00
Dan Mulloy 42bec5a858 Fix entity trackers in 1.17
Addresses #1217
2021-06-15 18:39:34 -04:00
Dan Mulloy fa317c1167 Working on live server 2021-06-14 16:36:22 -04:00
Dan Mulloy cc17b9ee6e Finish up unit tests 2021-06-13 17:18:36 -04:00
Dan Mulloy 190ca1ff6a Almost there, /theoretically/ 2021-06-13 15:57:23 -04:00
Dan Mulloy c51930121f Fix a bunch more classpaths
Also worked on fixing some wrappers
2021-06-13 11:36:44 -04:00
Dan Mulloy c7a8d734d4 Fix some more class paths 2021-06-12 23:53:09 -04:00
Dan Mulloy b446cf2183 Update unit tests to 1.17, fix packet lookups 2021-06-12 15:28:01 -04:00
Dan Mulloy f11c246276 Deprecate SocketInjector#getSocket (see #1188) 2021-06-04 18:24:30 -04:00
Camotoy 6f91bd23de Remove inferences of SocketChannel presence in temporary player (#1188)
To note: this is yet another compatibility change for my Geyser work, but https://github.com/PaperMC/Paper/pull/5611 will also break without these changes as Unix domain sockets don't implement SocketChannel.

The temporary player method delegation directed the isOnline and getName methods to functions that require the channel to be an instance of SocketChannel, when this won't always be the case. To solve this, this PR redirects `getSocket().getRemoteSocketAddress()` to `injector.getAddress()` which returns the same value. To determine if the player is online, a new method is created in SocketInjector to determine if a connection is online (which also returns the same value as before this commit).
2021-06-04 18:21:48 -04:00
Pim van der Loos 45c293df7d Update ByteBuddy dependency (#1156)
- Updated ByteBuddy dependency to add support for Java 17 (introduced in 1.10.21) and to take advantage of any fixes and improvements made between versions.
2021-05-29 13:01:45 -04:00
Camotoy 5acdb2b3c5 Mark connectionHandler as sharable (#1179)
Fixes #1170.

The reasoning for this PR is largely outlined in the above issue. As the ChannelInboundHandlerAdapter has no private class, a race condition cannot occur and therefore marking the class as sharable should incur no cost.
2021-05-29 13:00:58 -04:00
Camotoy 72c1f3e26c Redirect #mcdevs link to libera.chat (#1181)
The #mcdevs IRC channel is in the process of migrating away from Freenode.
2021-05-29 12:59:26 -04:00
Minecrell b3ccf82597 WrappedServerPing: Properly translate MotD to components for RGB colors (#1152)
In previous Minecraft versions, using WrappedServerPing.setMotD(String)
behaved exactly like using Bukkit's ServerListPingEvent.setMotd(String).

With the addition of RGB colors in Minecraft 1.16, Spigot's
ServerListPingEvent was patched to translate the MotD string to the
chat component equivalent to make it possible to use RGB colors in MotDs.
In general, using raw legacy color codes (e.g. §c) within a (JSON) text
component tends to cause weird issues on newer Minecraft versions,
so it's better to translate them to the JSON equivalents on the server.

However, the WrappedServerPing implementation in ProtocolLib was never
updated with the same change, which makes it behave differently from
Spigot's ServerListPingEvent now. Using ServerListPingEvent RGB color
codes work, using ProtocolLib they do not work.

To fix this, this commit changes WrappedServerPing.setMotD(String) to
use the same method as Spigot for translating the legacy text to the
JSON/chat component equivalent.

This allows for example ServerListPlus to use Spigot's RGB color codes
(e.g. &x&7&9&b&8&f&fHello) without requiring any changes in ServerListPlus.
2021-05-02 17:43:32 -04:00
LewUwU 0c01a11755 Fixed protocol injection with latest netty on minecraft 1.11 and below (#1067) 2021-05-01 15:51:52 -04:00
Pim van der Loos 7ce3f471bf Add support for Java 16 (#1120)
Switched from the now-unavailable ClassLoader::defineClass method to the java.lang.invoke.MethodHandles.Lookup::defineClass. This is available on Java 9+.
2021-04-04 23:03:05 -04:00
Dan Mulloy 97972acee8 Add converter for game state ids
Fixes #1041
2021-02-27 15:38:05 -05:00
LOOHP a0bb11e1bd Add support for PaperMC's new Adventure API Component (#1103) 2021-02-27 14:15:43 -05:00
Dan Mulloy ba74fceed6 Update version to 4.6.1-SNAPSHOT 2021-02-27 14:15:01 -05:00
84 changed files with 4510 additions and 2414 deletions

No files matched your search

+2 -2
View File
@@ -19,7 +19,7 @@ This page will detail specific things that must be done if you intend to contrib
#### Ready? Let's get started!
1. Read the [Protocol Changes](http://wiki.vg/Protocol_History). Always make sure the list is both
complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [freenode.net](http://freenode.net)
complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [libera.chat](http://libera.chat)
or #spigot on [irc.spi.gt](http://irc.spi.gt) ([webchat](https://irc.spi.gt/iris/?channels=spigot)).
2. Search for usages of the now-defunct NMS package guard and change them.
3. The class `com.comphenix.protocol.PacketType` contains a list of all the packets. If any packets were added or removed
@@ -35,4 +35,4 @@ and the release date.
8. `com.comphenix.protocol.utility.MinecraftProtocolVersion` contains a map of all the protocol version integers.
If the protocol version has been incremented, add a new line to the map.
9. `mvn` in root directory again. If it builds successfully, test on the appropriate version of a Spigot server. If
the build fails, debug!
the build fails, debug!
+26
View File
@@ -0,0 +1,26 @@
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: 'adopt'
java-version: '16'
check-latest: true
- 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
-11
View File
@@ -1,11 +0,0 @@
language: java
jdk:
- openjdk8
script: mvn clean test
install: true
notifications:
email:
recipients:
- "dmulloy2@live.com"
on_success: change
on_failure: always
+1 -1
View File
@@ -1,4 +1,4 @@
# ProtocolLib [![Travis Status](https://travis-ci.org/dmulloy2/ProtocolLib.svg?branch=master)](https://travis-ci.org/dmulloy2/ProtocolLib)
# ProtocolLib
Certain tasks are impossible to perform with the standard Bukkit API, and may require
working with and even modify Minecraft directly. A common technique is to modify incoming
+5
View File
@@ -0,0 +1,5 @@
before_install:
- source "$HOME/.sdkman/bin/sdkman-init.sh"
- sdk update
- sdk install java 16.0.1.hs-adpt
- sdk use java 16.0.1.hs-adpt
+17 -8
View File
@@ -4,7 +4,7 @@
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<name>ProtocolLib</name>
<version>4.6.0</version>
<version>4.7.0-SNAPSHOT</version>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>https://github.com/dmulloy2/ProtocolLib</url>
@@ -17,7 +17,7 @@
<project.fullVersion>${project.version}</project.fullVersion>
<powermock.version>2.0.7</powermock.version>
<spigot.version>1.16.4-R0.1-SNAPSHOT</spigot.version>
<spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version>
</properties>
<build>
@@ -108,6 +108,9 @@
<value>${project.version}</value>
</property>
</systemProperties>
<!-- TODO figure out a better way to do this before Java 17 -->
<!-- We're currently waiting on powermock, but we may need to switch -->
<argLine>--illegal-access=permit</argLine>
</configuration>
</plugin>
@@ -147,8 +150,8 @@
</activation>
<properties>
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
<!--<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>-->
<project.fullVersion>${project.version}</project.fullVersion>
<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>
<!--<project.fullVersion>${project.version}</project.fullVersion>-->
</properties>
</profile>
@@ -254,18 +257,18 @@
<distributionManagement>
<repository>
<id>dmulloy2-releases</id>
<url>https://repo.dmulloy2.net/nexus/repository/releases/</url>
<url>https://repo.dmulloy2.net/repository/releases/</url>
</repository>
<snapshotRepository>
<id>dmulloy2-snapshots</id>
<url>https://repo.dmulloy2.net/nexus/repository/snapshots/</url>
<url>https://repo.dmulloy2.net/repository/snapshots/</url>
</snapshotRepository>
</distributionManagement>
<repositories>
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/nexus/repository/public/</url>
<url>https://repo.dmulloy2.net/repository/public/</url>
</repository>
<repository>
<id>spigot-repo</id>
@@ -293,11 +296,17 @@
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId>
<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.10.16</version>
<version>1.11.0</version>
</dependency>
<!-- Testing dependencies -->
@@ -11,6 +11,7 @@ import java.util.function.Consumer;
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.utility.Constants;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Preconditions;
@@ -107,93 +108,104 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x02, "SpawnEntityLiving", "SPacketSpawnMob");
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x03, "SpawnEntityPainting", "SPacketSpawnPainting");
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x04, "NamedEntitySpawn", "SPacketSpawnPlayer");
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x05, "Animation", "SPacketAnimation");
public static final PacketType STATISTIC = new PacketType(PROTOCOL, SENDER, 0x06, "Statistic", "SPacketStatistics");
public static final PacketType BLOCK_BREAK = new PacketType(PROTOCOL, SENDER, 0x07, "BlockBreak");
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x08, "BlockBreakAnimation", "SPacketBlockBreakAnim");
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x09, "TileEntityData", "SPacketUpdateTileEntity");
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x0A, "BlockAction", "SPacketBlockAction");
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x0B, "BlockChange", "SPacketBlockChange");
public static final PacketType BOSS = new PacketType(PROTOCOL, SENDER, 0x0C, "Boss", "SPacketUpdateBossInfo");
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x0D, "ServerDifficulty", "SPacketServerDifficulty");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x0E, "Chat", "SPacketChat");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x0F, "TabComplete", "SPacketTabComplete");
public static final PacketType COMMANDS = new PacketType(PROTOCOL, SENDER, 0x10, "Commands");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x11, "Transaction", "SPacketConfirmTransaction");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x12, "CloseWindow", "SPacketCloseWindow");
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x13, "WindowItems", "SPacketWindowItems");
public static final PacketType WINDOW_DATA = new PacketType(PROTOCOL, SENDER, 0x14, "WindowData", "SPacketWindowProperty");
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x15, "SetSlot", "SPacketSetSlot");
public static final PacketType SET_COOLDOWN = new PacketType(PROTOCOL, SENDER, 0x16, "SetCooldown", "SPacketCooldown");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x17, "CustomPayload", "SPacketCustomPayload");
public static final PacketType CUSTOM_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x18, "CustomSoundEffect", "SPacketCustomSound");
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x19, "KickDisconnect", "SPacketDisconnect");
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1A, "EntityStatus", "SPacketEntityStatus");
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x1B, "Explosion", "SPacketExplosion");
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x1C, "UnloadChunk", "SPacketUnloadChunk");
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x1D, "GameStateChange", "SPacketChangeGameState");
public static final PacketType OPEN_WINDOW_HORSE = new PacketType(PROTOCOL, SENDER, 0x1E, "OpenWindowHorse");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x1F, "KeepAlive", "SPacketKeepAlive");
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x20, "MapChunk", "SPacketChunkData");
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x21, "WorldEvent", "SPacketEffect");
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x22, "WorldParticles", "SPacketParticles");
public static final PacketType LIGHT_UPDATE = new PacketType(PROTOCOL, SENDER, 0x23, "LightUpdate");
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x24, "Login", "SPacketJoinGame");
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x25, "Map", "SPacketMaps");
public static final PacketType OPEN_WINDOW_MERCHANT = new PacketType(PROTOCOL, SENDER, 0x26, "OpenWindowMerchant");
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x27, "Entity$RelEntityMove", "SPacketEntity$S15PacketEntityRelMove");
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x28, "Entity$RelEntityMoveLook", "SPacketEntity$S17PacketEntityLookMove");
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x29, "Entity$EntityLook", "SPacketEntity$S16PacketEntityLook");
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x2A, "Entity", "SPacketEntity");
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x2B, "VehicleMove", "SPacketMoveVehicle");
public static final PacketType OPEN_BOOK = new PacketType(PROTOCOL, SENDER, 0x2C, "OpenBook");
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2D, "OpenWindow", "SPacketOpenWindow");
public static final PacketType OPEN_SIGN_EDITOR = new PacketType(PROTOCOL, SENDER, 0x2E, "OpenSignEditor", "SPacketSignEditorOpen");
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x2F, "AutoRecipe", "SPacketPlaceGhostRecipe");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x30, "Abilities", "SPacketPlayerAbilities");
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 0x31, "CombatEvent", "SPacketCombatEvent");
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x32, "PlayerInfo", "SPacketPlayerListItem");
public static final PacketType LOOK_AT = new PacketType(PROTOCOL, SENDER, 0x33, "LookAt", "SPacketPlayerPosLook");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x34, "Position");
public static final PacketType RECIPES = new PacketType(PROTOCOL, SENDER, 0x35, "Recipes", "SPacketRecipeBook");
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x36, "EntityDestroy", "SPacketDestroyEntities");
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x37, "RemoveEntityEffect", "SPacketRemoveEntityEffect");
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x38, "ResourcePackSend", "SPacketResourcePackSend");
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x39, "Respawn", "SPacketRespawn");
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x3A, "EntityHeadRotation", "SPacketEntityHeadLook");
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x3B, "MultiBlockChange", "SPacketMultiBlockChange");
public static final PacketType SELECT_ADVANCEMENT_TAB = new PacketType(PROTOCOL, SENDER, 0x3C, "SelectAdvancementTab", "SPacketSelectAdvancementsTab");
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 0x3D, "WorldBorder", "SPacketWorldBorder");
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x3E, "Camera", "SPacketCamera");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x3F, "HeldItemSlot", "SPacketHeldItemChange");
public static final PacketType VIEW_CENTRE = new PacketType(PROTOCOL, SENDER, 0x40, "ViewCentre");
public static final PacketType VIEW_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x41, "ViewDistance");
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x42, "SpawnPosition", "SPacketSpawnPosition");
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x43, "ScoreboardDisplayObjective", "SPacketDisplayObjective");
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x44, "EntityMetadata", "SPacketEntityMetadata");
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x45, "AttachEntity", "SPacketEntityAttach");
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x46, "EntityVelocity", "SPacketEntityVelocity");
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x47, "EntityEquipment", "SPacketEntityEquipment");
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x48, "Experience", "SPacketSetExperience");
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x49, "UpdateHealth", "SPacketUpdateHealth");
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x4A, "ScoreboardObjective", "SPacketScoreboardObjective");
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x4B, "Mount", "SPacketSetPassengers");
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x4C, "ScoreboardTeam", "SPacketTeams");
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x4D, "ScoreboardScore", "SPacketUpdateScore");
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x4E, "UpdateTime", "SPacketTimeUpdate");
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x4F, "Title", "SPacketTitle");
public static final PacketType ENTITY_SOUND = new PacketType(PROTOCOL, SENDER, 0x50, "EntitySound", "SPacketSoundEffect");
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x51, "NamedSoundEffect");
public static final PacketType STOP_SOUND = new PacketType(PROTOCOL, SENDER, 0x52, "StopSound");
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x53, "PlayerListHeaderFooter", "SPacketPlayerListHeaderFooter");
public static final PacketType NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x54, "NBTQuery");
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x55, "Collect", "SPacketCollectItem");
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x56, "EntityTeleport", "SPacketEntityTeleport");
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x57, "Advancements", "SPacketAdvancementInfo");
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x58, "UpdateAttributes", "SPacketEntityProperties");
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x59, "EntityEffect", "SPacketEntityEffect");
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x5A, "RecipeUpdate");
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x5B, "Tags");
public static final PacketType ADD_VIBRATION_SIGNAL = new PacketType(PROTOCOL, SENDER, 0x05, "AddVibrationSignal");
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x06, "Animation", "SPacketAnimation");
public static final PacketType STATISTIC = new PacketType(PROTOCOL, SENDER, 0x07, "Statistic", "SPacketStatistics");
public static final PacketType BLOCK_BREAK = new PacketType(PROTOCOL, SENDER, 0x08, "BlockBreak");
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x09, "BlockBreakAnimation", "SPacketBlockBreakAnim");
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x0A, "TileEntityData", "SPacketUpdateTileEntity");
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x0B, "BlockAction", "SPacketBlockAction");
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x0C, "BlockChange", "SPacketBlockChange");
public static final PacketType BOSS = new PacketType(PROTOCOL, SENDER, 0x0D, "Boss", "SPacketUpdateBossInfo");
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x0E, "ServerDifficulty", "SPacketServerDifficulty");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x0F, "Chat", "SPacketChat");
public static final PacketType CLEAR_TITLES = new PacketType(PROTOCOL, SENDER, 0x10, "ClearTitles");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x11, "TabComplete", "SPacketTabComplete");
public static final PacketType COMMANDS = new PacketType(PROTOCOL, SENDER, 0x12, "Commands");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x13, "CloseWindow", "SPacketCloseWindow");
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x14, "WindowItems", "SPacketWindowItems");
public static final PacketType WINDOW_DATA = new PacketType(PROTOCOL, SENDER, 0x15, "WindowData", "SPacketWindowProperty");
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x16, "SetSlot", "SPacketSetSlot");
public static final PacketType SET_COOLDOWN = new PacketType(PROTOCOL, SENDER, 0x17, "SetCooldown", "SPacketCooldown");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x18, "CustomPayload", "SPacketCustomPayload");
public static final PacketType CUSTOM_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x19, "CustomSoundEffect", "SPacketCustomSound");
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x1A, "KickDisconnect", "SPacketDisconnect");
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1B, "EntityStatus", "SPacketEntityStatus");
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x1C, "Explosion", "SPacketExplosion");
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x1D, "UnloadChunk", "SPacketUnloadChunk");
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x1E, "GameStateChange", "SPacketChangeGameState");
public static final PacketType OPEN_WINDOW_HORSE = new PacketType(PROTOCOL, SENDER, 0x1F, "OpenWindowHorse");
public static final PacketType INITIALIZE_BORDER = new PacketType(PROTOCOL, SENDER, 0x20, "InitializeBorder");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x21, "KeepAlive", "SPacketKeepAlive");
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x22, "MapChunk", "SPacketChunkData");
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 SET_SUBTITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x57, "SetSubtitleText");
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x58, "UpdateTime", "SPacketTimeUpdate");
public static final PacketType SET_TITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x59, "SetTitleText");
public static final PacketType SET_TITLES_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x5A, "SetTitlesAnimation");
public static final PacketType ENTITY_SOUND = new PacketType(PROTOCOL, SENDER, 0x5B, "EntitySound", "SPacketSoundEffect");
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x5C, "NamedSoundEffect");
public static final PacketType STOP_SOUND = new PacketType(PROTOCOL, SENDER, 0x5D, "StopSound");
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x5E, "PlayerListHeaderFooter", "SPacketPlayerListHeaderFooter");
public static final PacketType NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x5F, "NBTQuery");
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x60, "Collect", "SPacketCollectItem");
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x61, "EntityTeleport", "SPacketEntityTeleport");
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x62, "Advancements", "SPacketAdvancementInfo");
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x63, "UpdateAttributes", "SPacketEntityProperties");
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x64, "EntityEffect", "SPacketEntityEffect");
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x65, "RecipeUpdate");
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x66, "Tags");
// ---- Removed in 1.9
@@ -256,7 +268,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @deprecated Removed in 1.14
*/
@Deprecated
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x33, "Bed", "SPacketUseBed");
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 251, "Bed", "SPacketUseBed");
/**
* @deprecated Renamed to {@link #BED}
@@ -268,7 +280,37 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @deprecated Removed in 1.16
*/
@Deprecated
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x02, "SpawnEntityWeather", "SPacketSpawnGlobalEntity");
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 250, "SpawnEntityWeather", "SPacketSpawnGlobalEntity");
/**
* @deprecated Removed in 1.17, split into separate packets
*/
@Deprecated
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 249, "Title");
/**
* @deprecated Removed in 1.17, split into separate packets
*/
@Deprecated
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 248, "WorldBorder");
/**
* @deprecated Removed in 1.17, split into separate packets
*/
@Deprecated
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 247, "CombatEvent");
/**
* @deprecated Removed in 1.17
*/
@Deprecated
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 246, "Transaction", "SPacketConfirmTransaction");
/**
* @deprecated Made abstract in 1.17, no actual packet anymore
*/
@Deprecated
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 245, "Entity", "SPacketEntity");
private final static Server INSTANCE = new Server();
@@ -297,29 +339,29 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x04, "ClientCommand", "CPacketClientStatus");
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x05, "Settings", "CPacketClientSettings");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x06, "TabComplete", "CPacketTabComplete");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x07, "Transaction", "CPacketConfirmTransaction");
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x08, "EnchantItem", "CPacketEnchantItem");
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x09, "WindowClick", "CPacketClickWindow");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x0A, "CloseWindow", "CPacketCloseWindow");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x0B, "CustomPayload", "CPacketCustomPayload");
public static final PacketType B_EDIT = new PacketType(PROTOCOL, SENDER, 0x0C, "BEdit");
public static final PacketType ENTITY_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x0D, "EntityNBTQuery");
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0E, "UseEntity", "CPacketUseEntity");
public static final PacketType JIGSAW_GENERATE = new PacketType(PROTOCOL, SENDER, 0x0F, "JigsawGenerate");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x10, "KeepAlive", "CPacketKeepAlive");
public static final PacketType DIFFICULTY_LOCK = new PacketType(PROTOCOL, SENDER, 0x11, "DifficultyLock");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x12, "Flying$Position", "CPacketPlayer$Position");
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x13, "Flying$PositionLook", "CPacketPlayer$PositionRotation");
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x14, "Flying$Look", "CPacketPlayer$Rotation");
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x15, "Flying", "CPacketPlayer");
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x16, "VehicleMove", "CPacketVehicleMove");
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x17, "BoatMove", "CPacketSteerBoat");
public static final PacketType PICK_ITEM = new PacketType(PROTOCOL, SENDER, 0x18, "PickItem");
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x19, "AutoRecipe", "CPacketPlaceRecipe");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x1A, "Abilities", "CPacketPlayerAbilities");
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x1B, "BlockDig", "CPacketPlayerDigging");
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x1C, "EntityAction", "CPacketEntityAction");
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x1D, "SteerVehicle", "CPacketInput");
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x07, "EnchantItem", "CPacketEnchantItem");
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x08, "WindowClick", "CPacketClickWindow");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x09, "CloseWindow", "CPacketCloseWindow");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x0A, "CustomPayload", "CPacketCustomPayload");
public static final PacketType B_EDIT = new PacketType(PROTOCOL, SENDER, 0x0B, "BEdit");
public static final PacketType ENTITY_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x0C, "EntityNBTQuery");
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0D, "UseEntity", "CPacketUseEntity");
public static final PacketType JIGSAW_GENERATE = new PacketType(PROTOCOL, SENDER, 0x0E, "JigsawGenerate");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x0F, "KeepAlive", "CPacketKeepAlive");
public static final PacketType DIFFICULTY_LOCK = new PacketType(PROTOCOL, SENDER, 0x10, "DifficultyLock");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x11, "Flying$PacketPlayInPosition", "Flying$Position", "CPacketPlayer$Position");
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x12, "Flying$PacketPlayInPositionLook", "Flying$PositionLook", "CPacketPlayer$PositionRotation");
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x13, "Flying$PacketPlayInLook", "Flying$Look", "CPacketPlayer$Rotation");
public static final PacketType GROUND = new PacketType(PROTOCOL, SENDER, 0x14, "Flying$d");
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x15, "VehicleMove", "CPacketVehicleMove");
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x16, "BoatMove", "CPacketSteerBoat");
public static final PacketType PICK_ITEM = new PacketType(PROTOCOL, SENDER, 0x17, "PickItem");
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x18, "AutoRecipe", "CPacketPlaceRecipe");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x19, "Abilities", "CPacketPlayerAbilities");
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x1A, "BlockDig", "CPacketPlayerDigging");
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x1B, "EntityAction", "CPacketEntityAction");
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x1C, "SteerVehicle", "CPacketInput");
public static final PacketType PONG = new PacketType(PROTOCOL, SENDER, 0x1D, "Pong", "ServerboundPongPacket");
public static final PacketType RECIPE_SETTINGS = new PacketType(PROTOCOL, SENDER, 0x1E, "RecipeSettings");
public static final PacketType RECIPE_DISPLAYED = new PacketType(PROTOCOL, SENDER, 0x1F, "RecipeDisplayed", "CPacketRecipeInfo");
public static final PacketType ITEM_NAME = new PacketType(PROTOCOL, SENDER, 0x20, "ItemName");
@@ -339,6 +381,18 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x2E, "UseItem", "CPacketPlayerTryUseItemOnBlock");
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x2F, "BlockPlace", "CPacketPlayerTryUseItem");
/**
* @deprecated Removed in 1.17
*/
@Deprecated
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 255, "Transaction", "CPacketConfirmTransaction");
/**
* @deprecated Removed in 1.17
*/
@Deprecated
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 254, "Flying", "CPacketPlayer");
private final static Client INSTANCE = new Client();
// Prevent accidental construction
@@ -490,15 +544,23 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @author Kristian
*/
public enum Protocol {
HANDSHAKING,
PLAY,
STATUS,
LOGIN,
HANDSHAKING("Handshaking", "handshake"),
PLAY("Play", "game"),
STATUS("Status", "status"),
LOGIN("Login", "login"),
/**
* Only for packets removed in Minecraft 1.7.2
*/
LEGACY;
LEGACY("", "");
private String packetName;
private String mojangName;
Protocol(String packetName, String mojangName) {
this.packetName = packetName;
this.mojangName = mojangName;
}
/**
* Retrieve the correct protocol enum from a given vanilla enum instance.
@@ -520,7 +582,11 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
}
public String getPacketName() {
return WordUtils.capitalize(name().toLowerCase(Locale.ENGLISH));
return packetName;
}
public String getMojangName() {
return mojangName;
}
public String getMcpPacketName() {
@@ -537,12 +603,22 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
/**
* Indicates that packets of this type will be sent by connected clients.
*/
CLIENT,
CLIENT("Serverbound", "In", "client"),
/**
* Indicate that packets of this type will be sent by the current server.
*/
SERVER;
SERVER("Clientbound", "Out", "server");
private String mojangName;
private String packetName;
private String mcpName;
Sender(String mojangName, String packetName, String mcpName) {
this.mojangName = mojangName;
this.packetName = packetName;
this.mcpName = mcpName;
}
/**
* Retrieve the equivialent connection side.
@@ -553,11 +629,15 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
}
public String getPacketName() {
return this == CLIENT ? "In" : "Out";
return packetName;
}
public String getMcpPacketName() {
return name().toLowerCase(Locale.ENGLISH);
return mcpName;
}
public String getMojangName() {
return mojangName;
}
}
@@ -574,13 +654,13 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
/**
* Protocol version of all the current IDs.
*/
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.NETHER_UPDATE;
private static final MinecraftVersion PROTOCOL_VERSION = Constants.CURRENT_VERSION;
private final Protocol protocol;
private final Sender sender;
private final int currentId;
private final MinecraftVersion version;
private final String[] classNames;
private final List<String> classNames;
String[] names;
private String name;
@@ -710,7 +790,17 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
}
}
private static String formatMojangClassName(Protocol protocol, Sender sender, String name) {
return "net.minecraft.network.protocol." + protocol.getMojangName() + "." + sender.getMojangName()
+ name + "Packet";
}
private static String formatClassName(Protocol protocol, Sender sender, String name) {
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
return "net.minecraft.network.protocol." + protocol.getMojangName() + ".Packet"
+ protocol.getPacketName() + sender.getPacketName() + name;
}
String base = MinecraftReflection.getMinecraftPackage() + ".Packet";
if (name.startsWith(base)) {
return name;
@@ -810,8 +900,8 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
// Check any aliases
for (PacketType check : map.values()) {
String[] aliases = check.getClassNames();
if (aliases.length > 1) {
List<String> aliases = check.getClassNames();
if (aliases.size() > 1) {
for (String alias : aliases) {
if (alias.equals(clazz)) {
// We have a match!
@@ -852,7 +942,9 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* Determine if a given class represents a packet class.
* @param packetClass - the class to lookup.
* @return TRUE if this is a packet class, FALSE otherwise.
* @deprecated Doesn't really have a purpose
*/
@Deprecated
public static boolean hasClass(Class<?> packetClass) {
return PacketRegistry.getPacketType(packetClass) != null;
}
@@ -931,12 +1023,13 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
this.currentId = currentId;
this.version = version;
this.classNames = new String[names.length];
for (int i = 0; i < classNames.length; i++) {
this.classNames = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
if (isMcpPacketName(names[i])) { // Minecraft MCP packets
classNames[i] = formatMcpClassName(protocol, sender, names[i]);
classNames.add(formatMcpClassName(protocol, sender, names[i]));
} else {
classNames[i] = formatClassName(protocol, sender, names[i]);
classNames.add(formatClassName(protocol, sender, names[i]));
classNames.add(formatMojangClassName(protocol, sender, names[i]));
}
}
@@ -997,7 +1090,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
return currentId;
}
public String[] getClassNames() {
public List<String> getClassNames() {
return classNames;
}
@@ -1006,11 +1099,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
* @return The packet class, or NULL if not found.
*/
public Class<?> getPacketClass() {
try {
return PacketRegistry.getPacketClassFromType(this);
} catch (Exception e) {
return null;
}
return PacketRegistry.tryGetPacketClass(this).orElse(null);
}
// Only used by Enum processor
@@ -1112,7 +1201,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
Class<?> clazz = getPacketClass();
if (clazz == null)
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + Arrays.toString(classNames) + " (unregistered)]";
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + classNames + " (unregistered)]";
else
return name() + "[class=" + clazz.getSimpleName() + ", id=" + currentId + "]";
}
@@ -110,22 +110,6 @@ public class PacketTypeEnum implements Iterable<PacketType> {
public boolean hasMember(PacketType member) {
return members.contains(member);
}
/**
* Retrieve a member by name,
* @param name - name of member to retrieve.
* @return The member, or NULL if not found.
* @deprecated Don't use this
*/
@Deprecated
public PacketType valueOf(String name) {
for (PacketType member : members) {
if (member.name().equals(name))
return member;
}
return null;
}
/**
* Retrieve every registered member.
@@ -108,7 +108,7 @@ class PacketTypeLookup {
// Skip unknown current packets
if (type.getCurrentId() != PacketType.UNKNOWN_PACKET) {
idLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames()[0], type);
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames().get(0), type);
}
nameLookup.put(type.name(), type);
}
@@ -38,6 +38,7 @@ import com.comphenix.protocol.updater.Updater;
import com.comphenix.protocol.updater.Updater.UpdateType;
import com.comphenix.protocol.utility.ChatExtensions;
import com.comphenix.protocol.utility.ByteBuddyFactory;
import com.comphenix.protocol.utility.NettyVersion;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
@@ -170,7 +171,11 @@ public class ProtocolLib extends JavaPlugin {
// Print the state of the debug mode
if (config.isDebug()) {
logger.warning("Debug mode is enabled!");
logger.info("Detected netty version: " + NettyVersion.getVersion());
} else {
NettyVersion.getVersion(); // this will cache the version
}
// And the state of the error reporter
if (config.isDetailedErrorReporting()) {
detailedReporter.setDetailedReporting(true);
@@ -38,12 +38,12 @@ public class ProtocolLibrary {
/**
* The maximum version ProtocolLib has been tested with.
*/
public static final String MAXIMUM_MINECRAFT_VERSION = "1.16.5";
public static final String MAXIMUM_MINECRAFT_VERSION = "1.17.1";
/**
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.16.5) was released.
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.17.1) was released.
*/
public static final String MINECRAFT_LAST_RELEASE_DATE = "2021-01-15";
public static final String MINECRAFT_LAST_RELEASE_DATE = "2021-07-06";
/**
* Plugins that are currently incompatible with ProtocolLib.
@@ -20,6 +20,7 @@ import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.comphenix.protocol.utility.MinecraftVersion;
import org.bukkit.plugin.Plugin;
/**
@@ -82,4 +83,10 @@ public class ProtocolLogger {
logger.log(Level.WARNING, "[Debug] " + message, ex);
}
}
public static void warnAbove(MinecraftVersion version, String message, Object... args) {
if (version.atOrAbove()) {
log(Level.WARNING, message, args);
}
}
}
@@ -32,11 +32,11 @@ public class PacketTypeSet {
* @param type - the type to add.
*/
public synchronized void addType(PacketType type) {
Class<?> packetClass = getPacketClass(type);
Class<?> packetClass = type.getPacketClass();
types.add(Preconditions.checkNotNull(type, "type cannot be NULL."));
if (packetClass != null) {
classes.add(getPacketClass(type));
classes.add(type.getPacketClass());
}
}
@@ -55,11 +55,11 @@ public class PacketTypeSet {
* @param type - the type to remove.
*/
public synchronized void removeType(PacketType type) {
Class<?> packetClass = getPacketClass(type);
Class<?> packetClass = type.getPacketClass();
types.remove(Preconditions.checkNotNull(type, "type cannot be NULL."));
if (packetClass != null) {
classes.remove(getPacketClass(type));
classes.remove(packetClass);
}
}
@@ -72,16 +72,7 @@ public class PacketTypeSet {
removeType(type);
}
}
/**
* Retrieve the packet class associated with a particular type.
* @param type - the packet type.
* @return The associated packet type.
*/
protected Class<?> getPacketClass(PacketType type) {
return PacketRegistry.getPacketClassFromType(type);
}
/**
* Determine if the given packet type exists in the set.
* @param type - the type to find.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,45 @@
package com.comphenix.protocol.events;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.Converters;
import java.util.List;
import java.util.Optional;
public class InternalStructure extends AbstractStructure {
protected InternalStructure(Object handle, StructureModifier<Object> structureModifier) {
super(handle, structureModifier);
}
protected static final EquivalentConverter<InternalStructure> CONVERTER = new EquivalentConverter<InternalStructure>() {
@Override
public Object getGeneric(InternalStructure specific) {
return specific.handle;
}
@Override
public InternalStructure getSpecific(Object generic) {
return new InternalStructure(generic, new StructureModifier<>(generic.getClass()).withTarget(generic));
}
@Override
public Class<InternalStructure> getSpecificType() {
return InternalStructure.class;
}
};
public StructureModifier<InternalStructure> getStructures() {
return structureModifier.withType(Object.class, CONVERTER);
}
public StructureModifier<Optional<InternalStructure>> getOptionalStructures() {
return structureModifier.withType(Optional.class, Converters.optional(CONVERTER));
}
@Override
public String toString() {
return "InternalStructure[handle=" + handle + " (" + handle.getClass().getSimpleName() + ")]";
}
}
File diff suppressed because it is too large. Load diff
@@ -17,6 +17,7 @@
package com.comphenix.protocol.injector;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -139,7 +140,7 @@ class EntityUtilities {
@SuppressWarnings("unchecked")
private Object getNewEntityTracker(Object worldServer, int entityId) {
if (getChunkProvider == null) {
Class<?> chunkProviderClass = MinecraftReflection.getMinecraftClass("ChunkProviderServer");
Class<?> chunkProviderClass = MinecraftReflection.getChunkProviderServer();
getChunkProvider = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(worldServer.getClass(), false).getMethod(
FuzzyMethodContract.newBuilder().parameterCount(0).returnTypeExact(chunkProviderClass).build()));
@@ -148,7 +149,7 @@ class EntityUtilities {
Object chunkProvider = getChunkProvider.invoke(worldServer);
if (chunkMapField == null) {
Class<?> chunkMapClass = MinecraftReflection.getMinecraftClass("PlayerChunkMap");
Class<?> chunkMapClass = MinecraftReflection.getPlayerChunkMap();
chunkMapField = Accessors.getFieldAccessor(
FuzzyReflection.fromClass(chunkProvider.getClass(), false).getField(
FuzzyFieldContract.newBuilder().typeExact(chunkMapClass).build()));
@@ -157,9 +158,21 @@ class EntityUtilities {
Object playerChunkMap = chunkMapField.get(chunkProvider);
if (trackedEntitiesField == null) {
trackedEntitiesField = Accessors.getFieldAccessor(
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
trackedEntitiesField = Accessors.getFieldAccessor(
FuzzyReflection.fromClass(playerChunkMap.getClass(), true).getField(
FuzzyFieldContract.newBuilder()
.banModifier(Modifier.STATIC)
.requirePublic()
.typeExact(MinecraftReflection.getInt2ObjectMapClass())
.build()
)
);
} else {
trackedEntitiesField = Accessors.getFieldAccessor(
FuzzyReflection.fromClass(playerChunkMap.getClass(), false).getField(
FuzzyFieldContract.newBuilder().typeDerivedOf(Map.class).nameExact("trackedEntities").build()));
}
}
Map<Integer, Object> trackedEntities = (Map<Integer, Object>) trackedEntitiesField.get(playerChunkMap);
@@ -229,14 +242,17 @@ class EntityUtilities {
Object tracker = null;
if (trackerEntry != null) {
// plugins like citizens will use their own tracker
// plugins like citizens will use their own tracker class, so cache the result
FieldAccessor trackerField = trackerFields.computeIfAbsent(trackerEntry.getClass(), x -> {
// get the first entity field
try {
return Accessors.getFieldAccessor(trackerEntry.getClass(), "tracker", true);
} catch (Exception e) {
// Assume it's the first entity field then
return Accessors.getFieldAccessor(FuzzyReflection.fromObject(trackerEntry, true)
.getFieldByType("tracker", MinecraftReflection.getEntityClass()));
return Accessors.getFieldAccessor(FuzzyReflection.fromClass(trackerEntry.getClass(), true)
.getField(FuzzyFieldContract.newBuilder().typeExact(MinecraftReflection.getEntityClass()).build()));
} catch (Exception ex) {
// try with the default class
Class<?> trackerEntryClass = MinecraftReflection.getEntityTrackerClass();
return Accessors.getFieldAccessor(FuzzyReflection.fromClass(trackerEntryClass, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(MinecraftReflection.getEntityClass()).build()));
}
});
@@ -39,14 +39,6 @@ public interface ListenerInvoker {
*/
void invokePacketSending(PacketEvent event);
/**
* Retrieve the associated ID of a packet.
* @param packet - the packet.
* @return The packet ID.
*/
@Deprecated
int getPacketID(Object packet);
/**
* Retrieve the associated type of a packet.
* @param packet - the packet.
@@ -20,6 +20,7 @@ package com.comphenix.protocol.injector;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Optional;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.error.RethrowErrorReporter;
@@ -146,13 +147,11 @@ public class PacketConstructor {
types[i] = Object.class;
}
}
Class<?> packetType = PacketRegistry.getPacketClassFromType(type, true);
if (packetType == null)
throw new IllegalArgumentException("Could not find a packet by the type " + type);
Class<?> packetClass = PacketRegistry.getPacketClassFromType(type);
// Find the correct constructor
for (Constructor<?> constructor : packetType.getConstructors()) {
for (Constructor<?> constructor : packetClass.getConstructors()) {
Class<?>[] params = constructor.getParameterTypes();
if (isCompatible(types, params)) {
@@ -979,12 +979,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
return phaseLoginCount.get();
}
@Override
@Deprecated
public int getPacketID(Object packet) {
return PacketRegistry.getPacketID(packet.getClass());
}
@Override
public PacketType getPacketType(Object packet) {
if (packet == null)
@@ -19,17 +19,29 @@ package com.comphenix.protocol.injector;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
import com.comphenix.protocol.reflect.compiler.CompileListener;
import com.comphenix.protocol.reflect.compiler.CompiledStructureModifier;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.ByteBuddyFactory;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.ZeroBuffer;
import io.netty.buffer.ByteBuf;
import com.google.common.base.Preconditions;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;
/**
* Caches structure modifiers.
@@ -37,9 +49,42 @@ import com.comphenix.protocol.utility.MinecraftReflection;
*/
public class StructureCache {
// Structure modifiers
private static ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
private static final ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
// invocation cache for packets
private static final ConcurrentMap<Class<?>, Supplier<Object>> PACKET_INSTANCE_CREATORS = new ConcurrentHashMap<>();
// packet data serializer which always returns an empty nbt tag compound
private static boolean trickTried;
private static ConstructorAccessor TRICKED_DATA_SERIALIZER;
private static Set<PacketType> compiling = new HashSet<>();
private static final Set<PacketType> compiling = new HashSet<>();
public static Object newPacket(Class<?> clazz) {
Object result = DefaultInstances.DEFAULT.create(clazz);
if (result == null) {
return PACKET_INSTANCE_CREATORS.computeIfAbsent(clazz, $ -> {
ConstructorAccessor accessor = Accessors.getConstructorAccessorOrNull(clazz, MinecraftReflection.getPacketDataSerializerClass());
if (accessor != null) {
return () -> {
try {
return accessor.invoke(MinecraftReflection.getPacketDataSerializer(new ZeroBuffer()));
} catch (Exception exception) {
// try trick nms around as they want a non-null compound in the map_chunk packet constructor
ConstructorAccessor trickyDataSerializerAccessor = getTrickDataSerializerOrNull();
if (trickyDataSerializerAccessor != null) {
return accessor.invoke(trickyDataSerializerAccessor.invoke(new ZeroBuffer()));
}
// the tricks are over
throw new IllegalArgumentException("Unable to create packet " + clazz, exception);
}
};
}
throw new IllegalArgumentException("No matching constructor to create packet in class " + clazz);
}).get();
}
return result;
}
/**
* Creates an empty Minecraft packet of the given type.
@@ -47,20 +92,7 @@ public class StructureCache {
* @return Created packet.
*/
public static Object newPacket(PacketType type) {
Class<?> clazz = PacketRegistry.getPacketClassFromType(type, true);
// Check the return value
if (clazz != null) {
// TODO: Optimize DefaultInstances
Object result = DefaultInstances.DEFAULT.create(clazz);
if (result == null) {
throw new IllegalArgumentException("Failed to create packet for type: " + type);
}
return result;
}
throw new IllegalArgumentException("Cannot find associated packet class: " + type);
return newPacket(PacketRegistry.getPacketClassFromType(type));
}
/**
@@ -91,7 +123,9 @@ public class StructureCache {
*/
public static StructureModifier<Object> getStructure(Class<?> packetType, boolean compile) {
// Get the ID from the class
return getStructure(PacketRegistry.getPacketType(packetType), compile);
PacketType type = PacketRegistry.getPacketType(packetType);
Preconditions.checkNotNull(type, "No packet type associated with " + packetType);
return getStructure(type, compile);
}
/**
@@ -101,13 +135,14 @@ public class StructureCache {
* @return A structure modifier.
*/
public static StructureModifier<Object> getStructure(final PacketType type, boolean compile) {
Preconditions.checkNotNull(type, "type cannot be null");
StructureModifier<Object> result = structureModifiers.get(type);
// We don't want to create this for every lookup
if (result == null) {
// Use the vanilla class definition
final StructureModifier<Object> value = new StructureModifier<Object>(
PacketRegistry.getPacketClassFromType(type, true), MinecraftReflection.getPacketClass(), true);
final StructureModifier<Object> value = new StructureModifier<>(
PacketRegistry.getPacketClassFromType(type), MinecraftReflection.getPacketClass(), true);
result = structureModifiers.putIfAbsent(type, value);
@@ -124,16 +159,42 @@ public class StructureCache {
final BackgroundCompiler compiler = BackgroundCompiler.getInstance();
if (!compiling.contains(type) && compiler != null) {
compiler.scheduleCompilation(result, new CompileListener<Object>() {
@Override
public void onCompiled(StructureModifier<Object> compiledModifier) {
structureModifiers.put(type, compiledModifier);
}
});
compiler.scheduleCompilation(result,
compiledModifier -> structureModifiers.put(type, compiledModifier));
compiling.add(type);
}
}
}
return result;
}
/**
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a null
* check in the MapChunk packet constructor.
* @return an accessor to a constructor which creates a data serializer.
*/
private static ConstructorAccessor getTrickDataSerializerOrNull() {
if (TRICKED_DATA_SERIALIZER == null && !trickTried) {
// ensure that we only try once to create the class
trickTried = true;
try {
// create an empty instance of a nbt tag compound that we can re-use when needed
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
// create the method in the class to read an empty nbt tag compound (currently used for MAP_CHUNK because of null check)
Class<?> generatedClass = ByteBuddyFactory.getInstance()
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializer")
.method(ElementMatchers.returns(MinecraftReflection.getNBTCompoundClass())
.and(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())))
.intercept(FixedValue.value(compound))
.make()
.load(ByteBuddyFactory.getInstance().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
TRICKED_DATA_SERIALIZER = Accessors.getConstructorAccessor(generatedClass, ByteBuf.class);
} catch (Exception ignored) {
// can happen if unsupported
}
}
return TRICKED_DATA_SERIALIZER;
}
}
@@ -44,7 +44,6 @@ import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.AttributeKey;
@@ -951,7 +950,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
@Override
public Socket getSocket() {
return SocketAdapter.adapt((SocketChannel) injector.originalChannel);
return SocketAdapter.adapt(injector.originalChannel);
}
@Override
@@ -989,6 +988,11 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
injector.setPlayer(updatedPlayer);
}
@Override
public boolean isConnected() {
return injector.originalChannel.isActive();
}
ChannelInjector getChannelInjector() {
return injector;
}
@@ -1,222 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.injector.netty;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.Maps;
/**
* @author dmulloy2
*/
public class NettyProtocolRegistry extends ProtocolRegistry {
public NettyProtocolRegistry() {
super();
}
@Override
protected synchronized void initialize() {
if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BEE_UPDATE)) {
initializeNew();
return;
}
Object[] protocols = enumProtocol.getEnumConstants();
// ID to Packet class maps
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
Register result = new Register();
StructureModifier<Object> modifier = null;
// Iterate through the protocols
for (Object protocol : protocols) {
if (modifier == null) {
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
}
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
for (Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
String direction = entry.getKey().toString();
if (direction.contains("CLIENTBOUND")) { // Sent by Server
serverMaps.put(protocol, entry.getValue());
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
clientMaps.put(protocol, entry.getValue());
}
}
}
// Maps we have to occasionally check have changed
for (Object map : serverMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Object map : clientMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Object protocol : protocols) {
Enum<?> enumProtocol = (Enum<?>) protocol;
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
// Associate known types
if (serverMaps.containsKey(protocol))
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
if (clientMaps.containsKey(protocol))
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
}
// Exchange (thread safe, as we have only one writer)
this.register = result;
}
@SuppressWarnings("unchecked")
private synchronized void initializeNew() {
Object[] protocols = enumProtocol.getEnumConstants();
// ID to Packet class maps
Map<Object, Map<Class<?>, Integer>> serverMaps = Maps.newLinkedHashMap();
Map<Object, Map<Class<?>, Integer>> clientMaps = Maps.newLinkedHashMap();
Register result = new Register();
Field mainMapField = null;
Field packetMapField = null;
// Iterate through the protocols
for (Object protocol : protocols) {
if (mainMapField == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true);
mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
.banModifier(Modifier.STATIC)
.requireModifier(Modifier.FINAL)
.typeDerivedOf(Map.class)
.build());
mainMapField.setAccessible(true);
}
Map<Object, Object> directionMap;
try {
directionMap = (Map<Object, Object>) mainMapField.get(protocol);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to access packet map", ex);
}
for (Entry<Object, Object> entry : directionMap.entrySet()) {
Object holder = entry.getValue();
if (packetMapField == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(holder.getClass(), true);
packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
.banModifier(Modifier.STATIC)
.requireModifier(Modifier.FINAL)
.typeDerivedOf(Map.class)
.build());
packetMapField.setAccessible(true);
}
Map<Class<?>, Integer> packetMap;
try {
packetMap = (Map<Class<?>, Integer>) packetMapField.get(holder);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to access packet map", ex);
}
String direction = entry.getKey().toString();
if (direction.contains("CLIENTBOUND")) { // Sent by Server
serverMaps.put(protocol, packetMap);
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
clientMaps.put(protocol, packetMap);
}
}
}
// Maps we have to occasionally check have changed
// TODO: Find equivalent in Object2IntMap
/* for (Object map : serverMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Object map : clientMaps.values()) {
result.containers.add(new MapContainer(map));
} */
for (Object protocol : protocols) {
Enum<?> enumProtocol = (Enum<?>) protocol;
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
// Associate known types
if (serverMaps.containsKey(protocol)) {
associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER);
}
if (clientMaps.containsKey(protocol)) {
associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT);
}
}
// Exchange (thread safe, as we have only one writer)
this.register = result;
}
/**
* Reverses a key->value map to value->key
* Non-deterministic behavior when multiple keys are mapped to the same value
*/
private <K, V> Map<V, K> reverse(Map<K, V> map) {
Map<V, K> newMap = new HashMap<>(map.size());
for (Entry<K, V> entry : map.entrySet()) {
newMap.put(entry.getValue(), entry.getKey());
}
return newMap;
}
@Override
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
// System.out.println(Arrays.toString(type.getClassNames()) + " -> " + entry.getValue());
try {
register.typeToClass.put(type, entry.getValue());
if (sender == Sender.SERVER)
register.serverPackets.add(type);
if (sender == Sender.CLIENT)
register.clientPackets.add(type);
} catch (Exception ex) {
ProtocolLogger.debug("Encountered an exception associating packet " + type, ex);
}
}
}
}
@@ -46,6 +46,7 @@ import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.NettyVersion;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.Lists;
@@ -146,10 +147,15 @@ public class ProtocolInjector implements ChannelListener {
protected void initChannel(final Channel channel) throws Exception {
try {
synchronized (networkManagers) {
// For some reason it needs to be delayed on 1.12, but the delay breaks 1.11 and below
// For some reason it needs to be delayed when using netty 4.1.24 (minecraft 1.12) or newer,
// but the delay breaks older minecraft versions
// TODO I see this more as a temporary hotfix than a permanent solution
if (MinecraftVersion.getCurrentVersion().getMinor() >= 12) {
channel.eventLoop().submit(() ->
// Check if the netty version is greater than 4.1.24, that's the version bundled with spigot 1.12
NettyVersion ver = NettyVersion.getVersion();
if ((ver.isValid() && ver.isGreaterThan(4,1,24)) ||
MinecraftVersion.getCurrentVersion().getMinor() >= 12) { // fallback if netty version couldn't be detected
channel.eventLoop().submit(() ->
injectionFactory.fromChannel(channel, ProtocolInjector.this, playerFactory).inject());
} else {
injectionFactory.fromChannel(channel, ProtocolInjector.this, playerFactory).inject();
@@ -180,6 +186,12 @@ public class ProtocolInjector implements ChannelListener {
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
@Override
public boolean isSharable() {
// Needed if multiple objects are stored in the bootstrap list
return true;
}
};
FuzzyReflection fuzzy = FuzzyReflection.fromObject(serverConnection, true);
@@ -1,125 +0,0 @@
package com.comphenix.protocol.injector.netty;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* Represents a way of accessing the new netty Protocol enum.
* @author Kristian
*/
public abstract class ProtocolRegistry {
/**
* Represents a register we are currently building.
* @author Kristian
*/
protected static class Register {
// The main lookup table
public BiMap<PacketType, Class<?>> typeToClass = HashBiMap.create();
public volatile Set<PacketType> serverPackets = Sets.newHashSet();
public volatile Set<PacketType> clientPackets = Sets.newHashSet();
public List<MapContainer> containers = Lists.newArrayList();
public Register() {
}
/**
* Determine if the current register is outdated.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isOutdated() {
for (MapContainer container : containers) {
if (container.hasChanged()) {
return true;
}
}
return false;
}
}
protected Class<?> enumProtocol;
// Current register
protected volatile Register register;
public ProtocolRegistry() {
enumProtocol = MinecraftReflection.getEnumProtocolClass();
initialize();
}
/**
* Retrieve an immutable view of the packet type lookup.
* @return The packet type lookup.
*/
public Map<PacketType, Class<?>> getPacketTypeLookup() {
return Collections.unmodifiableMap(register.typeToClass);
}
/**
* Retrieve an immutable view of the class to packet type lookup.
* @return The packet type lookup.
*/
public Map<Class<?>, PacketType> getPacketClassLookup() {
return Collections.unmodifiableMap(register.typeToClass.inverse());
}
/**
* Retrieve every known client packet, from every protocol.
* @return Every client packet.
*/
public Set<PacketType> getClientPackets() {
return Collections.unmodifiableSet(register.clientPackets);
}
/**
* Retrieve every known server packet, from every protocol.
* @return Every server packet.
*/
public Set<PacketType> getServerPackets() {
return Collections.unmodifiableSet(register.serverPackets);
}
/**
* Ensure that our local register is up-to-date with Minecraft.
* <p>
* This operation may block the calling thread.
*/
public synchronized void synchronize() {
// Check if the packet registry has changed
if (register.isOutdated()) {
initialize();
}
}
/**
* Load the packet lookup tables in each protocol.
*/
protected abstract void initialize();
protected abstract void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender);
/**
* Retrieve the number of mapping in all the maps.
* @param maps - iterable of maps.
* @return The sum of all the entries.
*/
protected final int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
int count = 0;
for (Map<Integer, Class<?>> map : maps)
count += map.size();
return count;
}
}
@@ -43,8 +43,11 @@ public class SocketAdapter extends Socket {
this.ch = ch;
}
public static SocketAdapter adapt(SocketChannel ch) {
return new SocketAdapter(ch);
public static SocketAdapter adapt(Channel ch) {
if (!(ch instanceof SocketChannel)) {
return null;
}
return new SocketAdapter((SocketChannel) ch);
}
@Override
@@ -17,42 +17,275 @@
package com.comphenix.protocol.injector.packet;
import java.util.Map;
import java.util.Set;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Function;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
* Static packet registry in Minecraft.
* @author Kristian
*/
@SuppressWarnings("rawtypes")
public class PacketRegistry {
// The Netty packet registry
private static volatile ProtocolRegistry NETTY;
// Whether or not the registry has been initialized
private static volatile boolean INITIALIZED = false;
/**
* Represents a register we are currently building.
* @author Kristian
*/
protected static class Register {
// The main lookup table
private final Map<PacketType, Optional<Class<?>>> typeToClass = new ConcurrentHashMap<>();
private final Map<Class<?>, PacketType> classToType = new ConcurrentHashMap<>();
private volatile Set<PacketType> serverPackets = Sets.newHashSet();
private volatile Set<PacketType> clientPackets = Sets.newHashSet();
private final List<MapContainer> containers = Lists.newArrayList();
public Register() {}
public void registerPacket(PacketType type, Class<?> clazz, Sender sender) {
typeToClass.put(type, Optional.of(clazz));
classToType.put(clazz, type);
if (sender == Sender.CLIENT) {
clientPackets.add(type);
} else {
serverPackets.add(type);
}
}
public void addContainer(MapContainer container) {
containers.add(container);
}
/**
* Determine if the current register is outdated.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isOutdated() {
for (MapContainer container : containers) {
if (container.hasChanged()) {
return true;
}
}
return false;
}
}
protected static final Class<?> ENUM_PROTOCOL = MinecraftReflection.getEnumProtocolClass();
// Current register
protected static volatile Register REGISTER;
/**
* Ensure that our local register is up-to-date with Minecraft.
* <p>
* This operation may block the calling thread.
*/
public static synchronized void synchronize() {
// Check if the packet registry has changed
if (REGISTER.isOutdated()) {
initialize();
}
}
protected static synchronized Register createOldRegister() {
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
// ID to Packet class maps
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
Register result = new Register();
StructureModifier<Object> modifier = null;
// Iterate through the protocols
for (Object protocol : protocols) {
if (modifier == null) {
modifier = new StructureModifier<>(protocol.getClass().getSuperclass(), false);
}
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
for (Map.Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
String direction = entry.getKey().toString();
if (direction.contains("CLIENTBOUND")) { // Sent by Server
serverMaps.put(protocol, entry.getValue());
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
clientMaps.put(protocol, entry.getValue());
}
}
}
// Maps we have to occasionally check have changed
for (Object map : serverMaps.values()) {
result.addContainer(new MapContainer(map));
}
for (Object map : clientMaps.values()) {
result.addContainer(new MapContainer(map));
}
for (Object protocol : protocols) {
Enum<?> enumProtocol = (Enum<?>) protocol;
PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol);
// Associate known types
if (serverMaps.containsKey(protocol))
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
if (clientMaps.containsKey(protocol))
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
}
return result;
}
@SuppressWarnings("unchecked")
private static synchronized Register createNewRegister() {
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
// ID to Packet class maps
Map<Object, Map<Class<?>, Integer>> serverMaps = Maps.newLinkedHashMap();
Map<Object, Map<Class<?>, Integer>> clientMaps = Maps.newLinkedHashMap();
Register result = new Register();
Field mainMapField = null;
Field packetMapField = null;
// Iterate through the protocols
for (Object protocol : protocols) {
if (mainMapField == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true);
mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
.banModifier(Modifier.STATIC)
.requireModifier(Modifier.FINAL)
.typeDerivedOf(Map.class)
.build());
mainMapField.setAccessible(true);
}
Map<Object, Object> directionMap;
try {
directionMap = (Map<Object, Object>) mainMapField.get(protocol);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to access packet map", ex);
}
for (Map.Entry<Object, Object> entry : directionMap.entrySet()) {
Object holder = entry.getValue();
if (packetMapField == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(holder.getClass(), true);
packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
.banModifier(Modifier.STATIC)
.requireModifier(Modifier.FINAL)
.typeDerivedOf(Map.class)
.build());
packetMapField.setAccessible(true);
}
Map<Class<?>, Integer> packetMap;
try {
packetMap = (Map<Class<?>, Integer>) packetMapField.get(holder);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to access packet map", ex);
}
String direction = entry.getKey().toString();
if (direction.contains("CLIENTBOUND")) { // Sent by Server
serverMaps.put(protocol, packetMap);
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
clientMaps.put(protocol, packetMap);
}
}
}
// Maps we have to occasionally check have changed
// TODO: Find equivalent in Object2IntMap
/* for (Object map : serverMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Object map : clientMaps.values()) {
result.containers.add(new MapContainer(map));
} */
for (Object protocol : protocols) {
Enum<?> enumProtocol = (Enum<?>) protocol;
PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol);
// Associate known types
if (serverMaps.containsKey(protocol)) {
associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER);
}
if (clientMaps.containsKey(protocol)) {
associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT);
}
}
return result;
}
/**
* Reverses a key->value map to value->key
* Non-deterministic behavior when multiple keys are mapped to the same value
*/
private static <K, V> Map<V, K> reverse(Map<K, V> map) {
Map<V, K> newMap = new HashMap<>(map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
newMap.put(entry.getValue(), entry.getKey());
}
return newMap;
}
protected static void associatePackets(Register register, Map<Integer, Class<?>> lookup, PacketType.Protocol protocol, Sender sender) {
for (Map.Entry<Integer, Class<?>> entry : lookup.entrySet()) {
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
try {
register.registerPacket(type, entry.getValue(), sender);
} catch (Exception ex) {
ProtocolLogger.debug("Encountered an exception associating packet " + type, ex);
}
}
}
private static void associate(PacketType type, Class<?> clazz) {
if (clazz != null) {
REGISTER.typeToClass.put(type, Optional.of(clazz));
REGISTER.classToType.put(clazz, type);
} else {
REGISTER.typeToClass.put(type, Optional.empty());
}
}
/**
* Initializes the packet registry.
*/
private static void initialize() {
if (INITIALIZED) {
if (NETTY == null) {
throw new IllegalStateException("Failed to initialize packet registry.");
}
return;
}
if (!INITIALIZED) {
INITIALIZED = true;
NETTY = new NettyProtocolRegistry();
INITIALIZED = true;
if (MinecraftVersion.BEE_UPDATE.atOrAbove()) {
REGISTER = createNewRegister();
} else {
REGISTER = createOldRegister();
}
}
}
/**
@@ -62,35 +295,7 @@ public class PacketRegistry {
*/
public static boolean isSupported(PacketType type) {
initialize();
return NETTY.getPacketTypeLookup().containsKey(type);
}
/**
* Retrieve a map of every packet class to every ID.
* <p>
* Deprecated: Use {@link #getPacketToType()} instead.
* @return A map of packet classes and their corresponding ID.
*/
@Deprecated
public static Map<Class, Integer> getPacketToID() {
initialize();
@SuppressWarnings("unchecked")
Map<Class, Integer> result = (Map) Maps.transformValues(
NETTY.getPacketClassLookup(), PacketType::getCurrentId);
return result;
}
/**
* Retrieve a map of every packet class to the respective packet type.
* @return A map of packet classes and their corresponding packet type.
*/
public static Map<Class, PacketType> getPacketToType() {
initialize();
@SuppressWarnings("unchecked")
Map<Class, PacketType> result = (Map) NETTY.getPacketClassLookup();
return result;
return tryGetPacketClass(type).isPresent();
}
/**
@@ -99,9 +304,9 @@ public class PacketRegistry {
*/
public static Set<PacketType> getServerPacketTypes() {
initialize();
NETTY.synchronize();
synchronize();
return NETTY.getServerPackets();
return Collections.unmodifiableSet(REGISTER.serverPackets);
}
/**
@@ -110,88 +315,68 @@ public class PacketRegistry {
*/
public static Set<PacketType> getClientPacketTypes() {
initialize();
NETTY.synchronize();
synchronize();
return NETTY.getClientPackets();
return Collections.unmodifiableSet(REGISTER.clientPackets);
}
private static Class<?> searchForPacket(List<String> classNames) {
for (String name : classNames) {
try {
Class<?> clazz = MinecraftReflection.getMinecraftClass(name);
if (MinecraftReflection.getPacketClass().isAssignableFrom(clazz)
&& !Modifier.isAbstract(clazz.getModifiers())) {
return clazz;
}
} catch (Exception ignored) {}
}
return null;
}
/**
* Retrieves the correct packet class from a given packet ID.
* <p>
* Deprecated: Use {@link #getPacketClassFromType(PacketType)} instead.
* @param packetID - the packet ID.
* @return The associated class.
*/
@Deprecated
public static Class getPacketClassFromID(int packetID) {
initialize();
return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID));
}
/**
* Retrieves the correct packet class from a given type.
* @param type - the packet type.
* @return The associated class.
*/
public static Class getPacketClassFromType(PacketType type) {
return getPacketClassFromType(type, false);
}
/**
* Retrieves the correct packet class from a given type.
* <p>
* Note that forceVanillla will be ignored on MC 1.7.2 and later.
*
* @param type - the packet type.
* @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
* @return The associated class.
* @deprecated forceVanilla no longer has any effect
*/
public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) {
@Deprecated
public static Class<?> getPacketClassFromType(PacketType type, boolean forceVanilla) {
return getPacketClassFromType(type);
}
public static Optional<Class<?>> tryGetPacketClass(PacketType type) {
initialize();
// Try the lookup first
Class<?> clazz = NETTY.getPacketTypeLookup().get(type);
if (clazz != null) {
return clazz;
// Try the lookup first (may be null, so check contains)
Optional<Class<?>> res = REGISTER.typeToClass.get(type);
if (res != null) {
return res;
}
// Then try looking up the class names
for (String name : type.getClassNames()) {
try {
clazz = MinecraftReflection.getMinecraftClass(name);
break;
} catch (Exception ignored) { }
Class<?> clazz = searchForPacket(type.getClassNames());
if (clazz != null) {
// we'd like for it to be associated correctly from the get-go; this is OK on older versions though
ProtocolLogger.warnAbove(type.getCurrentVersion(), "Updating associated class for {0} to {1}", type.name(), clazz);
}
// TODO Cache the result?
return clazz;
// cache it for next time
associate(type, clazz);
return Optional.ofNullable(clazz);
}
/**
* Retrieves the correct packet class from a given packet ID.
* <p>
* This method has been deprecated.
* @param packetID - the packet ID.
* @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
* @return The associated class.
* Get the packet class associated with a given type. First attempts to read from the
* type-to-class mapping, and tries
* @param type the packet type
* @return The associated class
*/
@Deprecated
public static Class getPacketClassFromID(int packetID, boolean forceVanilla) {
initialize();
return getPacketClassFromID(packetID);
}
/**
* Retrieve the packet ID of a given packet.
* <p>
* Deprecated: Use {@link #getPacketType(Class)}.
* @param packet - the type of packet to check.
* @return The legacy ID of the given packet.
* @throws IllegalArgumentException If this is not a valid packet.
*/
@Deprecated
public static int getPacketID(Class<?> packet) {
initialize();
return NETTY.getPacketClassLookup().get(packet).getCurrentId();
public static Class<?> getPacketClassFromType(PacketType type) {
return tryGetPacketClass(type)
.orElseThrow(() -> new IllegalArgumentException("Could not find packet for type " + type.name()));
}
/**
@@ -200,7 +385,8 @@ public class PacketRegistry {
* @return The packet type, or NULL if not found.
*/
public static PacketType getPacketType(Class<?> packet) {
return getPacketType(packet, null);
initialize();
return REGISTER.classToType.get(packet);
}
/**
@@ -208,9 +394,10 @@ public class PacketRegistry {
* @param packet - the class of the packet.
* @param sender - the sender of the packet, or NULL.
* @return The packet type, or NULL if not found.
* @deprecated sender no longer has any effect
*/
@Deprecated
public static PacketType getPacketType(Class<?> packet, Sender sender) {
initialize();
return NETTY.getPacketClassLookup().get(packet);
return getPacketType(packet);
}
}
@@ -80,4 +80,9 @@ public class BukkitSocketInjector implements SocketInjector {
public void setUpdatedPlayer(Player updatedPlayer) {
this.player = updatedPlayer;
}
@Override
public boolean isConnected() {
return player.isOnline();
}
}
@@ -18,22 +18,24 @@ public interface SocketInjector {
* Retrieve the associated socket of this player.
* @return The associated socket.
* @throws IllegalAccessException If we're unable to read the socket field.
* @deprecated May be null on certain server implementations. Also don't use raw sockets.
*/
public abstract Socket getSocket() throws IllegalAccessException;
@Deprecated
Socket getSocket() throws IllegalAccessException;
/**
* Retrieve the associated address of this player.
* @return The associated address.
* @throws IllegalAccessException If we're unable to read the socket field.
*/
public abstract SocketAddress getAddress() throws IllegalAccessException;
SocketAddress getAddress() throws IllegalAccessException;
/**
* Attempt to disconnect the current client.
* @param message - the message to display.
* @throws InvocationTargetException If disconnection failed.
*/
public abstract void disconnect(String message) throws InvocationTargetException;
void disconnect(String message) throws InvocationTargetException;
/**
* Send a packet to the client.
@@ -42,30 +44,36 @@ public interface SocketInjector {
* @param filtered - whether or not the packet will be filtered by our listeners.
* @throws InvocationTargetException If an error occured when sending the packet.
*/
public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
throws InvocationTargetException;
/**
* Retrieve the hooked player.
* @return The hooked player.
*/
public abstract Player getPlayer();
Player getPlayer();
/**
* Retrieve the hooked player object OR the more up-to-date player instance.
* @return The hooked player, or a more up-to-date instance.
*/
public abstract Player getUpdatedPlayer();
Player getUpdatedPlayer();
/**
* Invoked when a delegated socket injector transfers the state of one injector to the next.
* @param delegate - the new injector.
*/
public abstract void transferState(SocketInjector delegate);
void transferState(SocketInjector delegate);
/**
* Set the real Bukkit player that we will use.
* @param updatedPlayer - the real Bukkit player.
*/
public abstract void setUpdatedPlayer(Player updatedPlayer);
void setUpdatedPlayer(Player updatedPlayer);
/**
* Determines if the player is currently connected.
* @return true if the player is connected.
*/
boolean isConnected();
}
@@ -157,9 +157,9 @@ public class TemporaryPlayerFactory {
// Methods that are supported in the fallback instance
if (methodName.equals("isOnline"))
return injector.getSocket() != null && injector.getSocket().isConnected();
return injector.isConnected();
else if (methodName.equals("getName"))
return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]";
return "UNKNOWN[" + injector.getAddress() + "]";
// Ignore all other methods
throw new UnsupportedOperationException(
@@ -2,7 +2,6 @@ package com.comphenix.protocol.metrics;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.tuple.Pair;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
@@ -24,7 +24,6 @@ import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.utility.Util;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.tuple.Pair;
import java.io.IOException;
import java.util.HashMap;
@@ -87,13 +86,7 @@ public class Statistics {
for (PacketListener listener : ProtocolLibrary.getProtocolManager().getPacketListeners()) {
String name = PacketAdapter.getPluginName(listener);
// Increment occurence
if (!users.containsKey(name)) {
users.put(name, 1);
} else {
users.put(name, users.get(name) + 1);
}
users.put(name, 1);
}
return users;
@@ -117,12 +117,11 @@ public class ObjectWriter {
}
// Copy private fields underneath
Class<?> superclass = commonType.getSuperclass();
if (superclass != null && !superclass.equals(Object.class)) {
copyToInternal(source, destination, superclass, false);
}
// Class<?> superclass = commonType.getSuperclass();
//
// if (superclass != null && !superclass.equals(Object.class)) {
// copyToInternal(source, destination, superclass, false);
// }
} catch (FieldAccessException e) {
throw new RuntimeException("Unable to copy fields from " + commonType.getName(), e);
}
@@ -289,6 +289,7 @@ public final class Accessors {
* @return The method accessor.
*/
public static ConstructorAccessor getConstructorAccessor(final Constructor<?> constructor) {
constructor.setAccessible(true); // let us in even if we are not allowed to
return new DefaultConstrutorAccessor(constructor);
}
@@ -256,11 +256,11 @@ public class AggregateCloner implements Cloner {
if (index < cloners.size()) {
Cloner cloner = cloners.get(index);
try {
return cloner.clone(source);
} catch (Exception ex) {
throw new RuntimeException("Failed to clone " + source + " (" + source.getClass() + ") with " + cloner, ex);
}
// try {
return cloner.clone(source);
// } catch (Exception ex) {
// throw new RuntimeException("Failed to clone " + source + " (" + source.getClass() + ") with " + cloner, ex);
// }
}
// Damn - failure
@@ -88,6 +88,11 @@ public class BukkitCloner implements Cloner {
fromManual(ComponentConverter::getBaseComponentArrayClass, source ->
ComponentConverter.clone((BaseComponent[]) source));
} catch (Throwable ignored) { }
try {
fromManual(AdventureComponentConverter::getComponentClass, source ->
AdventureComponentConverter.clone(source));
} catch (Throwable ignored) { }
}
private Function<Object, Object> findCloner(Class<?> type) {
@@ -62,29 +62,29 @@ public class ImmutableDetector implements Cloner {
add(MinecraftReflection::getDataWatcherSerializerClass);
add(MinecraftReflection::getBlockClass);
add(MinecraftReflection::getItemClass);
add("SoundEffect");
add("sounds.SoundEffect", "SoundEffect");
if (MinecraftVersion.AQUATIC_UPDATE.atOrAbove()) {
add(MinecraftReflection::getFluidTypeClass);
add(MinecraftReflection::getParticleTypeClass);
add("Particle");
add("core.particles.Particle", "Particle");
}
if (MinecraftVersion.VILLAGE_UPDATE.atOrAbove()) {
add("EntityTypes");
add("VillagerType");
add("VillagerProfession");
add(MinecraftReflection::getEntityTypes);
add("world.entity.npc.VillagerType", "VillagerType");
add("world.entity.npc.VillagerProfession", "VillagerProfession");
}
// TODO automatically detect the technically-not-an-enum enums that Mojang is so fond of
// Would also probably go in tandem with having the FieldCloner use this
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
add("IRegistry");
add("core.IRegistry", "IRegistry");
}
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
add("ResourceKey");
add(MinecraftReflection::getResourceKey);
}
}
@@ -97,13 +97,11 @@ public class ImmutableDetector implements Cloner {
} catch (RuntimeException ignored) { }
}
private static void add(String className) {
try {
Class<?> clazz = MinecraftReflection.getMinecraftClass(className);
if (clazz != null) {
immutableNMS.add(clazz);
}
} catch (RuntimeException ignored) { }
private static void add(String className, String... aliases) {
Class<?> clazz = MinecraftReflection.getNullableNMS(className, aliases);
if (clazz != null) {
immutableNMS.add(clazz);
}
}
@Override
@@ -141,6 +141,18 @@ public final class StructureCompiler {
private static String COMPILED_CLASS = PACKAGE_NAME + "/CompiledStructureModifier";
private static String FIELD_EXCEPTION_CLASS = "com/comphenix/protocol/reflect/FieldAccessException";
// On java 9+ (53.0+) CLassLoader#defineClass(String, byte[], int, int) should not be used anymore.
// It will throw warnings and on Java 16+ (60.0+), it does not work at all anymore.
private static final boolean LEGACY_CLASS_DEFINITION =
Float.parseFloat(System.getProperty("java.class.version")) < 53;
/**
* The MethodHandles.Lookup object for this compiler. Only used when using the modern defineClass strategy.
*/
private Object lookup = null;
// Used to get the MethodHandles.Lookup object on newer versions of Java.
private volatile static Method lookupMethod;
public static boolean attemptClassLoad = false;
/**
@@ -289,36 +301,54 @@ public final class StructureCompiler {
byte[] data = cw.toByteArray();
// Call the define method
Class<?> clazz = defineClass(data);
// DEBUG CODE: Print the content of the generated class.
//org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(data);
//cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), 0);
return clazz;
}
private Class<?> defineClassLegacy(byte[] data) throws InvocationTargetException, IllegalAccessException,
NoSuchMethodException {
if (defineMethod == null) {
Method defined = ClassLoader.class.getDeclaredMethod("defineClass",
new Class<?>[]{String.class, byte[].class, int.class, int.class});
// Awesome. Now, create and return it.
defined.setAccessible(true);
defineMethod = defined;
}
return (Class<?>) defineMethod.invoke(loader, null, data, 0, data.length);
}
private Class<?> defineClassModern(byte[] data) throws InvocationTargetException, IllegalAccessException,
ClassNotFoundException, NoSuchMethodException {
if (defineMethod == null) {
defineMethod = Class.forName("java.lang.invoke.MethodHandles$Lookup")
.getDeclaredMethod("defineClass", byte[].class);
}
if (lookupMethod == null) {
lookupMethod = Class.forName("java.lang.invoke.MethodHandles").getDeclaredMethod("lookup");
}
if (lookup == null)
lookup = lookupMethod.invoke(null);
return (Class<?>) defineMethod.invoke(lookup, data);
}
private Class<?> defineClass(byte[] data) {
try {
if (defineMethod == null) {
Method defined = ClassLoader.class.getDeclaredMethod("defineClass",
new Class<?>[] { String.class, byte[].class, int.class, int.class });
// Awesome. Now, create and return it.
defined.setAccessible(true);
defineMethod = defined;
}
@SuppressWarnings("rawtypes")
Class clazz = (Class) defineMethod.invoke(loader, null, data, 0, data.length);
// DEBUG CODE: Print the content of the generated class.
//org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(data);
//cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), 0);
return clazz;
return LEGACY_CLASS_DEFINITION ? defineClassLegacy(data) : defineClassModern(data);
} catch (SecurityException e) {
throw new RuntimeException("Cannot use reflection to dynamically load a class.", e);
} catch (NoSuchMethodException e) {
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new IllegalStateException("Incompatible JVM.", e);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Cannot call defineMethod - wrong JVM?", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Security limitation! Cannot dynamically load class.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Error occured in code generator.", e);
throw new RuntimeException("Error occurred in code generator.", e);
}
}
@@ -17,32 +17,31 @@
package com.comphenix.protocol.reflect.instances;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import javax.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nullable;
import com.comphenix.protocol.ProtocolLogger;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
/**
* Used to construct default instances of any type.
* @author Kristian
*
*/
public class DefaultInstances implements InstanceProvider {
public static final InstanceProvider UUID_GENERATOR = type -> type == UUID.class ? new UUID(0L, 0L) : null;
/**
* Standard default instance provider.
*/
public static final DefaultInstances DEFAULT = DefaultInstances.fromArray(
PrimitiveGenerator.INSTANCE, CollectionGenerator.INSTANCE, UUID_GENERATOR);
PrimitiveGenerator.INSTANCE,
CollectionGenerator.INSTANCE,
MinecraftGenerator.INSTANCE
);
/**
* The maximum height of the heirarchy of creates types. Used to prevent cycles.
@@ -188,7 +187,7 @@ public class DefaultInstances implements InstanceProvider {
// Note that we don't allow recursive types - that is, types that
// require itself in the constructor.
if (types.length < lastCount) {
if (!contains(types, type)) {
if (!contains(types, type) && !contains(types, MinecraftReflection.getPacketDataSerializerClass())) {
if (nonNull) {
// Make sure all of these types are non-null
if (isAnyNull(types, providers, recursionLevel)) {
@@ -273,7 +272,6 @@ public class DefaultInstances implements InstanceProvider {
Constructor<T> minimum = getMinimumConstructor(type, providers, recursionLevel + 1);
// Create the type with this constructor using default values. This might fail, though.
// TODO every packet has a zero-args constructor
try {
if (minimum != null) {
@@ -0,0 +1,77 @@
package com.comphenix.protocol.reflect.instances;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.BukkitConverters;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class MinecraftGenerator {
// system unique id representation
public static final UUID SYS_UUID;
// minecraft default types
public static final Object AIR_ITEM_STACK;
private static Object DEFAULT_ENTITY_TYPES; // modern servers only (older servers will use an entity type id)
// minecraft method accessors
private static final MethodAccessor NON_NULL_LIST_CREATE;
// fast util mappings for paper relocation
private static final Map<Class<?>, Constructor<?>> FAST_MAP_CONSTRUCTORS;
static {
try {
SYS_UUID = new UUID(0L, 0L);
AIR_ITEM_STACK = BukkitConverters.getItemStackConverter().getGeneric(new ItemStack(Material.AIR));
FAST_MAP_CONSTRUCTORS = new ConcurrentHashMap<>();
NON_NULL_LIST_CREATE = MinecraftReflection.getNonNullListCreateAccessor();
} catch (Throwable ex) {
throw new RuntimeException("Failed to create static fields in MinecraftGenerator", ex);
}
}
public static final InstanceProvider INSTANCE = type -> {
if (type != null) {
if (type == UUID.class) {
return SYS_UUID;
} else if (type.isEnum()) {
return type.getEnumConstants()[0];
} else if (type == MinecraftReflection.getItemStackClass()) {
return AIR_ITEM_STACK;
} else if (type == MinecraftReflection.getEntityTypes()) {
if (DEFAULT_ENTITY_TYPES == null) {
// try to initialize now
try {
DEFAULT_ENTITY_TYPES = BukkitConverters.getEntityTypeConverter().getGeneric(EntityType.AREA_EFFECT_CLOUD);
} catch (Exception ignored) {
// not available in this version of minecraft
}
}
return DEFAULT_ENTITY_TYPES;
} else if (type.isAssignableFrom(Map.class)) {
Constructor<?> ctor = FAST_MAP_CONSTRUCTORS.computeIfAbsent(type, __ -> {
try {
String name = type.getCanonicalName();
if (name != null && name.contains("it.unimi.fastutils")) {
return Class.forName(name.substring(name.length() - 3) + "OpenHashMap").getConstructor();
}
} catch (Exception ignored) {}
return null;
});
if (ctor != null) {
try {
return ctor.newInstance();
} catch (ReflectiveOperationException ignored) {}
}
} else if (NON_NULL_LIST_CREATE != null && type == MinecraftReflection.getNonNullListClass()) {
return NON_NULL_LIST_CREATE.invoke(null);
}
}
return null;
};
}
@@ -21,10 +21,10 @@ package com.comphenix.protocol.utility;
*/
public final class Constants {
public static final String PACKAGE_VERSION = "v1_16_R3";
public static final String NMS = "net.minecraft.server." + PACKAGE_VERSION;
public static final String PACKAGE_VERSION = "v1_17_R1";
public static final String NMS = "net.minecraft";
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
public static final MinecraftVersion CURRENT_VERSION = MinecraftVersion.NETHER_UPDATE_2;
public static final MinecraftVersion CURRENT_VERSION = MinecraftVersion.CAVES_CLIFFS_1;
public static void init() {
MinecraftReflection.setMinecraftPackage(NMS, OBC);
@@ -248,8 +248,8 @@ public class MinecraftMethods {
}
}
if (packetReadByteBuf == null)
throw new IllegalStateException("Unable to find Packet.read(PacketDataSerializer)");
// if (packetReadByteBuf == null)
// throw new IllegalStateException("Unable to find Packet.read(PacketDataSerializer)");
if (packetWriteByteBuf == null)
throw new IllegalStateException("Unable to find Packet.write(PacketDataSerializer)");
}
@@ -72,6 +72,10 @@ 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);
return map;
}
@@ -27,10 +27,8 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
@@ -57,6 +55,7 @@ import com.comphenix.protocol.reflect.ClassAnalyser;
import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
@@ -65,6 +64,7 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException;
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException.Reason;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.comphenix.protocol.wrappers.nbt.NbtType;
import com.google.common.base.Joiner;
@@ -222,30 +222,35 @@ public class MinecraftReflection {
Class<?> craftEntity = getCraftEntityClass();
Method getHandle = craftEntity.getMethod("getHandle");
MINECRAFT_FULL_PACKAGE = getPackage(getHandle.getReturnType().getCanonicalName());
// Pretty important invariantt
if (!MINECRAFT_FULL_PACKAGE.startsWith(MINECRAFT_PREFIX_PACKAGE)) {
// See if we got the Forge entity package
if (MINECRAFT_FULL_PACKAGE.equals(FORGE_ENTITY_PACKAGE)) {
// USe the standard NMS versioned package
MINECRAFT_FULL_PACKAGE = CachedPackage.combine(MINECRAFT_PREFIX_PACKAGE, packageVersion);
} else {
// Assume they're the same instead
MINECRAFT_PREFIX_PACKAGE = MINECRAFT_FULL_PACKAGE;
}
// The package is usualy flat, so go with that assumption
String matcher =
(MINECRAFT_PREFIX_PACKAGE.length() > 0 ?
Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + CANONICAL_REGEX;
// We'll still accept the default location, however
setDynamicPackageMatcher("(" + matcher + ")|(" + MINECRAFT_OBJECT + ")");
} else {
// Use the standard matcher
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
// total rework of the NMS structure in 1.17 (at least there's no versioning)
MINECRAFT_FULL_PACKAGE = MINECRAFT_PREFIX_PACKAGE = "net.minecraft";
setDynamicPackageMatcher(MINECRAFT_OBJECT);
} else {
MINECRAFT_FULL_PACKAGE = getPackage(getHandle.getReturnType().getCanonicalName());
// Pretty important invariantt
if (!MINECRAFT_FULL_PACKAGE.startsWith(MINECRAFT_PREFIX_PACKAGE)) {
// See if we got the Forge entity package
if (MINECRAFT_FULL_PACKAGE.equals(FORGE_ENTITY_PACKAGE)) {
// USe the standard NMS versioned package
MINECRAFT_FULL_PACKAGE = CachedPackage.combine(MINECRAFT_PREFIX_PACKAGE, packageVersion);
} else {
// Assume they're the same instead
MINECRAFT_PREFIX_PACKAGE = MINECRAFT_FULL_PACKAGE;
}
// The package is usualy flat, so go with that assumption
String matcher =
(MINECRAFT_PREFIX_PACKAGE.length() > 0 ? Pattern.quote(MINECRAFT_PREFIX_PACKAGE + ".") : "") + CANONICAL_REGEX;
// We'll still accept the default location, however
setDynamicPackageMatcher("(" + matcher + ")|(" + MINECRAFT_OBJECT + ")");
} else {
// Use the standard matcher
setDynamicPackageMatcher(MINECRAFT_OBJECT);
}
}
return MINECRAFT_FULL_PACKAGE;
@@ -580,7 +585,7 @@ public class MinecraftReflection {
*/
public static Class<?> getEntityPlayerClass() {
try {
return getMinecraftClass("EntityPlayer");
return getMinecraftClass("server.level.EntityPlayer","EntityPlayer");
} catch (RuntimeException e) {
try {
// Grab CraftPlayer's handle
@@ -637,7 +642,7 @@ public class MinecraftReflection {
*/
public static Class<?> getEntityClass() {
try {
return getMinecraftClass("Entity");
return getMinecraftClass("server.world.Entity", "Entity");
} catch (RuntimeException e) {
return fallbackMethodReturn("Entity", "entity.CraftEntity", "getHandle");
}
@@ -657,7 +662,7 @@ public class MinecraftReflection {
*/
public static Class<?> getWorldServerClass() {
try {
return getMinecraftClass("WorldServer");
return getMinecraftClass("server.level.WorldServer", "WorldServer");
} catch (RuntimeException e) {
return fallbackMethodReturn("WorldServer", "CraftWorld", "getHandle");
}
@@ -669,7 +674,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNmsWorldClass() {
try {
return getMinecraftClass("World");
return getMinecraftClass("world.level.World", "World");
} catch (RuntimeException e) {
return setMinecraftClass("World", getWorldServerClass().getSuperclass());
}
@@ -696,7 +701,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPacketClass() {
try {
return getMinecraftClass("Packet");
return getMinecraftClass("network.protocol.Packet", "Packet");
} catch (RuntimeException e) {
FuzzyClassContract paketContract = null;
@@ -752,8 +757,10 @@ public class MinecraftReflection {
* @return The Enum protocol class.
*/
public static Class<?> getEnumProtocolClass() {
try {
return getMinecraftClass("EnumProtocol");
return getMinecraftClass("network.EnumProtocol", "EnumProtocol");
/* try {
return getMinecraftClass("network.EnumProtocol", "EnumProtocol");
} catch (RuntimeException e) {
Method protocolMethod = FuzzyReflection.fromClass(getNetworkManagerClass()).getMethod(
FuzzyMethodContract.newBuilder().
@@ -762,7 +769,7 @@ public class MinecraftReflection {
build()
);
return setMinecraftClass("EnumProtocol", protocolMethod.getParameterTypes()[0]);
}
} */
}
/**
@@ -771,7 +778,7 @@ public class MinecraftReflection {
*/
public static Class<?> getIChatBaseComponentClass() {
try {
return getMinecraftClass("IChatBaseComponent");
return getMinecraftClass("network.chat.IChatbaseComponent", "IChatBaseComponent");
} catch (RuntimeException e) {
return setMinecraftClass("IChatBaseComponent",
Accessors.getMethodAccessor(getCraftChatMessage(), "fromString", String.class).
@@ -790,7 +797,7 @@ public class MinecraftReflection {
*/
public static Class<?> getChatComponentTextClass() {
try {
return getMinecraftClass("ChatComponentText");
return getMinecraftClass("network.chat.ChatComponentText", "ChatComponentText");
} catch (RuntimeException e) {
try {
Method getScoreboardDisplayName = FuzzyReflection.fromClass(getEntityClass()).
@@ -818,7 +825,8 @@ public class MinecraftReflection {
*/
public static Class<?> getChatSerializerClass() {
try {
return getMinecraftClass("ChatSerializer", "IChatBaseComponent$ChatSerializer");
return getMinecraftClass("network.chat.IChatBaseComponent$ChatSerializer",
"ChatSerializer", "IChatBaseComponent$ChatSerializer");
} catch (RuntimeException e) {
// TODO: Figure out a functional fallback
throw new IllegalStateException("Could not find ChatSerializer class.", e);
@@ -830,11 +838,8 @@ public class MinecraftReflection {
* @return The ServerPing class.
*/
public static Class<?> getServerPingClass() {
if (!isUsingNetty())
throw new IllegalStateException("ServerPing is only supported in 1.7.2.");
try {
return getMinecraftClass("ServerPing");
return getMinecraftClass("network.protocol.status.ServerPing", "ServerPing");
} catch (RuntimeException e) {
Class<?> statusServerInfo = PacketType.Status.Server.SERVER_INFO.getPacketClass();
@@ -856,11 +861,9 @@ public class MinecraftReflection {
* @return The ServerPingServerData class.
*/
public static Class<?> getServerPingServerDataClass() {
if (!isUsingNetty())
throw new IllegalStateException("ServerPingServerData is only supported in 1.7.2.");
try {
return getMinecraftClass("ServerPingServerData", "ServerPing$ServerData");
return getMinecraftClass("network.protocol.status.ServerPing$ServerData",
"ServerPingServerData", "ServerPing$ServerData");
} catch (RuntimeException e) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(getServerPingClass(), true);
return setMinecraftClass("ServerPingServerData", fuzzy.getFieldByType("(.*)(ServerData)(.*)").getType());
@@ -872,11 +875,9 @@ public class MinecraftReflection {
* @return The ServerPingPlayerSample class.
*/
public static Class<?> getServerPingPlayerSampleClass() {
if (!isUsingNetty())
throw new IllegalStateException("ServerPingPlayerSample is only supported in 1.7.2.");
try {
return getMinecraftClass("ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
return getMinecraftClass("network.protocol.status.ServerPing$ServerPingPlayerSample",
"ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
} catch (RuntimeException e) {
Class<?> serverPing = getServerPingClass();
@@ -942,7 +943,7 @@ public class MinecraftReflection {
*/
public static Class<?> getMinecraftServerClass() {
try {
return getMinecraftClass("MinecraftServer");
return getMinecraftClass("server.MinecraftServer","MinecraftServer");
} catch (RuntimeException e) {
useFallbackServer();
@@ -958,7 +959,7 @@ public class MinecraftReflection {
*/
public static Class<?> getStatisticClass() {
// TODO: Implement fallback
return getMinecraftClass("Statistic");
return getMinecraftClass("stats.Statistic", "Statistic");
}
/**
@@ -967,7 +968,7 @@ public class MinecraftReflection {
*/
public static Class<?> getStatisticListClass() {
// TODO: Implement fallback
return getMinecraftClass("StatisticList");
return getMinecraftClass("stats.StatisticList", "StatisticList");
}
/**
@@ -994,7 +995,8 @@ public class MinecraftReflection {
*/
public static Class<?> getPlayerListClass() {
try {
return getMinecraftClass("ServerConfigurationManager", "PlayerList");
return getMinecraftClass("server.players.PlayerList",
"ServerConfigurationManager", "PlayerList");
} catch (RuntimeException e) {
useFallbackServer();
@@ -1033,7 +1035,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPlayerConnectionClass() {
try {
return getMinecraftClass("PlayerConnection", "NetServerHandler");
return getMinecraftClass("server.network.PlayerConnection","PlayerConnection", "NetServerHandler");
} catch (RuntimeException e) {
try {
// Use the player connection field
@@ -1077,7 +1079,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNetworkManagerClass() {
try {
return getMinecraftClass("INetworkManager", "NetworkManager");
return getMinecraftClass("network.NetworkManager", "INetworkManager", "NetworkManager");
} catch (RuntimeException e) {
Constructor<?> selected = FuzzyReflection.fromClass(getPlayerConnectionClass()).
getConstructor(FuzzyMethodContract.newBuilder().
@@ -1110,7 +1112,7 @@ public class MinecraftReflection {
*/
public static Class<?> getItemStackClass() {
try {
return getMinecraftClass("ItemStack");
return getMinecraftClass("world.item.ItemStack", "ItemStack");
} catch (RuntimeException e) {
// Use the handle reference
return setMinecraftClass("ItemStack",
@@ -1124,7 +1126,7 @@ public class MinecraftReflection {
*/
public static Class<?> getBlockClass() {
try {
return getMinecraftClass("Block");
return getMinecraftClass("world.level.block.Block", "Block");
} catch (RuntimeException e) {
FuzzyReflection reflect = FuzzyReflection.fromClass(getItemStackClass());
Set<Class<?>> candidates = new HashSet<Class<?>>();
@@ -1149,15 +1151,15 @@ public class MinecraftReflection {
}
public static Class<?> getItemClass() {
return getNullableNMS("Item");
return getNullableNMS("world.item.Item", "Item");
}
public static Class<?> getFluidTypeClass() {
return getNullableNMS("FluidType");
return getNullableNMS("world.level.material.FluidType", "FluidType");
}
public static Class<?> getParticleTypeClass() {
return getNullableNMS("ParticleType");
return getNullableNMS("core.particles.ParticleType", "ParticleType");
}
/**
@@ -1188,7 +1190,7 @@ public class MinecraftReflection {
*/
public static Class<?> getDataWatcherClass() {
try {
return getMinecraftClass("DataWatcher");
return getMinecraftClass("network.syncher.DataWatcher", "DataWatcher");
} catch (RuntimeException e) {
// Describe the DataWatcher
FuzzyClassContract dataWatcherContract = FuzzyClassContract.newBuilder().
@@ -1236,7 +1238,7 @@ public class MinecraftReflection {
*/
public static Class<?> getBlockPositionClass() {
try {
return getMinecraftClass("BlockPosition");
return getMinecraftClass("core.BlockPosition", "BlockPosition");
} catch (RuntimeException e) {
try {
Class<?> normalChunkGenerator = getCraftBukkitClass("generator.NormalChunkGenerator");
@@ -1263,7 +1265,7 @@ public class MinecraftReflection {
*/
public static Class<?> getVec3DClass() {
try {
return getMinecraftClass("Vec3D");
return getMinecraftClass("world.phys.Vec3D", "Vec3D");
} catch (RuntimeException e) {
// TODO: Figure out a fuzzy field contract
return null;
@@ -1288,13 +1290,10 @@ public class MinecraftReflection {
* @return The ChunkCoordIntPair class.
*/
public static Class<?> getChunkCoordIntPair() {
if (!isUsingNetty())
throw new IllegalArgumentException("Not supported on 1.6.4 and older.");
try {
return getMinecraftClass("ChunkCoordIntPair");
return getMinecraftClass("world.level.ChunkCoordIntPair", "ChunkCoordIntPair");
} catch (RuntimeException e) {
Class<?> packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.MULTI_BLOCK_CHANGE);
Class<?> packet = PacketType.Play.Server.MULTI_BLOCK_CHANGE.getPacketClass();
AbstractFuzzyMatcher<Class<?>> chunkCoordIntContract = FuzzyClassContract.newBuilder().
field(FuzzyFieldContract.newBuilder().
@@ -1326,7 +1325,8 @@ public class MinecraftReflection {
*/
public static Class<?> getDataWatcherItemClass() {
try {
return getMinecraftClass("DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
return getMinecraftClass("network.syncher.DataWatcher$Item",
"DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
} catch (RuntimeException e) {
Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true).
getMethod(FuzzyMethodContract.newBuilder().
@@ -1342,7 +1342,7 @@ public class MinecraftReflection {
public static Class<?> getDataWatcherObjectClass() {
try {
return getMinecraftClass("DataWatcherObject");
return getMinecraftClass("network.syncher.DataWatcherObject", "DataWatcherObject");
} catch (RuntimeException ex) {
return null;
}
@@ -1362,27 +1362,27 @@ public class MinecraftReflection {
public static Class<?> getDataWatcherSerializerClass() {
// TODO Implement a fallback
return getNullableNMS("DataWatcherSerializer");
return getNullableNMS("network.syncher.DataWatcherSerializer", "DataWatcherSerializer");
}
public static Class<?> getDataWatcherRegistryClass() {
// TODO Implement a fallback
return getMinecraftClass("DataWatcherRegistry");
return getMinecraftClass("network.syncher.DataWatcherRegistry", "DataWatcherRegistry");
}
public static Class<?> getMinecraftKeyClass() {
// TODO Implement a fallback
return getMinecraftClass("MinecraftKey");
return getMinecraftClass("resources.MinecraftKey", "MinecraftKey");
}
public static Class<?> getMobEffectListClass() {
// TODO Implement a fallback
return getMinecraftClass("MobEffectList");
return getMinecraftClass("world.effect.MobEffectList", "MobEffectList");
}
public static Class<?> getSoundEffectClass() {
try {
return getMinecraftClass("SoundEffect");
return getMinecraftClass("sounds.SoundEffect", "SoundEffect");
} catch (RuntimeException ex) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(PacketType.Play.Server.NAMED_SOUND_EFFECT.getPacketClass(), true);
Field field = fuzzy.getFieldByType("(.*)(Sound)(.*)");
@@ -1396,7 +1396,7 @@ public class MinecraftReflection {
*/
public static Class<?> getServerConnectionClass() {
try {
return getMinecraftClass("ServerConnection");
return getMinecraftClass("server.network.ServerConnection", "ServerConnection");
} catch (RuntimeException e) {
Method selected = null;
FuzzyClassContract.Builder serverConnectionContract = FuzzyClassContract.newBuilder().
@@ -1441,7 +1441,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNBTBaseClass() {
try {
return getMinecraftClass("NBTBase");
return getMinecraftClass("nbt.NBTBase", "NBTBase");
} catch (RuntimeException e) {
Class<?> nbtBase = null;
@@ -1501,7 +1501,7 @@ public class MinecraftReflection {
* @return The NBT read limiter.
*/
public static Class<?> getNBTReadLimiterClass() {
return getMinecraftClass("NBTReadLimiter");
return getMinecraftClass("nbt.NBTReadLimiter", "NBTReadLimiter");
}
/**
@@ -1510,7 +1510,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNBTCompoundClass() {
try {
return getMinecraftClass("NBTTagCompound");
return getMinecraftClass("nbt.NBTTagCompound","NBTTagCompound");
} catch (RuntimeException e) {
return setMinecraftClass(
"NBTTagCompound",
@@ -1525,7 +1525,8 @@ public class MinecraftReflection {
*/
public static Class<?> getEntityTrackerClass() {
try {
return getMinecraftClass("EntityTracker", "PlayerChunkMap$EntityTracker");
return getMinecraftClass("server.level.PlayerChunkMap$EntityTracker",
"EntityTracker", "PlayerChunkMap$EntityTracker");
} catch (RuntimeException e) {
FuzzyClassContract entityTrackerContract = FuzzyClassContract.newBuilder().
field(FuzzyFieldContract.newBuilder().
@@ -1553,38 +1554,6 @@ public class MinecraftReflection {
}
}
/**
* Retrieve the NetworkListenThread class (NMS).
* <p>
* Note that this class was removed after Minecraft 1.3.1.
* @return NetworkListenThread class.
*/
public static Class<?> getNetworkListenThreadClass() {
try {
return getMinecraftClass("NetworkListenThread");
} catch (RuntimeException e) {
FuzzyClassContract networkListenContract = FuzzyClassContract.newBuilder().
field(FuzzyFieldContract.newBuilder().
typeDerivedOf(ServerSocket.class)).
field(FuzzyFieldContract.newBuilder().
typeDerivedOf(Thread.class)).
field(FuzzyFieldContract.newBuilder().
typeDerivedOf(List.class)).
method(FuzzyMethodContract.newBuilder().
parameterExactType(getPlayerConnectionClass())).
build();
Field selected = FuzzyReflection.fromClass(MinecraftReflection.getMinecraftServerClass(), true).
getField(FuzzyFieldContract.newBuilder().
typeMatches(networkListenContract).
build()
);
// Go by the defined type of this field
return setMinecraftClass("NetworkListenThread", selected.getType());
}
}
/**
* Retrieve the attribute snapshot class.
* <p>
@@ -1593,7 +1562,8 @@ public class MinecraftReflection {
*/
public static Class<?> getAttributeSnapshotClass() {
try {
return getMinecraftClass("AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
return getMinecraftClass("network.protocol.game.PacketPlayOutUpdateAttributes$AttributeSnapshot",
"AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
} catch (RuntimeException ex) {
try {
// It should be the parameter of a list in the update attributes packet
@@ -1652,7 +1622,7 @@ public class MinecraftReflection {
*/
public static Class<?> getAttributeModifierClass() {
try {
return getMinecraftClass("AttributeModifier");
return getMinecraftClass("world.entity.ai.attributes.AttributeModifier", "AttributeModifier");
} catch (RuntimeException e) {
getAttributeSnapshotClass();
@@ -1668,10 +1638,10 @@ public class MinecraftReflection {
*/
public static Class<?> getMobEffectClass() {
try {
return getMinecraftClass("MobEffect");
return getMinecraftClass("world.effect.MobEffect", "MobEffect");
} catch (RuntimeException e) {
// It is the second parameter in Packet41MobEffect
Class<?> packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.ENTITY_EFFECT);
Class<?> packet = PacketType.Play.Server.ENTITY_EFFECT.getPacketClass();
Constructor<?> constructor = FuzzyReflection.fromClass(packet).getConstructor(
FuzzyMethodContract.newBuilder().
parameterCount(2).
@@ -1689,7 +1659,7 @@ public class MinecraftReflection {
*/
public static Class<?> getPacketDataSerializerClass() {
try {
return getMinecraftClass("PacketDataSerializer");
return getMinecraftClass("network.PacketDataSerializer", "PacketDataSerializer");
} catch (RuntimeException e) {
Class<?> packet = getPacketClass();
Method method = FuzzyReflection.fromClass(packet).getMethod(
@@ -1709,7 +1679,7 @@ public class MinecraftReflection {
*/
public static Class<?> getNbtCompressedStreamToolsClass() {
try {
return getMinecraftClass("NBTCompressedStreamTools");
return getMinecraftClass("nbt.NBTCompressedStreamTools", "NBTCompressedStreamTools");
} catch (RuntimeException e) {
Class<?> packetSerializer = getPacketDataSerializerClass();
@@ -1738,7 +1708,7 @@ public class MinecraftReflection {
* @return The tile entity class.
*/
public static Class<?> getTileEntityClass() {
return getMinecraftClass("TileEntity");
return getMinecraftClass("world.level.block.entity.TileEntity", "TileEntity");
}
/**
@@ -1820,7 +1790,54 @@ public class MinecraftReflection {
* @return The PlayerInfoData class
*/
public static Class<?> getPlayerInfoDataClass() {
return getMinecraftClass("PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
return getMinecraftClass("network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData",
"PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
}
/**
* Retrieves the entity use action class in 1.17.
* @return The EntityUseAction class
*/
public static Class<?> getEnumEntityUseActionClass() {
Class<?> packetClass = PacketType.Play.Client.USE_ENTITY.getPacketClass();
return FuzzyReflection.fromClass(packetClass, true).getFieldByType("^.*(EnumEntityUseAction)").getType();
}
/**
* Get a method accessor to get the actual use action out of the wrapping EnumEntityUseAction in 1.17.
* @return a method accessor to get the actual use action
*/
public static MethodAccessor getEntityUseActionEnumMethodAccessor() {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getEnumEntityUseActionClass(), true);
return Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
.returnTypeExact(EnumWrappers.getEntityUseActionClass())
.build()));
}
/**
* Get a field accessor for the hand in the wrapping EnumEntityUseAction in 1.17.
*
* @param enumEntityUseAction the object instance of the action, the field is not present in attack.
* @return a field accessor for the hand in the wrapping EnumEntityUseAction
*/
public static FieldAccessor getHandEntityUseActionEnumFieldAccessor(Object enumEntityUseAction) {
FuzzyReflection fuzzy = FuzzyReflection.fromObject(enumEntityUseAction, true);
return Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract.newBuilder()
.typeExact(EnumWrappers.getHandClass())
.build()));
}
/**
* Get a field accessor for the vec3d in the wrapping EnumEntityUseAction in 1.17.
*
* @param enumEntityUseAction the object instance of the action, the field is not present in attack.
* @return a field accessor for the hand in the wrapping EnumEntityUseAction
*/
public static FieldAccessor getVec3EntityUseActionEnumFieldAccessor(Object enumEntityUseAction) {
FuzzyReflection fuzzy = FuzzyReflection.fromObject(enumEntityUseAction, true);
return Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract.newBuilder()
.typeExact(MinecraftReflection.getVec3DClass())
.build()));
}
/**
@@ -1837,7 +1854,7 @@ public class MinecraftReflection {
* @return The IBlockData class
*/
public static Class<?> getIBlockDataClass() {
return getMinecraftClass("IBlockData");
return getMinecraftClass("world.level.block.state.IBlockData", "IBlockData");
}
/**
@@ -1856,16 +1873,35 @@ public class MinecraftReflection {
return getArrayClass(getMultiBlockChangeInfoClass());
}
/**
* Retrieve the PacketPlayOutGameStateChange.a class, aka GameState in 1.16
* @return The GameState class
*/
public static Class<?> getGameStateClass() {
// it's called "a" so there's not a whole lot we can do to identify it
Class<?> packetClass = PacketType.Play.Server.GAME_STATE_CHANGE.getPacketClass();
return packetClass.getClasses()[0];
}
public static boolean signUpdateExists() {
try {
return getMinecraftClass("PacketPlayOutUpdateSign") != null;
} catch (RuntimeException ex) {
return false;
}
return getNullableNMS("PacketPlayOutUpdateSign") != null;
}
public static Class<?> getNonNullListClass() {
return getMinecraftClass("NonNullList");
return getMinecraftClass("core.NonNullList", "NonNullList");
}
public static MethodAccessor getNonNullListCreateAccessor() {
try {
Class<?> nonNullListType = MinecraftReflection.getNonNullListClass();
return Accessors.getMethodAccessor(FuzzyReflection.fromClass(nonNullListType).getMethod(
FuzzyMethodContract.newBuilder()
.returnTypeExact(nonNullListType)
.requireModifier(Modifier.STATIC)
.build()));
} catch (Exception ex) {
return null;
}
}
public static Class<?> getCraftSoundClass() {
@@ -1873,7 +1909,7 @@ public class MinecraftReflection {
}
public static Class<?> getSectionPositionClass() {
return getMinecraftClass("SectionPosition");
return getMinecraftClass("core.SectionPosition", "SectionPosition");
}
// ---- ItemStack conversions
@@ -2027,10 +2063,12 @@ public class MinecraftReflection {
.orElseThrow(() -> new RuntimeException("Failed to find NMS class: " + className));
}
public static Class<?> getNullableNMS(String className) {
if (minecraftPackage == null)
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
return minecraftPackage.getPackageClass(className).orElse(null);
public static Class<?> getNullableNMS(String className, String... aliases) {
try {
return getMinecraftClass(className, aliases);
} catch (RuntimeException ex) {
return null;
}
}
/**
@@ -2163,4 +2201,70 @@ 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) {
try {
return getMinecraftLibraryClass("it.unimi.dsi.fastutil." + className);
} catch (RuntimeException ex) {
Class<?> clazz = getMinecraftLibraryClass("org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil." + className);
setMinecraftLibraryClass("it.unimi.dsi.fastutil." + className, clazz);
return clazz;
}
}
public static Class<?> getInt2ObjectMapClass() {
return getFastUtilClass("ints.Int2ObjectMap");
}
public static Class<?> getIntArrayListClass() {
return getFastUtilClass("ints.IntArrayList");
}
}
@@ -44,6 +44,11 @@ public class MinecraftVersion implements Comparable<MinecraftVersion>, Serializa
*/
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
/**
* Version 1.17 - caves and cliffs part 1
*/
public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17");
/**
* Version 1.16.2 - breaking change to the nether update
*/
@@ -0,0 +1,83 @@
package com.comphenix.protocol.utility;
import com.comphenix.protocol.ProtocolLibrary;
import io.netty.util.Version;
import java.util.Map;
public class NettyVersion {
private final static String NETTY_ARTIFACT_ID = "netty-common";
private static NettyVersion version;
public static NettyVersion getVersion() {
if(version == null) {
version = detectVersion();
}
return version;
}
private static NettyVersion detectVersion() {
Map<String, Version> nettyArtifacts = Version.identify();
Version version = nettyArtifacts.get(NETTY_ARTIFACT_ID);
if(version != null) {
return new NettyVersion(version.artifactVersion());
}
return new NettyVersion(null);
}
private boolean valid = false;
private int major, minor, revision;
public NettyVersion(String s) {
if(s == null) {
return;
}
String[] split = s.split( "\\.");
try {
this.major = Integer.parseInt(split[0]);
this.minor = Integer.parseInt(split[1]);
this.revision = Integer.parseInt(split[2]);
this.valid = true;
} catch (Throwable t) {
ProtocolLibrary.getPlugin().getLogger().warning("Could not detect netty version: '" + s + "'");
}
}
@Override
public String toString() {
if(!valid) {
return "(invalid)";
}
return major + "." + minor + "." + revision;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof NettyVersion)) {
return false;
}
NettyVersion v = (NettyVersion) obj;
return v.major == major && v.minor == minor && v.revision == revision;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getRevision() {
return revision;
}
public boolean isValid() {
return this.valid;
}
public boolean isGreaterThan(int major, int minor, int rev) {
return this.major > major || this.minor > minor || this.revision > rev;
}
}
@@ -0,0 +1,741 @@
package com.comphenix.protocol.utility;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufProcessor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
public class ZeroBuffer extends ByteBuf {
@Override
public int capacity() {
return 0;
}
@Override
public ByteBuf capacity(int i) {
return null;
}
@Override
public int maxCapacity() {
return 0;
}
@Override
public ByteBufAllocator alloc() {
return null;
}
@Override
public ByteOrder order() {
return null;
}
@Override
public ByteBuf order(ByteOrder byteOrder) {
return null;
}
@Override
public ByteBuf unwrap() {
return null;
}
@Override
public boolean isDirect() {
return false;
}
@Override
public int readerIndex() {
return 0;
}
@Override
public ByteBuf readerIndex(int i) {
return null;
}
@Override
public int writerIndex() {
return 0;
}
@Override
public ByteBuf writerIndex(int i) {
return null;
}
@Override
public ByteBuf setIndex(int i, int i1) {
return null;
}
@Override
public int readableBytes() {
return 0;
}
@Override
public int writableBytes() {
return 0;
}
@Override
public int maxWritableBytes() {
return 0;
}
@Override
public boolean isReadable() {
return false;
}
@Override
public boolean isReadable(int i) {
return false;
}
@Override
public boolean isWritable() {
return false;
}
@Override
public boolean isWritable(int i) {
return false;
}
@Override
public ByteBuf clear() {
return null;
}
@Override
public ByteBuf markReaderIndex() {
return null;
}
@Override
public ByteBuf resetReaderIndex() {
return null;
}
@Override
public ByteBuf markWriterIndex() {
return null;
}
@Override
public ByteBuf resetWriterIndex() {
return null;
}
@Override
public ByteBuf discardReadBytes() {
return null;
}
@Override
public ByteBuf discardSomeReadBytes() {
return null;
}
@Override
public ByteBuf ensureWritable(int i) {
return null;
}
@Override
public int ensureWritable(int i, boolean b) {
return 0;
}
@Override
public boolean getBoolean(int i) {
return false;
}
@Override
public byte getByte(int i) {
return 0;
}
@Override
public short getUnsignedByte(int i) {
return 0;
}
@Override
public short getShort(int i) {
return 0;
}
@Override
public int getUnsignedShort(int i) {
return 0;
}
@Override
public int getMedium(int i) {
return 0;
}
@Override
public int getUnsignedMedium(int i) {
return 0;
}
@Override
public int getInt(int i) {
return 0;
}
@Override
public long getUnsignedInt(int i) {
return 0;
}
@Override
public long getLong(int i) {
return 0;
}
@Override
public char getChar(int i) {
return 0;
}
@Override
public float getFloat(int i) {
return 0;
}
@Override
public double getDouble(int i) {
return 0;
}
@Override
public ByteBuf getBytes(int i, ByteBuf byteBuf) {
return null;
}
@Override
public ByteBuf getBytes(int i, ByteBuf byteBuf, int i1) {
return null;
}
@Override
public ByteBuf getBytes(int i, ByteBuf byteBuf, int i1, int i2) {
return null;
}
@Override
public ByteBuf getBytes(int i, byte[] bytes) {
return null;
}
@Override
public ByteBuf getBytes(int i, byte[] bytes, int i1, int i2) {
return null;
}
@Override
public ByteBuf getBytes(int i, ByteBuffer byteBuffer) {
return null;
}
@Override
public ByteBuf getBytes(int i, OutputStream outputStream, int i1) throws IOException {
return null;
}
@Override
public int getBytes(int i, GatheringByteChannel gatheringByteChannel, int i1) throws IOException {
return 0;
}
@Override
public ByteBuf setBoolean(int i, boolean b) {
return null;
}
@Override
public ByteBuf setByte(int i, int i1) {
return null;
}
@Override
public ByteBuf setShort(int i, int i1) {
return null;
}
@Override
public ByteBuf setMedium(int i, int i1) {
return null;
}
@Override
public ByteBuf setInt(int i, int i1) {
return null;
}
@Override
public ByteBuf setLong(int i, long l) {
return null;
}
@Override
public ByteBuf setChar(int i, int i1) {
return null;
}
@Override
public ByteBuf setFloat(int i, float v) {
return null;
}
@Override
public ByteBuf setDouble(int i, double v) {
return null;
}
@Override
public ByteBuf setBytes(int i, ByteBuf byteBuf) {
return null;
}
@Override
public ByteBuf setBytes(int i, ByteBuf byteBuf, int i1) {
return null;
}
@Override
public ByteBuf setBytes(int i, ByteBuf byteBuf, int i1, int i2) {
return null;
}
@Override
public ByteBuf setBytes(int i, byte[] bytes) {
return null;
}
@Override
public ByteBuf setBytes(int i, byte[] bytes, int i1, int i2) {
return null;
}
@Override
public ByteBuf setBytes(int i, ByteBuffer byteBuffer) {
return null;
}
@Override
public int setBytes(int i, InputStream inputStream, int i1) throws IOException {
return 0;
}
@Override
public int setBytes(int i, ScatteringByteChannel scatteringByteChannel, int i1) throws IOException {
return 0;
}
@Override
public ByteBuf setZero(int i, int i1) {
return null;
}
@Override
public boolean readBoolean() {
return false;
}
@Override
public byte readByte() {
return 0;
}
@Override
public short readUnsignedByte() {
return 0;
}
@Override
public short readShort() {
return 0;
}
@Override
public int readUnsignedShort() {
return 0;
}
@Override
public int readMedium() {
return 0;
}
@Override
public int readUnsignedMedium() {
return 0;
}
@Override
public int readInt() {
return 0;
}
@Override
public long readUnsignedInt() {
return 0;
}
@Override
public long readLong() {
return 0;
}
@Override
public char readChar() {
return 0;
}
@Override
public float readFloat() {
return 0;
}
@Override
public double readDouble() {
return 0;
}
@Override
public ByteBuf readBytes(int i) {
return null;
}
@Override
public ByteBuf readSlice(int i) {
return null;
}
@Override
public ByteBuf readBytes(ByteBuf byteBuf) {
return null;
}
@Override
public ByteBuf readBytes(ByteBuf byteBuf, int i) {
return null;
}
@Override
public ByteBuf readBytes(ByteBuf byteBuf, int i, int i1) {
return null;
}
@Override
public ByteBuf readBytes(byte[] bytes) {
return null;
}
@Override
public ByteBuf readBytes(byte[] bytes, int i, int i1) {
return null;
}
@Override
public ByteBuf readBytes(ByteBuffer byteBuffer) {
return null;
}
@Override
public ByteBuf readBytes(OutputStream outputStream, int i) throws IOException {
return null;
}
@Override
public int readBytes(GatheringByteChannel gatheringByteChannel, int i) throws IOException {
return 0;
}
@Override
public ByteBuf skipBytes(int i) {
return null;
}
@Override
public ByteBuf writeBoolean(boolean b) {
return null;
}
@Override
public ByteBuf writeByte(int i) {
return null;
}
@Override
public ByteBuf writeShort(int i) {
return null;
}
@Override
public ByteBuf writeMedium(int i) {
return null;
}
@Override
public ByteBuf writeInt(int i) {
return null;
}
@Override
public ByteBuf writeLong(long l) {
return null;
}
@Override
public ByteBuf writeChar(int i) {
return null;
}
@Override
public ByteBuf writeFloat(float v) {
return null;
}
@Override
public ByteBuf writeDouble(double v) {
return null;
}
@Override
public ByteBuf writeBytes(ByteBuf byteBuf) {
return null;
}
@Override
public ByteBuf writeBytes(ByteBuf byteBuf, int i) {
return null;
}
@Override
public ByteBuf writeBytes(ByteBuf byteBuf, int i, int i1) {
return null;
}
@Override
public ByteBuf writeBytes(byte[] bytes) {
return null;
}
@Override
public ByteBuf writeBytes(byte[] bytes, int i, int i1) {
return null;
}
@Override
public ByteBuf writeBytes(ByteBuffer byteBuffer) {
return null;
}
@Override
public int writeBytes(InputStream inputStream, int i) throws IOException {
return 0;
}
@Override
public int writeBytes(ScatteringByteChannel scatteringByteChannel, int i) throws IOException {
return 0;
}
@Override
public ByteBuf writeZero(int i) {
return null;
}
@Override
public int indexOf(int i, int i1, byte b) {
return 0;
}
@Override
public int bytesBefore(byte b) {
return 0;
}
@Override
public int bytesBefore(int i, byte b) {
return 0;
}
@Override
public int bytesBefore(int i, int i1, byte b) {
return 0;
}
@Override
public int forEachByte(ByteBufProcessor byteBufProcessor) {
return 0;
}
@Override
public int forEachByte(int i, int i1, ByteBufProcessor byteBufProcessor) {
return 0;
}
@Override
public int forEachByteDesc(ByteBufProcessor byteBufProcessor) {
return 0;
}
@Override
public int forEachByteDesc(int i, int i1, ByteBufProcessor byteBufProcessor) {
return 0;
}
@Override
public ByteBuf copy() {
return null;
}
@Override
public ByteBuf copy(int i, int i1) {
return null;
}
@Override
public ByteBuf slice() {
return null;
}
@Override
public ByteBuf slice(int i, int i1) {
return null;
}
@Override
public ByteBuf duplicate() {
return null;
}
@Override
public int nioBufferCount() {
return 0;
}
@Override
public ByteBuffer nioBuffer() {
return null;
}
@Override
public ByteBuffer nioBuffer(int i, int i1) {
return null;
}
@Override
public ByteBuffer internalNioBuffer(int i, int i1) {
return null;
}
@Override
public ByteBuffer[] nioBuffers() {
return new ByteBuffer[0];
}
@Override
public ByteBuffer[] nioBuffers(int i, int i1) {
return new ByteBuffer[0];
}
@Override
public boolean hasArray() {
return false;
}
@Override
public byte[] array() {
return new byte[0];
}
@Override
public int arrayOffset() {
return 0;
}
@Override
public boolean hasMemoryAddress() {
return false;
}
@Override
public long memoryAddress() {
return 0;
}
@Override
public String toString(Charset charset) {
return "";
}
@Override
public String toString(int i, int i1, Charset charset) {
return "";
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object o) {
return false;
}
@Override
public int compareTo(ByteBuf byteBuf) {
return 0;
}
@Override
public String toString() {
return null;
}
@Override
public ByteBuf retain(int i) {
return null;
}
@Override
public boolean release() {
return false;
}
@Override
public boolean release(int i) {
return false;
}
@Override
public int refCnt() {
return 0;
}
@Override
public ByteBuf retain() {
return null;
}
}
@@ -0,0 +1,57 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.wrappers;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
/**
* Utility class for converting between the Adventure API Component and ProtocolLib's wrapper
* <p>
* Note: The Adventure API Component is not included in CraftBukkit, Bukkit or Spigot and but is present in PaperMC.
*/
public class AdventureComponentConverter {
private AdventureComponentConverter() {
}
/**
* Converts a {@link WrappedChatComponent} into a {@link Component}
* @param wrapper ProtocolLib wrapper
* @return Component
*/
public static Component fromWrapper(WrappedChatComponent wrapper) {
return GsonComponentSerializer.gson().deserialize(wrapper.getJson());
}
/**
* Converts a {@link Component} into a ProtocolLib wrapper
* @param components Component
* @return ProtocolLib wrapper
*/
public static WrappedChatComponent fromComponent(Component component) {
return WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component));
}
public static Class<?> getComponentClass() {
return Component.class;
}
public static Component clone(Object component) {
return (Component) component;
}
}
@@ -17,12 +17,16 @@
package com.comphenix.protocol.wrappers;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -42,6 +46,7 @@ import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
@@ -49,12 +54,17 @@ import com.comphenix.protocol.wrappers.EnumWrappers.Dimension;
import com.comphenix.protocol.wrappers.EnumWrappers.FauxEnumConverter;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.advancement.Advancement;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@@ -257,6 +267,87 @@ public class BukkitConverters {
};
}
private static final Map<Class<?>, Supplier<List<Object>>> LIST_SUPPLIERS = new ConcurrentHashMap<>();
private static <T> Object getGenericList(Class<?> listClass, List<T> specific, EquivalentConverter<T> itemConverter) {
List<Object> newList;
Supplier<List<Object>> supplier = LIST_SUPPLIERS.get(listClass);
if (supplier == null) {
try {
Constructor<?> ctor = listClass.getConstructor();
newList = (List<Object>) ctor.newInstance();
supplier = () -> {
try {
return (List<Object>) ctor.newInstance();
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
};
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
supplier = ArrayList::new;
newList = new ArrayList<>();
}
LIST_SUPPLIERS.put(listClass, supplier);
} else {
newList = supplier.get();
}
// Convert each object
for (T position : specific) {
if (position != null) {
Object converted = itemConverter.getGeneric(position);
if (converted != null) {
newList.add(converted);
}
} else {
newList.add(null);
}
}
return newList;
}
private static <T> List<T> getSpecificList(Object generic, EquivalentConverter<T> itemConverter) {
if (generic instanceof Collection) {
List<T> items = new ArrayList<>();
// Copy everything to a new list
for (Object item : (Collection<Object>) generic) {
T result = itemConverter.getSpecific(item);
if (item != null)
items.add(result);
}
return items;
}
// Not valid
return null;
}
public static <T> EquivalentConverter<List<T>> getListConverter(final Class<?> listClass, final EquivalentConverter<T> itemConverter) {
return ignoreNull(new EquivalentConverter<List<T>>() {
@Override
public List<T> getSpecific(Object generic) {
return getSpecificList(generic, itemConverter);
}
@Override
public Object getGeneric(List<T> specific) {
return getGenericList(listClass, specific, itemConverter);
}
@Override
public Class<List<T>> getSpecificType() {
// Damn you Java
Class<?> dummy = List.class;
return (Class<List<T>>) dummy;
}
});
}
/**
* Retrieve an equivalent converter for a list of generic items.
* @param <T> Type
@@ -268,46 +359,12 @@ public class BukkitConverters {
return ignoreNull(new EquivalentConverter<List<T>>() {
@Override
public List<T> getSpecific(Object generic) {
if (generic instanceof Collection) {
List<T> items = new ArrayList<>();
// Copy everything to a new list
for (Object item : (Collection<Object>) generic) {
T result = itemConverter.getSpecific(item);
if (item != null)
items.add(result);
}
return items;
}
// Not valid
return null;
return getSpecificList(generic, itemConverter);
}
@Override
public Object getGeneric(List<T> specific) {
List<Object> newList;
try {
newList = (List<Object>) specific.getClass().newInstance();
} catch (ReflectiveOperationException ex) {
newList = new ArrayList<>();
}
// Convert each object
for (T position : specific) {
if (position != null) {
Object converted = itemConverter.getGeneric(position);
if (converted != null) {
newList.add(converted);
}
} else {
newList.add(null);
}
}
return newList;
return getGenericList(specific.getClass(), specific, itemConverter);
}
@Override
@@ -349,20 +406,6 @@ public class BukkitConverters {
});
}
/**
* @deprecated While this solution is not as abhorrent as I had imagined, I still highly recommend switching to the
* new conversion API.
*/
@Deprecated
public static <T> EquivalentConverter<Set<T>> getSetConverter(final Class<?> genericType,
final EquivalentConverter<T> itemConverter) {
if (itemConverter instanceof EnumWrappers.EnumConverter) {
((EnumWrappers.EnumConverter) itemConverter).setGenericType(genericType);
}
return getSetConverter(itemConverter);
}
/**
* Retrieve an equivalent converter for a set of generic items.
* @param <T> Element type
@@ -700,7 +743,7 @@ public class BukkitConverters {
@Override
public Object getGeneric(EntityType specific) {
if (entityTypeFromName == null) {
Class<?> entityTypesClass = MinecraftReflection.getMinecraftClass("EntityTypes");
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
entityTypeFromName = Accessors.getMethodAccessor(
FuzzyReflection
.fromClass(entityTypesClass, false)
@@ -718,7 +761,7 @@ public class BukkitConverters {
@Override
public EntityType getSpecific(Object generic) {
if (getEntityTypeName == null) {
Class<?> entityTypesClass = MinecraftReflection.getMinecraftClass("EntityTypes");
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
getEntityTypeName = Accessors.getMethodAccessor(
FuzzyReflection
.fromClass(entityTypesClass, false)
@@ -1075,7 +1118,7 @@ public class BukkitConverters {
public Advancement getSpecific(Object generic) {
try {
return (Advancement) getCraftBukkitClass("advancement.CraftAdvancement")
.getConstructor(getMinecraftClass("Advancement"))
.getConstructor(getMinecraftClass("advancements.Advancement", "Advancement"))
.newInstance(generic);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
@@ -1194,7 +1237,12 @@ public class BukkitConverters {
public Object getGeneric(PotionEffectType specific) {
Class<?> clazz = MinecraftReflection.getMobEffectListClass();
if (getMobEffect == null) {
getMobEffect = Accessors.getMethodAccessor(clazz, "fromId", int.class);
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
getMobEffect = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
.parameterExactArray(int.class)
.returnTypeExact(clazz)
.requireModifier(Modifier.STATIC)
.build()));
}
int id = specific.getId();
@@ -1205,7 +1253,12 @@ public class BukkitConverters {
public PotionEffectType getSpecific(Object generic) {
Class<?> clazz = MinecraftReflection.getMobEffectListClass();
if (getMobEffectId == null) {
getMobEffectId = Accessors.getMethodAccessor(clazz, "getId", clazz);
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
getMobEffectId = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
.parameterExactArray(clazz)
.returnTypeExact(int.class)
.requireModifier(Modifier.STATIC)
.build()));
}
int id = (int) getMobEffectId.invoke(null, generic);
@@ -1234,7 +1287,7 @@ public class BukkitConverters {
if (worldKeyField == null) {
Class<?> worldClass = MinecraftReflection.getNmsWorldClass();
Class<?> resourceKeyClass = MinecraftReflection.getMinecraftClass("ResourceKey");
Class<?> resourceKeyClass = MinecraftReflection.getResourceKey();
FuzzyReflection fuzzy = FuzzyReflection.fromClass(nmsWorld.getClass(), true);
worldKeyField = Accessors.getFieldAccessor(fuzzy.getParameterizedField(resourceKeyClass, worldClass));
@@ -1294,14 +1347,95 @@ public class BukkitConverters {
}
}
private static FieldAccessor dimensionKey;
private static MethodAccessor worldHandleAccessor;
private static MethodAccessor worldHandleDimensionManagerAccessor;
public static EquivalentConverter<World> getDimensionConverter() {
return ignoreNull(new EquivalentConverter<World>() {
@Override
public Object getGeneric(World specific) {
return getWorldHandleDimensionManagerAccessor().invoke(getWorldHandleAccessor().invoke(specific));
}
@Override
public World getSpecific(Object generic) {
for (World world : Bukkit.getWorlds()) {
if (getGeneric(world) == generic) {
return world;
}
}
throw new IllegalArgumentException();
}
@Override
public Class<World> getSpecificType() {
return World.class;
}
});
}
private static MethodAccessor getWorldHandleAccessor() {
if (worldHandleAccessor == null) {
Method handleMethod = FuzzyReflection.fromClass(MinecraftReflection.getCraftWorldClass())
.getMethod(FuzzyMethodContract.newBuilder()
.nameExact("getHandle") // i guess this will never change
.returnTypeExact(MinecraftReflection.getWorldServerClass())
.build());
worldHandleAccessor = Accessors.getMethodAccessor(handleMethod);
}
return worldHandleAccessor;
}
private static MethodAccessor getWorldHandleDimensionManagerAccessor() {
if (worldHandleDimensionManagerAccessor == null) {
Method dimensionGetter = FuzzyReflection.fromClass(MinecraftReflection.getWorldServerClass())
.getMethod(FuzzyMethodContract.newBuilder()
.returnTypeExact(MinecraftReflection.getDimensionManager())
.build());
worldHandleDimensionManagerAccessor = Accessors.getMethodAccessor(dimensionGetter);
}
return worldHandleDimensionManagerAccessor;
}
public static EquivalentConverter<Integer> getDimensionIDConverter() {
return ignoreNull(new EquivalentConverter<Integer>() {
@Override
public Object getGeneric(Integer specific) {
if (dimensionManager == null) {
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
dimensionManager = MinecraftReflection.getDimensionManager();
}
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
World world = null;
if (specific == 0) {
world = Bukkit.getWorlds().get(0);
} else if (specific == -1) {
for (World world1 : Bukkit.getWorlds()) {
if (world1.getEnvironment() == World.Environment.NETHER) {
world = world1;
break;
}
}
} else if (specific == 1) {
for (World world1 : Bukkit.getWorlds()) {
if (world1.getEnvironment() == World.Environment.THE_END) {
world = world1;
break;
}
}
}
if (world != null) {
try {
return getWorldHandleDimensionManagerAccessor().invoke(getWorldHandleAccessor().invoke(world));
} catch (Exception ignored) {
// method not available, fall through
}
}
throw new IllegalArgumentException();
}
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
if (dimensionImplConverter == null) {
dimensionImplConverter = new FauxEnumConverter<>(DimensionImpl.class, dimensionManager);
@@ -1335,9 +1469,31 @@ public class BukkitConverters {
@Override
public Integer getSpecific(Object generic) {
if (dimensionManager == null) {
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
dimensionManager = MinecraftReflection.getDimensionManager();
}
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
if (dimensionKey == null) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(dimensionManager, false);
dimensionKey = Accessors.getFieldAccessor(fuzzy.getField(FuzzyFieldContract
.newBuilder()
.typeExact(MinecraftReflection.getMinecraftKeyClass())
.banModifier(Modifier.STATIC)
.build()));
}
MinecraftKey key = MinecraftKey.fromHandle(dimensionKey.get(generic));
switch (key.getKey()) {
case "overworld":
return Dimension.OVERWORLD.getId();
case "the_nether":
return Dimension.THE_NETHER.getId();
case "the_end":
return Dimension.THE_END.getId();
default:
throw new IllegalArgumentException("id not supported for extra dimensions");
}
}
if (MinecraftVersion.NETHER_UPDATE_2.atOrAbove()) {
if (dimensionImplConverter == null) {
dimensionImplConverter = new FauxEnumConverter<>(DimensionImpl.class, dimensionManager);
@@ -1393,7 +1549,7 @@ public class BukkitConverters {
@Override
public Object getGeneric(List<MerchantRecipe> specific) {
if (merchantRecipeListConstructor == null) {
Class<?> merchantRecipeListClass = MinecraftReflection.getMinecraftClass("MerchantRecipeList");
Class<?> merchantRecipeListClass = MinecraftReflection.getMerchantRecipeList();
merchantRecipeListConstructor = Accessors.getConstructorAccessor(merchantRecipeListClass);
Class<?> craftMerchantRecipeClass = MinecraftReflection.getCraftBukkitClass("inventory.CraftMerchantRecipe");
FuzzyReflection reflection = FuzzyReflection.fromClass(craftMerchantRecipeClass, false);
@@ -1407,7 +1563,9 @@ public class BukkitConverters {
@Override
public List<MerchantRecipe> getSpecific(Object generic) {
if (nmsMerchantRecipeToBukkit == null) {
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass("MerchantRecipe");
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass(
"world.item.trading.MerchantRecipe","MerchantRecipe"
);
FuzzyReflection reflection = FuzzyReflection.fromClass(merchantRecipeClass, false);
nmsMerchantRecipeToBukkit = Accessors.getMethodAccessor(reflection.getMethodByName("asBukkit"));
}
@@ -1432,7 +1590,7 @@ public class BukkitConverters {
@Override
public Object getGeneric(BlockPosition specific) {
if (sectionPositionClass == null) {
sectionPositionClass = MinecraftReflection.getMinecraftClass("SectionPosition");
sectionPositionClass = MinecraftReflection.getSectionPosition();
}
if (sectionPositionCreate == null) {
@@ -1461,4 +1619,73 @@ public class BukkitConverters {
}
});
}
private static Field gameStateMapField;
private static Field gameStateIdField;
public static EquivalentConverter<Integer> getGameStateConverter() {
return new EquivalentConverter<Integer>() {
@Override
public Object getGeneric(Integer specific) {
if (specific == null) {
specific = 0;
}
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
if (gameStateMapField == null) {
Class<?> stateClass = MinecraftReflection.getGameStateClass();
gameStateMapField = FuzzyReflection
.fromClass(stateClass, true)
.getField(FuzzyFieldContract
.newBuilder()
.typeDerivedOf(Map.class)
.build());
gameStateMapField.setAccessible(true);
}
try {
Map<Integer, Object> map = (Map<Integer, Object>) gameStateMapField.get(null);
return map.get(specific);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
} else {
return specific;
}
}
@Override
public Integer getSpecific(Object generic) {
if (generic == null) {
return 0;
}
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
if (gameStateIdField == null) {
Class<?> stateClass = MinecraftReflection.getGameStateClass();
gameStateIdField = FuzzyReflection
.fromClass(stateClass, true)
.getField(FuzzyFieldContract
.newBuilder()
.typeExact(int.class)
.build());
gameStateIdField.setAccessible(true);
}
try {
return (Integer) gameStateIdField.get(generic);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
} else {
return (Integer) generic;
}
}
@Override
public Class<Integer> getSpecificType() {
return Integer.class;
}
};
}
}
@@ -1,12 +1,18 @@
package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Objects;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
/**
* Represents a ChunkCoordIntPair.
* @author Kristian
@@ -79,9 +85,14 @@ public class ChunkCoordIntPair {
public ChunkCoordIntPair getSpecific(Object generic) {
if (MinecraftReflection.isChunkCoordIntPair(generic)) {
if (COORD_X == null || COORD_Z == null) {
FieldAccessor[] ints = Accessors.getFieldAccessorArray(COORD_PAIR_CLASS, int.class, true);
COORD_X = ints[0];
COORD_Z = ints[1];
FuzzyReflection fuzzy = FuzzyReflection.fromClass(COORD_PAIR_CLASS, true);
List<Field> fields = fuzzy.getFieldList(FuzzyFieldContract
.newBuilder()
.banModifier(Modifier.STATIC)
.typeExact(int.class)
.build());
COORD_X = Accessors.getFieldAccessor(fields.get(0));
COORD_Z = Accessors.getFieldAccessor(fields.get(1));
}
return new ChunkCoordIntPair((Integer) COORD_X.get(generic), (Integer) COORD_Z.get(generic));
}
@@ -17,6 +17,7 @@
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Array;
import java.util.Optional;
import java.util.function.Function;
import com.comphenix.protocol.reflect.EquivalentConverter;
@@ -150,4 +151,24 @@ public class Converters {
}
};
}
public static <T> EquivalentConverter<Optional<T>> optional(final EquivalentConverter<T> converter) {
return new EquivalentConverter<Optional<T>>() {
@Override
public Object getGeneric(Optional<T> specific) {
return specific.map(converter::getGeneric);
}
@Override
public Optional<T> getSpecific(Object generic) {
Optional<Object> optional = (Optional<Object>) generic;
return optional.map(converter::getSpecific);
}
@Override
public Class<Optional<T>> getSpecificType() {
return (Class<Optional<T>>) Optional.empty().getClass();
}
};
}
}
@@ -10,6 +10,7 @@ import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Maps;
@@ -481,7 +482,6 @@ public abstract class EnumWrappers {
DIFFICULTY_CLASS = getEnum(PacketType.Play.Server.LOGIN.getPacketClass(), 1);
}
ENTITY_USE_ACTION_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 0);
GAMEMODE_CLASS = getEnum(PacketType.Play.Server.LOGIN.getPacketClass(), 0);
RESOURCE_PACK_STATUS_CLASS = getEnum(PacketType.Play.Client.RESOURCE_PACK_STATUS.getPacketClass(), 0);
PLAYER_INFO_ACTION_CLASS = getEnum(PacketType.Play.Server.PLAYER_INFO.getPacketClass(), 0);
@@ -496,21 +496,29 @@ public abstract class EnumWrappers {
try {
// TODO enum names are more stable than their packet associations
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("EnumItemSlot");
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("world.entity.EnumItemSlot", "EnumItemSlot");
} catch (Exception ex) {
ITEM_SLOT_CLASS = getEnum(PacketType.Play.Server.ENTITY_EQUIPMENT.getPacketClass(), 0);
}
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
// In 1.17 the hand and use action class is no longer a field in the packet
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
HAND_CLASS = MinecraftReflection.getMinecraftClass("world.EnumHand");
// class is named 'b' in the packet but class order differs in spigot and paper so we can only use the first method's return type (safest way)
ENTITY_USE_ACTION_CLASS = MinecraftReflection.getEnumEntityUseActionClass().getMethods()[0].getReturnType();
} else {
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
ENTITY_USE_ACTION_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 0);
}
DIRECTION_CLASS = getEnum(PacketType.Play.Server.SPAWN_ENTITY_PAINTING.getPacketClass(), 0);
CHAT_TYPE_CLASS = getEnum(PacketType.Play.Server.CHAT.getPacketClass(), 0);
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("EntityPose");
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("world.entity.EntityPose", "EntityPose");
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
associate(CHAT_VISIBILITY_CLASS, ChatVisibility.class, getChatVisibilityConverter());
associate(DIFFICULTY_CLASS, Difficulty.class, getDifficultyConverter());
associate(ENTITY_USE_ACTION_CLASS, EntityUseAction.class, getEntityUseActionConverter());
associate(GAMEMODE_CLASS, NativeGameMode.class, getGameModeConverter());
associate(RESOURCE_PACK_STATUS_CLASS, ResourcePackStatus.class, getResourcePackStatusConverter());
associate(PLAYER_INFO_ACTION_CLASS, PlayerInfoAction.class, getPlayerInfoActionConverter());
@@ -523,15 +531,14 @@ public abstract class EnumWrappers {
associate(PARTICLE_CLASS, Particle.class, getParticleConverter());
associate(SOUND_CATEGORY_CLASS, SoundCategory.class, getSoundCategoryConverter());
associate(ITEM_SLOT_CLASS, ItemSlot.class, getItemSlotConverter());
associate(HAND_CLASS, Hand.class, getHandConverter());
associate(DIRECTION_CLASS, Direction.class, getDirectionConverter());
associate(CHAT_TYPE_CLASS, ChatType.class, getChatTypeConverter());
associate(HAND_CLASS, Hand.class, getHandConverter());
associate(ENTITY_USE_ACTION_CLASS, EntityUseAction.class, getEntityUseActionConverter());
if (ENTITY_POSE_CLASS != null) {
associate(ENTITY_POSE_CLASS, EntityPose.class, getEntityPoseConverter());
}
INITIALIZED = true;
}
private static void associate(Class<?> nativeClass, Class<?> wrapperClass, EquivalentConverter<?> converter) {
@@ -550,12 +557,19 @@ public abstract class EnumWrappers {
* @return The type of the enum field.
*/
private static Class<?> getEnum(Class<?> clazz, int index) {
try {
return FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class).get(index).getType();
} catch (Throwable ex) {
ProtocolLogger.debug("Exception getting enum from " + clazz + " at index " + index, ex);
if (clazz == null) {
// not supported in the current version
return null;
}
List<Field> enumFields = FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class);
if (enumFields.size() <= index) {
// also probably not supported
ProtocolLogger.debug("Enum field not found at index {0} of {1}", index, clazz);
return null;
}
return enumFields.get(index).getType();
}
public static Map<Class<?>, EquivalentConverter<?>> getFromNativeMap() {
@@ -772,22 +786,17 @@ public abstract class EnumWrappers {
return new EnumConverter<>(genericClass, specificType);
}
/**
* @deprecated Replaced with {@link #getGenericConverter(Class, Class)}
*/
@Deprecated
public static <T extends Enum<T>> EquivalentConverter<T> getGenericConverter(Class<T> specificType) {
return new EnumConverter<>(null, specificType);
}
/**
* The common Enum converter
*/
public static class EnumConverter<T extends Enum<T>> implements EquivalentConverter<T> {
private Class<?> genericType;
private Class<T> specificType;
private final Class<?> genericType;
private final Class<T> specificType;
public EnumConverter(Class<?> genericType, Class<T> specificType) {
Validate.notNull(specificType, "specificType cannot be null");
// would love to check if genericType is null, but it breaks other stuff
this.genericType = genericType;
this.specificType = specificType;
}
@@ -806,10 +815,6 @@ public abstract class EnumWrappers {
public Class<T> getSpecificType() {
return specificType;
}
void setGenericType(Class<?> genericType) {
this.genericType = genericType;
}
}
public interface AliasedEnum {
@@ -10,7 +10,8 @@ import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
import org.bukkit.util.Vector;
public class MovingObjectPositionBlock implements Cloneable {
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("MovingObjectPositionBlock");
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
"world.phys.MovingObjectPositionBlock", "MovingObjectPositionBlock");
private BlockPosition position;
private Vector posVector;
@@ -17,10 +17,14 @@
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
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;
@@ -94,14 +98,17 @@ public class PlayerInfoData {
public Object getGeneric(PlayerInfoData specific) {
if (constructor == null) {
try {
// public PlayerInfoData(Packet, GameProfile, int, GameMode, ChatComponent)
constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor(
MinecraftReflection.getMinecraftClass("PacketPlayOutPlayerInfo"),
MinecraftReflection.getGameProfileClass(),
int.class,
EnumWrappers.getGameModeClass(),
MinecraftReflection.getIChatBaseComponentClass()
);
List<Class<?>> args = new ArrayList<>();
if (!MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
args.add(PacketType.Play.Server.PLAYER_INFO.getPacketClass());
}
args.add(MinecraftReflection.getGameProfileClass());
args.add(int.class);
args.add(EnumWrappers.getGameModeClass());
args.add(MinecraftReflection.getIChatBaseComponentClass());
constructor = MinecraftReflection.getPlayerInfoDataClass().getConstructor(args.toArray(new Class<?>[0]));
} catch (Exception e) {
throw new RuntimeException("Cannot find PlayerInfoData constructor.", e);
}
@@ -110,16 +117,14 @@ public class PlayerInfoData {
// Attempt to construct the underlying PlayerInfoData
try {
// public PlayerInfoData(null, GameProfile, ping, GameMode, ChatComponent)
// The packet isn't a field, so it can be null
Object result = constructor.newInstance(
null,
specific.profile.handle,
specific.latency,
EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode),
specific.displayName != null ? specific.displayName.handle : null
);
return result;
Object gameMode = EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode);
Object displayName = specific.displayName != null ? specific.displayName.handle : null;
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
return constructor.newInstance(specific.profile.handle, specific.latency, gameMode, displayName);
} else {
return constructor.newInstance(null, specific.profile.handle, specific.latency, gameMode, displayName);
}
} catch (Exception e) {
throw new RuntimeException("Failed to construct PlayerInfoData.", e);
}
@@ -83,10 +83,10 @@ public class Vector3F {
}
private static Constructor<?> constructor = null;
private static Class<?> clazz = MinecraftReflection.getMinecraftClass("Vector3f");
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f","Vector3f");
public static Class<?> getMinecraftClass() {
return clazz;
return NMS_CLASS;
}
public static EquivalentConverter<Vector3F> getConverter() {
@@ -100,7 +100,7 @@ public class Vector3F {
public Object getGeneric(Vector3F specific) {
if (constructor == null) {
try {
constructor = clazz.getConstructor(float.class, float.class, float.class);
constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
}
@@ -3,13 +3,12 @@ package com.comphenix.protocol.wrappers;
import java.lang.reflect.Constructor;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
@@ -34,9 +33,6 @@ public class WrappedAttribute extends AbstractWrapper {
// The one constructor
private static Constructor<?> ATTRIBUTE_CONSTRUCTOR;
private static Object REGISTRY = null;
private static MethodAccessor REGISTRY_GET = null;
private static final Map<String, String> REMAP;
static {
@@ -76,7 +72,7 @@ public class WrappedAttribute extends AbstractWrapper {
// Initialize modifier
if (ATTRIBUTE_MODIFIER == null) {
ATTRIBUTE_MODIFIER = new StructureModifier<Object>(MinecraftReflection.getAttributeSnapshotClass());
ATTRIBUTE_MODIFIER = new StructureModifier<>(MinecraftReflection.getAttributeSnapshotClass());
}
this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle);
}
@@ -115,7 +111,9 @@ public class WrappedAttribute extends AbstractWrapper {
public String key;
}
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS("AttributeBase");
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.ai.attributes.AttributeBase", "AttributeBase"
);
private static final AutoWrapper<WrappedAttributeBase> ATTRIBUTE_BASE = AutoWrapper.wrap(
WrappedAttributeBase.class, ATTRIBUTE_BASE_CLASS
@@ -167,8 +165,14 @@ public class WrappedAttribute extends AbstractWrapper {
/**
* Retrieve the parent update attributes packet.
* @return The parent packet.
* @deprecated Removed in 1.17
*/
@Nullable
public PacketContainer getParentPacket() {
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
return null;
}
return new PacketContainer(
PacketType.Play.Server.UPDATE_ATTRIBUTES,
modifier.withType(MinecraftReflection.getPacketClass()).read(0)
@@ -223,7 +227,7 @@ public class WrappedAttribute extends AbstractWrapper {
}
};
attributeModifiers = new CachedSet<WrappedAttributeModifier>(converted);
attributeModifiers = new CachedSet<>(converted);
}
return Collections.unmodifiableSet(attributeModifiers);
}
@@ -246,9 +250,7 @@ public class WrappedAttribute extends AbstractWrapper {
if (getBaseValue() == other.getBaseValue() &&
Objects.equal(getAttributeKey(), other.getAttributeKey())) {
return getModifiers().stream()
.filter((elem) -> !other.getModifiers().contains(elem))
.count() == 0;
return other.getModifiers().containsAll(getModifiers());
}
}
return false;
@@ -411,45 +413,33 @@ public class WrappedAttribute extends AbstractWrapper {
* @throws RuntimeException If anything went wrong with the reflection.
*/
public WrappedAttribute build() {
Preconditions.checkNotNull(packet, "packet cannot be NULL.");
Preconditions.checkNotNull(attributeKey, "attributeKey cannot be NULL.");
// Remember to set the base value
if (Double.isNaN(baseValue)) {
throw new IllegalStateException("Base value has not been set.");
}
// Retrieve the correct constructor
boolean isStatic = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
if (ATTRIBUTE_CONSTRUCTOR == null) {
ATTRIBUTE_CONSTRUCTOR = FuzzyReflection.fromClass(MinecraftReflection.getAttributeSnapshotClass(), true)
.getConstructor(FuzzyMethodContract.newBuilder().parameterCount(4)
.parameterDerivedOf(MinecraftReflection.getPacketClass(), 0)
.parameterExactType(double.class, 2).parameterDerivedOf(Collection.class, 3)
.build()
);
FuzzyReflection ref = FuzzyReflection.fromClass(MinecraftReflection.getAttributeSnapshotClass(), true);
FuzzyMethodContract.Builder contract = FuzzyMethodContract.newBuilder().parameterCount(isStatic ? 3 : 4);
if (!isStatic) {
contract.parameterDerivedOf(MinecraftReflection.getPacketClass(), 0);
}
contract.parameterExactType(double.class).parameterDerivedOf(Collection.class);
ATTRIBUTE_CONSTRUCTOR = ref.getConstructor(contract.build());
// Just in case
ATTRIBUTE_CONSTRUCTOR.setAccessible(true);
}
Object attributeKey;
if (KEY_WRAPPED) {
if (REGISTRY == null) {
Class<?> iRegistry = MinecraftReflection.getMinecraftClass("IRegistry");
try {
REGISTRY = iRegistry.getDeclaredField("ATTRIBUTE").get(null);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to obtain ATTRIBUTE registry", ex);
}
}
if (REGISTRY_GET == null) {
Class<?> keyClass = MinecraftReflection.getMinecraftKeyClass();
REGISTRY_GET = Accessors.getMethodAccessor(REGISTRY.getClass(), "get", keyClass);
}
WrappedRegistry registry = WrappedRegistry.getAttributeRegistry();
String strKey = REMAP.getOrDefault(this.attributeKey, this.attributeKey);
Object key = MinecraftKey.getConverter().getGeneric(new MinecraftKey(strKey));
attributeKey = REGISTRY_GET.invoke(REGISTRY, key);
attributeKey = registry.get(strKey);
if (attributeKey == null) {
throw new IllegalArgumentException("Invalid attribute name: " + this.attributeKey);
@@ -459,15 +449,14 @@ public class WrappedAttribute extends AbstractWrapper {
}
try {
Object handle = ATTRIBUTE_CONSTRUCTOR.newInstance(
packet.getHandle(),
attributeKey,
baseValue,
getUnwrappedModifiers());
Object handle;
if (isStatic) {
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(attributeKey, baseValue, getUnwrappedModifiers());
} else {
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(packet.getHandle(), attributeKey, baseValue, getUnwrappedModifiers());
}
// Create it
return new WrappedAttribute(handle);
} catch (Exception e) {
throw new RuntimeException("Cannot construct AttributeSnapshot.", e);
}
@@ -66,7 +66,9 @@ public class WrappedAttributeModifier extends AbstractWrapper {
}
static {
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass("AttributeModifier$Operation") : null;
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass(
"world.entity.ai.attributes.AttributeModifier$Operation", "AttributeModifier$Operation"
) : null;
OPERATION_CONVERTER = OPERATION_ENUM ? new IndexedEnumConverter<>(Operation.class, OPERATION_CLASS) : null;
}
@@ -42,7 +42,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
}
try {
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getMinecraftClass("ChatDeserializer"), true)
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getChatDeserializer(), true)
.getMethodByParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
} catch (IllegalArgumentException ex) {
// We'll handle it in the ComponentParser
@@ -50,7 +50,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
}
// Get a component from a standard Minecraft message
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class, boolean.class);
// And the component text constructor
CONSTRUCT_TEXT_COMPONENT = Accessors.getConstructorAccessor(MinecraftReflection.getChatComponentTextClass(), String.class);
@@ -95,6 +95,9 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
/**
* Construct a wrapper around a new text chat component with the given text.
* <p>
* Note: {@link #fromLegacyText(String)} is preferred for text that contains
* legacy formatting codes since it will translate them to the JSON equivalent.
* @param text - the text of the text chat component.
* @return The wrapper around the new chat component.
*/
@@ -111,7 +114,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
* @return The equivalent chat components.
*/
public static WrappedChatComponent[] fromChatMessage(String message) {
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message);
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message, false);
WrappedChatComponent[] result = new WrappedChatComponent[components.length];
for (int i = 0; i < components.length; i++) {
@@ -120,6 +123,18 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
return result;
}
/**
* Construct a single chat component from a standard Minecraft message
* (with legacy formatting codes), preserving multiple lines.
* @param message - the message.
* @return The equivalent chat component.
*/
public static WrappedChatComponent fromLegacyText(String message) {
// With keepNewlines = true (second parameter), only one component is returned
Object[] components = (Object[]) CONSTRUCT_COMPONENT.invoke(null, message, true);
return fromHandle(components[0]);
}
/**
* Retrieve a copy of this component as a JSON string.
* <p>
@@ -129,8 +129,10 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
// We can create a fake egg without it affecting anything
// Mojang added difficulty to lightning strikes, so this'll have to do
if (eggConstructor == null) {
eggConstructor = Accessors.getConstructorAccessor(MinecraftReflection.getMinecraftClass("EntityEgg"),
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class);
eggConstructor = Accessors.getConstructorAccessor(
MinecraftReflection.getMinecraftClass("world.entity.projectile.EntityEgg", "EntityEgg"),
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class
);
}
Object world = BukkitUnwrapper.getInstance().unwrapItem(Bukkit.getWorlds().get(0));
@@ -0,0 +1,200 @@
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
import org.bukkit.util.Vector;
/**
* Represents an entity used action used in the UseEntity packet sent by the client.
* @author derklaro
*/
public class WrappedEnumEntityUseAction extends AbstractWrapper implements ClonableWrapper {
public static final EquivalentConverter<WrappedEnumEntityUseAction> CONVERTER = Converters.handle(AbstractWrapper::getHandle,
WrappedEnumEntityUseAction::fromHandle, WrappedEnumEntityUseAction.class);
private static final Class<?> PACKET_CLASS = PacketType.Play.Client.USE_ENTITY.getPacketClass();
private static final Class<?>[] DECLARED_CLASSES = PACKET_CLASS.getDeclaredClasses();
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getEnumEntityUseActionClass();
private static final MethodAccessor ACTION_USE = MinecraftReflection.getEntityUseActionEnumMethodAccessor();
private static final ConstructorAccessor INTERACT = useAction(EnumWrappers.getHandClass());
private static final ConstructorAccessor INTERACT_AT = useAction(EnumWrappers.getHandClass(),
MinecraftReflection.getVec3DClass());
private static final Object ATTACK = Accessors.getFieldAccessor(FuzzyReflection.fromClass(PACKET_CLASS, true)
.getField(FuzzyFieldContract.newBuilder()
.requireModifier(Modifier.STATIC)
.typeExact(MinecraftReflection.getEnumEntityUseActionClass())
.build())
).get(null);
private static final WrappedEnumEntityUseAction ATTACK_WRAPPER = new WrappedEnumEntityUseAction(ATTACK);
private final EntityUseAction action;
// these fields are only available for interact & interact_at
private FieldAccessor handAccessor;
private FieldAccessor positionAccessor;
/**
* Construct a new wrapper for the entity use action class in the UseEntity packet.
* @param handle - the NMS handle.
*/
private WrappedEnumEntityUseAction(Object handle) {
super(HANDLE_TYPE);
setHandle(handle);
action = EnumWrappers.getEntityUseActionConverter().getSpecific(ACTION_USE.invoke(handle));
}
/**
* Finds a constructor of a declared class in the UseEntity class. Used to find the action class implementations.
* @param parameterTypes - the types the constructor of the class must have.
* @return a constructor for a matching class.
* @throws IllegalArgumentException if no constructor was found.
*/
private static ConstructorAccessor useAction(Class<?>... parameterTypes) {
for (Class<?> subClass : DECLARED_CLASSES) {
ConstructorAccessor accessor = Accessors.getConstructorAccessorOrNull(subClass, parameterTypes);
if (accessor != null) {
return accessor;
}
}
throw new IllegalArgumentException(
"No constructor with " + Arrays.toString(parameterTypes) + " in " + PACKET_CLASS);
}
/**
* Construct a new wrapper for the entity use action class in the UseEntity packet.
* @param handle - the NMS handle.
* @return the created wrapper.
*/
public static WrappedEnumEntityUseAction fromHandle(Object handle) {
return new WrappedEnumEntityUseAction(handle);
}
/**
* Get the jvm static action for attacking an entity.
* @return the action for an entity attack.
*/
public static WrappedEnumEntityUseAction attack() {
return ATTACK_WRAPPER;
}
/**
* Get an action for interacting with an entity.
* @param hand - the hand used for the interact.
* @return the action for an interact.
*/
public static WrappedEnumEntityUseAction interact(Hand hand) {
Object handle = INTERACT.invoke(EnumWrappers.getHandConverter().getGeneric(hand));
return new WrappedEnumEntityUseAction(handle);
}
/**
* Get an action for interacting with an entity at a specific location.
* @param hand - the hand used for the interact.
* @param vector - the position of the interact.
* @return the action for an interact_at.
*/
public static WrappedEnumEntityUseAction interactAt(Hand hand, Vector vector) {
Object handle = INTERACT_AT.invoke(EnumWrappers.getHandConverter().getGeneric(hand),
BukkitConverters.getVectorConverter().getGeneric(vector));
return new WrappedEnumEntityUseAction(handle);
}
/**
* Get the action used for the interact.
* @return the interact action.
*/
public EntityUseAction getAction() {
return action;
}
/**
* Get the hand used for the interact. Only available if this represents interact or interact_at.
* @return the hand used for the interact.
* @throws IllegalArgumentException if called for attack.
*/
public Hand getHand() {
return EnumWrappers.getHandConverter().getSpecific(getHandAccessor().get(handle));
}
/**
* Sets the hand used for the interact.
* @param hand the used hand.
* @throws IllegalArgumentException if called for attack.
*/
public void setHand(Hand hand) {
getHandAccessor().set(handle, EnumWrappers.getHandConverter().getGeneric(hand));
}
/**
* Get the position of the interact. Only available if this represents interact_at.
* @return the position of the interact.
* @throws IllegalArgumentException if called for attack or interact.
*/
public Vector getPosition() {
return BukkitConverters.getVectorConverter().getSpecific(getPositionAccessor().get(handle));
}
/**
* Sets the position of the interact.
* @param position the position.
* @throws IllegalArgumentException if called for attack or interact.
*/
public void setPosition(Vector position) {
getPositionAccessor().set(handle, BukkitConverters.getVectorConverter().getGeneric(position));
}
@Override
public WrappedEnumEntityUseAction deepClone() {
switch (action) {
case ATTACK:
return WrappedEnumEntityUseAction.attack();
case INTERACT:
return WrappedEnumEntityUseAction.interact(getHand());
case INTERACT_AT:
return WrappedEnumEntityUseAction.interactAt(getHand(), getPosition());
default:
throw new IllegalArgumentException("Invalid EntityUseAction: " + action);
}
}
/**
* Get a field accessor for the hand in the interact and interact_at type.
* @return a field accessor for the hand field.
* @throws IllegalArgumentException if called for attack.
*/
private FieldAccessor getHandAccessor() {
if (handAccessor == null) {
handAccessor = MinecraftReflection.getHandEntityUseActionEnumFieldAccessor(handle);
}
return handAccessor;
}
/**
* Get a field accessor for the position in the interact_at type.
* @return a field accessor for the position field.
* @throws IllegalArgumentException if called for attack or interact.
*/
public FieldAccessor getPositionAccessor() {
if (positionAccessor == null) {
positionAccessor = MinecraftReflection.getVec3EntityUseActionEnumFieldAccessor(handle);
}
return positionAccessor;
}
}
@@ -9,6 +9,8 @@ import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.mojang.math.Vector3fa;
import org.bukkit.Color;
import org.bukkit.Particle;
import org.bukkit.inventory.ItemStack;
@@ -31,14 +33,14 @@ public class WrappedParticle<T> {
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(Particle.class)
.parameterExactType(MinecraftReflection.getMinecraftClass("ParticleParam"))
.parameterExactType(MinecraftReflection.getParticleParam())
.build();
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
contract = FuzzyMethodContract
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(MinecraftReflection.getMinecraftClass("ParticleParam"))
.returnTypeExact(MinecraftReflection.getParticleParam())
.parameterCount(2)
.build();
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
@@ -130,12 +132,26 @@ public class WrappedParticle<T> {
}
private static Object getRedstone(Object handle) {
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
return new Particle.DustOptions(Color.fromRGB(
(int) (modifier.read(0) * 255),
(int) (modifier.read(1) * 255),
(int) (modifier.read(2) * 255)),
modifier.read(3));
int r, g, b;
float alpha;
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0);
r = (int) (rgb.a() * 255);
g = (int) (rgb.b() * 255);
b = (int) (rgb.c() * 255);
alpha = (float) modifier.withType(float.class).read(0);
} else {
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
r = (int) (modifier.read(0) * 255);
g = (int) (modifier.read(1) * 255);
b = (int) (modifier.read(2) * 255);
alpha = modifier.read(3);
}
return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha);
}
public static <T> WrappedParticle<T> create(Particle particle, T data) {
@@ -0,0 +1,86 @@
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.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Field;
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);
GET = Accessors.getMethodAccessor(regClass, "get", MinecraftReflection.getMinecraftKeyClass());
FuzzyReflection fuzzy = FuzzyReflection.fromClass(regClass, false);
GET_KEY = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
.newBuilder()
.parameterCount(1)
.returnTypeExact(MinecraftReflection.getMinecraftKeyClass())
.build()));
}
private final Object handle;
private WrappedRegistry(Object handle) {
this.handle = handle;
}
public Object get(MinecraftKey key) {
return GET.invoke(handle, MinecraftKey.getConverter().getGeneric(key));
}
public Object get(String key) {
return get(new MinecraftKey(key));
}
public MinecraftKey getKey(Object generic) {
return MinecraftKey.getConverter().getSpecific(GET_KEY.invoke(handle, generic));
}
// TODO add more methods
public static WrappedRegistry getAttributeRegistry() {
return REGISTRY.get(MinecraftReflection.getAttributeBase());
}
public static WrappedRegistry getDimensionRegistry() {
return REGISTRY.get(MinecraftReflection.getDimensionManager());
}
}
@@ -161,7 +161,7 @@ public class WrappedServerPing extends AbstractWrapper implements ClonableWrappe
* @param message - the message.
*/
public void setMotD(String message) {
setMotD(WrappedChatComponent.fromText(message));
setMotD(WrappedChatComponent.fromLegacyText(message));
}
/**
@@ -7,9 +7,12 @@ import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
public class WrappedVillagerData extends AbstractWrapper implements ClonableWrapper {
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("VillagerData");
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS("VillagerType");
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS("VillagerProfession");
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.npc.VillagerData","VillagerData");
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.npc.VillagerType", "VillagerType");
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.npc.VillagerProfession", "VillagerProfession");
private static EquivalentConverter<Type> TYPE_CONVERTER;
private static EquivalentConverter<Profession> PROF_CONVERTER;
@@ -592,7 +592,7 @@ public class NbtFactory {
Constructor<?> constructor = CONSTRUCTORS.get(type);
if (constructor == null) {
if (getTagType == null) {
Class<?> tagTypes = MinecraftReflection.getMinecraftClass("NBTTagTypes");
Class<?> tagTypes = MinecraftReflection.getNbtTagTypes();
FuzzyReflection fuzzy = FuzzyReflection.fromClass(tagTypes, false);
getTagType = fuzzy.getMethod(
FuzzyMethodContract.newBuilder().parameterCount(1).parameterExactType(int.class).build());
@@ -35,7 +35,8 @@ import org.bukkit.block.BlockState;
* @author Kristian
*/
class TileEntityAccessor<T extends BlockState> {
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove();
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove()
&& !MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
/**
* Token indicating that the given block state doesn't contain any tile entities.
@@ -5,18 +5,21 @@ import java.util.List;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.utility.Constants;
import com.mojang.bridge.game.GameVersion;
import net.minecraft.server.v1_16_R3.DispenserRegistry;
import net.minecraft.server.v1_16_R3.WorldServer;
import net.minecraft.SharedConstants;
import net.minecraft.core.IRegistry;
import net.minecraft.server.DispenserRegistry;
import net.minecraft.server.level.WorldServer;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_16_R3.util.Versioning;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_17_R1.util.Versioning;
import org.spigotmc.SpigotWorldConfig;
import static org.mockito.Mockito.mock;
@@ -53,8 +56,6 @@ public class BukkitInitialization {
// Denote that we're done
initialized = true;
initializePackage();
try {
LogManager.getLogger();
} catch (Throwable ex) {
@@ -62,8 +63,17 @@ public class BukkitInitialization {
ex.printStackTrace();
}
initializePackage();
SharedConstants.a();
DispenserRegistry.init();
try {
IRegistry.class.getName();
} catch (Throwable ex) {
ex.printStackTrace();
}
// Mock the server object
Server mockedServer = mock(Server.class);
@@ -22,14 +22,15 @@ 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 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 net.minecraft.network.EnumProtocol;
import net.minecraft.network.protocol.EnumProtocolDirection;
import net.minecraft.network.protocol.login.PacketLoginInStart;
import org.apache.commons.lang.WordUtils;
import org.junit.AfterClass;
@@ -45,9 +46,11 @@ public class PacketTypeTest {
@BeforeClass
public static void beforeClass() {
BukkitInitialization.initializeItemMeta();
// 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);
throw new RuntimeException("Dynamically generated packet " + className);
};
}
@@ -67,7 +70,7 @@ public class PacketTypeTest {
for (EnumProtocol protocol : protocols) {
System.out.println(WordUtils.capitalize(protocol.name().toLowerCase()));
Field field = EnumProtocol.class.getDeclaredField("h");
Field field = EnumProtocol.class.getDeclaredField("j");
field.setAccessible(true);
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
@@ -144,17 +147,30 @@ public class PacketTypeTest {
String fullName = clazz.getName();
fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
List<String> classNames = new ArrayList<>(2);
for (String name : fullName.split("\\$")) {
List<String> split = splitOnCaps(name);
StringBuilder nameBuilder = new StringBuilder();
for (int i = 3; i < split.size(); i++) {
nameBuilder.append(split.get(i));
String className;
List<String> classNames = new ArrayList<>();
if (fullName.endsWith("Packet")) {
for (String name : fullName.split("\\$")) {
List<String> split = splitOnCaps(name);
StringBuilder nameBuilder = new StringBuilder();
for (int i = 1; i < split.size() - 1; i++) {
nameBuilder.append(split.get(i));
}
classNames.add(nameBuilder.toString());
}
} else {
for (String name : fullName.split("\\$")) {
List<String> split = splitOnCaps(name);
StringBuilder nameBuilder = new StringBuilder();
for (int i = 3; i < split.size(); i++) {
nameBuilder.append(split.get(i));
}
classNames.add(nameBuilder.toString());
}
classNames.add(nameBuilder.toString());
}
String className = classNames.get(classNames.size() - 1);
className = classNames.get(classNames.size() - 1);
// Format it like SET_PROTOCOL
StringBuilder fieldName = new StringBuilder();
@@ -208,6 +224,7 @@ 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);
}
@@ -262,7 +279,7 @@ public class PacketTypeTest {
EnumProtocol[] protocols = EnumProtocol.values();
for (EnumProtocol protocol : protocols) {
Field field = EnumProtocol.class.getDeclaredField("h");
Field field = EnumProtocol.class.getDeclaredField("j");
field.setAccessible(true);
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
@@ -293,4 +310,20 @@ public class PacketTypeTest {
assertTrue("Packet type(s) were incorrect!", !fail);
}
@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("Packet type(s) failed to instantiate", fail);
}
}
@@ -16,6 +16,8 @@
*/
package com.comphenix.protocol.events;
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;
@@ -38,10 +40,20 @@ import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.collect.Lists;
import net.md_5.bungee.api.chat.*;
import net.minecraft.server.v1_16_R3.*;
import net.minecraft.server.v1_16_R3.MinecraftKey;
import net.minecraft.server.v1_16_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.core.IRegistry;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
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.resources.MinecraftKey;
import net.minecraft.world.entity.npc.VillagerData;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerType;
import net.minecraft.world.level.dimension.DimensionManager;
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.bukkit.ChatColor;
@@ -95,7 +107,7 @@ public class PacketContainerTest {
private <T> void testObjectArray(StructureModifier<T[]> modifier, int index, T[] initialValue, T[] testValue) {
// Check initial value
assertNull(modifier.read(index));
assertEquals(modifier.read(index).length, initialValue.length);
modifier.writeDefaults();
// Test initial
@@ -133,7 +145,7 @@ public class PacketContainerTest {
@Test
public void testGetShorts() {
PacketContainer itemData = new PacketContainer(PacketType.Play.Server.TRANSACTION);
PacketContainer itemData = new PacketContainer(PacketType.Play.Server.REL_ENTITY_MOVE);
testPrimitive(itemData.getShorts(), 0, (short)0, (short)1);
}
@@ -164,25 +176,25 @@ public class PacketContainerTest {
@Test
public void testGetStrings() {
PacketContainer explosion = new PacketContainer(PacketType.Play.Client.CHAT);
testPrimitive(explosion.getStrings(), 0, null, "hello");
testPrimitive(explosion.getStrings(), 0, "", "hello");
}
@Test
public void testGetStringArrays() {
PacketContainer packet = new PacketContainer(PacketType.Play.Client.UPDATE_SIGN);
testObjectArray(packet.getStringArrays(), 0, new String[0], new String[] { "hello", "world" });
testObjectArray(packet.getStringArrays(), 0,
new String[] { "", "", "", "" },
new String[] { "hello", "world" }
);
}
@Test
public void testGetIntegerArrays() {
// Contains a byte array we will test
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
PacketContainer packet = new PacketContainer(PacketType.Play.Server.MAP_CHUNK);
StructureModifier<int[]> integers = packet.getIntegerArrays();
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);
@@ -221,7 +233,7 @@ public class PacketContainerTest {
items.add(itemWithData());
items.add(new ItemStack(Material.DIAMOND_AXE));
assertNull(itemAccess.read(0));
assertEquals(itemAccess.read(0).size(), 0);
// Insert and check that it was succesful
itemAccess.write(0, items);
@@ -307,7 +319,7 @@ public class PacketContainerTest {
PacketContainer explosionPacket = new PacketContainer(PacketType.Play.Server.EXPLOSION);
StructureModifier<List<BlockPosition>> positionAccessor = explosionPacket.getBlockPositionCollectionModifier();
assertNull(positionAccessor.read(0));
assertEquals(positionAccessor.read(0).size(), 0);
List<BlockPosition> positions = Lists.newArrayList();
positions.add(new BlockPosition(1, 2, 3));
@@ -373,6 +385,19 @@ public class PacketContainerTest {
assertEquals("Test", copy.getStrings().read(0));
}
@Test
public void testIntList() {
PacketContainer destroy = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
destroy.getIntLists().write(0, new ArrayList<Integer>() {{
add(420);
add(69);
}});
List<Integer> back = destroy.getIntLists().read(0);
assertEquals(back.size(), 2);
assertEquals((int) back.get(0), 420);
assertEquals((int) back.get(1), 69);
}
@Test
public void testAttributeList() {
PacketContainer attribute = new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES);
@@ -380,18 +405,19 @@ public class PacketContainerTest {
// Initialize some test data
List<AttributeModifier> modifiers = Lists.newArrayList(
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10, AttributeModifier.Operation.ADDITION));
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10, AttributeModifier.Operation.a));
// Obtain an AttributeSnapshot instance. This is complicated by the fact that AttributeSnapshots
// are inner classes (which is ultimately pointless because AttributeSnapshots don't access any
// members of the packet itself)
PacketPlayOutUpdateAttributes packet = (PacketPlayOutUpdateAttributes) attribute.getHandle();
AttributeBase base = IRegistry.ATTRIBUTE.get(MinecraftKey.a("generic.max_health"));
AttributeSnapshot snapshot = packet.new AttributeSnapshot(base, 20.0D, modifiers);
AttributeBase base = IRegistry.al.get(MinecraftKey.a("generic.max_health"));
AttributeSnapshot snapshot = new AttributeSnapshot(base, 20.0D, modifiers);
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
PacketContainer cloned = attribute.deepClone();
AttributeSnapshot clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
AttributeSnapshot
clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
// Compare the fields, because apparently the packet is a field in AttributeSnapshot
for (Field field : AttributeSnapshot.class.getDeclaredFields()) {
@@ -402,7 +428,7 @@ public class PacketContainerTest {
}
field.setAccessible(true);
assertEquals(field.get(snapshot), field.get(clonedSnapshot));
testEquality(field.get(snapshot), field.get(clonedSnapshot));
} catch (AssertionError e) {
throw e;
} catch (Throwable ex) {
@@ -494,16 +520,35 @@ public class PacketContainerTest {
assertEquals(container.getSoundEffects().read(0), Sound.ENTITY_CAT_HISS);
}
@Test
// @Test
public void testGenericEnums() {
PacketContainer container = new PacketContainer(PacketType.Play.Server.BOSS);
container.getEnumModifier(Action.class, 1).write(0, Action.UPDATE_PCT);
assertEquals(container.getEnumModifier(Action.class, PacketPlayOutBoss.Action.class).read(0), Action.UPDATE_PCT);
// assertEquals(container.getEnumModifier(Action.class, PacketPlayOutBoss.d.class).read(0), Action.UPDATE_PCT);
}
@Test
public void testInternalStructures() {
PacketContainer container = new PacketContainer(PacketType.Play.Server.SCOREBOARD_TEAM);
Optional<InternalStructure> optStruct = container.getOptionalStructures().read(0);
assertTrue(optStruct.isPresent());
InternalStructure struct = optStruct.get();
struct.getChatComponents().write(0, WrappedChatComponent.fromText("hi there"));
container.getOptionalStructures().write(0, Optional.of(struct));
optStruct = container.getOptionalStructures().read(0);
assertTrue(optStruct.isPresent());
struct = optStruct.get();
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));
@@ -565,6 +610,67 @@ public class PacketContainerTest {
assertNotSame(clone, packet);
}
@Test
public void testGameStateChange() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.GAME_STATE_CHANGE);
assertTrue(packet.getGameStateIDs().read(0) == 0);
packet.getGameStateIDs().write(0, 2);
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 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.getNbtModifier().optionRead(0).isPresent());
}
/**
* Actions from the outbound Boss packet. Used for testing generic enums.
* @author dmulloy2
@@ -591,8 +697,27 @@ 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(getArray(firstMod.read(i)), getArray(secondMod.read(i)));
else
testEquality(firstMod.read(i), secondMod.read(i));
}
}
}
@Test
public void testDeepClone() {
public void testCloning() {
boolean failed = false;
// Try constructing all the packets
for (PacketType type : PacketType.values()) {
if (type.isDeprecated() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("TAGS") || !type.isSupported()
@@ -615,49 +740,61 @@ public class PacketContainerTest {
"String"),
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.get(Float.class)), 1.0F),
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.getChatComponentSerializer(true)),
com.google.common.base.Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
new WrappedWatchableObject(new WrappedDataWatcherObject(0, Registry.get(VillagerData.class)),
new VillagerData(VillagerType.SNOW, VillagerProfession.ARMORER, 69))
new VillagerData(VillagerType.b, VillagerProfession.c, 69))
));
} else if (type == PacketType.Play.Server.CHAT) {
constructed.getChatComponents().write(0, ComponentConverter.fromBaseComponent(TEST_COMPONENT));
//constructed.getModifier().write(1, TEST_COMPONENT);
}
// Clone the packet
PacketContainer cloned = constructed.deepClone();
// Clone the packet both ways
PacketContainer shallowCloned = constructed.shallowClone();
assertPacketsEqual(constructed, shallowCloned);
// Make sure they're equivalent
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
assertEquals(firstMod.size(), secondMod.size());
if (PacketType.Status.Server.SERVER_INFO.equals(type)) {
assertArrayEquals(SerializationUtils.serialize(constructed), SerializationUtils.serialize(cloned));
} else {
// Make sure all the fields are equivalent
for (int i = 0; i < firstMod.size(); i++) {
if (firstMod.getField(i).getType().isArray())
assertArrayEquals(getArray(firstMod.read(i)), getArray(secondMod.read(i)));
else
testEquality(firstMod.read(i), secondMod.read(i));
}
}
PacketContainer deepCloned = constructed.deepClone();
assertPacketsEqual(constructed, deepCloned);
} catch (Exception ex) {
throw new RuntimeException("Failed to serialize packet " + type, ex);
ex.printStackTrace();
failed = true;
}
}
assertFalse("Packet(s) failed to clone", failed);
}
// Convert to objects that support equals()
private void testEquality(Object a, Object b) {
if (a != null && b != null) {
if (MinecraftReflection.isDataWatcher(a)) {
a = watchConvert.getSpecific(a);
b = watchConvert.getSpecific(b);
} else if (MinecraftReflection.isItemStack(a)) {
a = itemConvert.getSpecific(a);
b = itemConvert.getSpecific(b);
if (a == null) {
if (b == null) {
return;
} else {
throw new AssertionError("a was null, but b was not");
}
} else if (b == null) {
throw new AssertionError("a was not null, but b was null");
}
if (a instanceof Optional) {
if (b instanceof Optional) {
testEquality(((Optional<?>) a).orElse(null), ((Optional<?>) b).orElse(null));
return;
} else {
throw new AssertionError("a was optional, but b was not");
}
}
if (a.equals(b) || Objects.equals(a, b) || stringEquality(a, b)) {
return;
}
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 instanceof ItemStack || b instanceof ItemStack) {
@@ -665,16 +802,6 @@ public class PacketContainerTest {
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;
}
@@ -1,21 +1,32 @@
package com.comphenix.protocol.injector;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
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 com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import net.minecraft.server.level.ChunkProviderServer;
import net.minecraft.server.level.EntityTrackerEntry;
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.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.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
import org.junit.BeforeClass;
import org.junit.Test;
import java.lang.reflect.Field;
import static com.comphenix.protocol.utility.TestUtils.setFinalField;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -28,7 +39,7 @@ public class EntityUtilitiesTest {
}
@Test
public void testReflection() {
public void testReflection() throws ReflectiveOperationException {
CraftWorld bukkit = mock(CraftWorld.class);
WorldServer world = mock(WorldServer.class);
when(bukkit.getHandle()).thenReturn(world);
@@ -37,18 +48,24 @@ public class EntityUtilitiesTest {
when(world.getChunkProvider()).thenReturn(provider);
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
Accessors.getFieldAccessor(ChunkProviderServer.class, "playerChunkMap", true).set(provider, chunkMap);
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
setFinalField(provider, chunkMapField, chunkMap);
CraftEntity bukkitEntity = mock(CraftEntity.class);
Entity fakeEntity = mock(Entity.class);
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
EntityTracker tracker = mock(EntityTracker.class);
Accessors.getFieldAccessor(EntityTracker.class, "tracker", true).set(tracker, fakeEntity);
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
setFinalField(tracker, trackerField, fakeEntity);
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
trackerMap.put(1, tracker);
Accessors.getFieldAccessor(PlayerChunkMap.class, "trackedEntities", true).set(chunkMap, trackerMap);
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
setFinalField(chunkMap, trackedEntitiesField, trackerMap);
assertEquals(bukkitEntity, EntityUtilities.getInstance().getEntityFromID(bukkit, 1));
}
@@ -3,12 +3,10 @@ package com.comphenix.protocol.reflect.cloning;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Field;
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;
@@ -16,11 +14,14 @@ import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import net.minecraft.core.NonNullList;
import net.minecraft.world.item.ItemStack;
public class AggregateClonerTest {
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -29,7 +30,8 @@ public class AggregateClonerTest {
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
}
@Test
// @Test
// Usages of NonNullList were removed in 1.17.1
public void testNonNullList() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
@@ -34,6 +34,7 @@ public class MinecraftMethodsTest {
setNull("packetWriteByteBuf");
assertNotNull(MinecraftMethods.getPacketWriteByteBufMethod());
assertNotNull(MinecraftMethods.getPacketReadByteBufMethod());
// TODO it's now a constructor
// assertNotNull(MinecraftMethods.getPacketReadByteBufMethod());
}
}
@@ -6,22 +6,9 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import net.minecraft.server.v1_16_R3.ChatComponentText;
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
import net.minecraft.server.v1_16_R3.DataWatcher;
import net.minecraft.server.v1_16_R3.IBlockData;
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
import net.minecraft.server.v1_16_R3.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
import net.minecraft.server.v1_16_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.server.v1_16_R3.PlayerConnection;
import net.minecraft.server.v1_16_R3.ServerPing;
import net.minecraft.server.v1_16_R3.ServerPing.ServerData;
import net.minecraft.server.v1_16_R3.ServerPing.ServerPingPlayerSample;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.junit.AfterClass;
@@ -33,6 +20,16 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
import com.comphenix.protocol.BukkitInitialization;
import com.mojang.authlib.GameProfile;
import net.minecraft.nbt.NBTCompressedStreamTools;
import net.minecraft.network.chat.ChatComponentText;
import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
import net.minecraft.network.protocol.status.ServerPing;
import net.minecraft.network.syncher.DataWatcher;
import net.minecraft.server.network.PlayerConnection;
import net.minecraft.world.level.ChunkCoordIntPair;
import net.minecraft.world.level.block.state.IBlockData;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
public class MinecraftReflectionTest {
@@ -81,7 +78,7 @@ public class MinecraftReflectionTest {
@Test
public void testAttributeSnapshot() {
assertEquals(AttributeSnapshot.class, MinecraftReflection.getAttributeSnapshotClass());
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class, MinecraftReflection.getAttributeSnapshotClass());
}
@Test
@@ -96,7 +93,7 @@ public class MinecraftReflectionTest {
@Test
public void testChatSerializer() {
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
}
@Test
@@ -121,12 +118,12 @@ public class MinecraftReflectionTest {
@Test
public void testServerPingPlayerSample() {
assertEquals(ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
}
@Test
public void testServerPingServerData() {
assertEquals(ServerData.class, MinecraftReflection.getServerPingServerDataClass());
assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass());
}
@Test
@@ -153,4 +150,10 @@ 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();
}
}
@@ -1,7 +1,9 @@
package com.comphenix.protocol.utility;
import java.lang.reflect.Field;
import java.util.List;
import sun.misc.Unsafe;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
@@ -42,4 +44,13 @@ public class TestUtils {
return first.getType().equals(second.getType());
}
}
public static void setFinalField(Object obj, Field field, Object newValue) throws ReflectiveOperationException {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
long offset = unsafe.objectFieldOffset(field);
unsafe.putObject(obj, offset, newValue);
}
}
@@ -16,17 +16,17 @@ public class ChunkCoordIntPairTest {
@Test
public void test() {
net.minecraft.server.v1_16_R3.ChunkCoordIntPair pair = new net.minecraft.server.v1_16_R3.ChunkCoordIntPair(1, 2);
net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2);
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
assertEquals(1, specific.getChunkX());
assertEquals(2, specific.getChunkZ());
net.minecraft.server.v1_16_R3.ChunkCoordIntPair roundtrip =
(net.minecraft.server.v1_16_R3.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
net.minecraft.world.level.ChunkCoordIntPair roundtrip =
(net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
getGeneric(specific);
assertEquals(1, roundtrip.x);
assertEquals(2, roundtrip.z);
assertEquals(1, roundtrip.b);
assertEquals(2, roundtrip.c);
}
}
@@ -12,7 +12,7 @@ public class CloningTest {
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -3,12 +3,6 @@ package com.comphenix.protocol.wrappers;
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;
@@ -18,53 +12,63 @@ import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
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.EnumHand;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.entity.player.EnumChatVisibility;
import net.minecraft.world.level.EnumGamemode;
public class EnumWrappersTest {
private static class EnumClass {
public EnumProtocol protocol;
public EnumClientCommand command;
public EnumChatVisibility visibility;
public EnumDifficulty difficulty;
public EnumEntityUseAction action;
public EnumHand hand;
// public EnumEntityUseAction action; // moved to PacketPlayInUseEntity but is private
public EnumGamemode mode;
}
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
}
@Test
public void testEnum() {
EnumClass obj = new EnumClass();
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;
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, 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.hand, roundtrip(obj, "hand", EnumWrappers.getHandConverter()) );
// 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))
);
}
private static final Set<String> KNOWN_INVALID = Sets.newHashSet("Particle");
private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
"Particle", "WorldBorderAction", "CombatEventType", "TitleAction"
);
@Test
public void testValidity() {
@@ -34,7 +34,7 @@ public class PlayerInfoDataTest {
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -6,13 +6,6 @@ import static org.junit.Assert.assertTrue;
import java.util.List;
import net.minecraft.server.v1_16_R3.AttributeBase;
import net.minecraft.server.v1_16_R3.AttributeModifier;
import net.minecraft.server.v1_16_R3.IRegistry;
import net.minecraft.server.v1_16_R3.MinecraftKey;
import net.minecraft.server.v1_16_R3.PacketPlayOutUpdateAttributes;
import net.minecraft.server.v1_16_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -23,6 +16,12 @@ import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
import com.google.common.collect.Lists;
import net.minecraft.core.IRegistry;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.world.entity.ai.attributes.AttributeBase;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.resources.MinecraftKey;
public class WrappedAttributeTest {
private WrappedAttributeModifier doubleModifier;
private WrappedAttributeModifier constantModifier;
@@ -75,6 +74,11 @@ public class WrappedAttributeTest {
assertTrue(attribute.hasModifier(doubleModifier.getUUID()));
assertTrue(attribute.hasModifier(constantModifier.getUUID()));
}
@Test
public void testFromTemplate() {
assertEquals(attribute, WrappedAttribute.newBuilder(attribute).build());
}
/**
* Retrieve the equivalent NMS attribute.
@@ -88,9 +92,8 @@ public class WrappedAttributeTest {
modifiers.add((AttributeModifier) wrapper.getHandle());
}
PacketPlayOutUpdateAttributes accessor = new PacketPlayOutUpdateAttributes();
AttributeBase base = IRegistry.ATTRIBUTE.get(MinecraftKey.a(attribute.getAttributeKey()));
return accessor.new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
AttributeBase base = IRegistry.al.get(MinecraftKey.a(attribute.getAttributeKey()));
return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
}
private AttributeModifier getModifierCopy(WrappedAttributeModifier modifier) {
@@ -18,14 +18,14 @@ package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.BukkitInitialization;
import net.minecraft.server.v1_16_R3.IBlockData;
import net.minecraft.world.level.block.state.IBlockData;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.GlassPane;
import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_16_R3.block.impl.CraftStainedGlassPane;
import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_17_R1.block.impl.CraftStainedGlassPane;
import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -23,10 +23,10 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
import net.minecraft.server.v1_16_R3.EntityEgg;
import net.minecraft.world.entity.projectile.EntityEgg;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEgg;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEgg;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -58,7 +58,7 @@ public class WrappedDataWatcherTest {
// Make sure we can set existing objects
wrapper.setObject(0, (byte) 21);
assertTrue(wrapper.getByte(0) == 21);
assertEquals(21, (byte) wrapper.getByte(0));
}
@Test
@@ -87,8 +87,8 @@ public class WrappedDataWatcherTest {
@Test
public void testSerializers() {
Serializer blockPos = Registry.get(net.minecraft.server.v1_16_R3.BlockPosition.class, false);
Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_16_R3.BlockPosition.class, true);
Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false);
Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true);
assertNotSame(blockPos, optionalBlockPos);
// assertNull(Registry.get(ItemStack.class, false));
@@ -28,7 +28,7 @@ public class NbtCompoundTest {
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -30,10 +30,6 @@ import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.server.v1_16_R3.ItemStack;
import net.minecraft.server.v1_16_R3.Items;
import net.minecraft.server.v1_16_R3.NBTTagTypes;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,6 +44,9 @@ import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
//@PrepareForTest(CraftItemFactory.class)
@@ -81,7 +80,7 @@ public class NbtFactoryTest {
@Test
public void testItemTag() {
ItemStack test = new ItemStack(Items.GOLDEN_AXE);
ItemStack test = new ItemStack(Items.L);
org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
NbtCompound compound = NbtFactory.ofCompound("tag");
@@ -14,7 +14,7 @@ public class NbtConfigurationSerializerTest {
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
BukkitInitialization.initializeItemMeta();
}
@Test