Compare commits

...
160 Commits
Author SHA1 Message Date
Dan Mulloy adb3c5392c Release version 4.3.0 2017-06-14 14:30:46 -04:00
Dan Mulloy cd2f56d7c7 Update TinyProtocol to 1.12 2017-06-14 14:30:31 -04:00
Dan Mulloy 7c9bbc3f6c Add 1.12 protocol version 2017-06-09 15:08:04 -04:00
Dan Mulloy 52e396b25d Update to Spigot 1.12 2017-06-08 13:30:57 -04:00
Dan Mulloy aeb2cfb65e Update to 1.12-pre6
No real changes this time
2017-05-30 14:31:13 -04:00
Dan Mulloy 7f5ea6e493 Merge remote-tracking branch 'origin/master' 2017-05-29 22:14:28 -04:00
Dan Mulloy 1be94aad78 Rework packet type deprecation to actually work properly
Also fix compatibility with 1.8.0
2017-05-29 22:14:08 -04:00
dadus33 6bb169ac01 Fix 1.8 compatibility (#339)
Use proper method name ('setLenient' instead of 'setLenienent') in the deserializeLegacy method for 1.8 compatibility.
2017-05-29 12:59:01 -04:00
Dan Mulloy ea7900d64f Better ensure packet types are correct, deprecate legacy IDs 2017-05-24 17:20:27 -04:00
Dan Mulloy 123abdff30 Code cleanup, remove some ancient compatibility 2017-05-24 14:35:22 -04:00
Dan Mulloy 11247f1c01 Return an empty modifier if a class does not exist
Addresses #336
2017-05-23 18:52:28 -04:00
Dan Mulloy f093c9196d Ignore IntelliJ files 2017-05-19 11:17:31 -04:00
Dan Mulloy 81daa62071 Update to 1.12-pre5 2017-05-19 11:11:30 -04:00
Dan Mulloy f99b977888 Restore backwards compatibility, restructure poms 2017-05-18 12:02:47 -04:00
Dan Mulloy b00ae2ff15 Remove Java 8 warning
It's required, so the JVM will warn you for me
2017-05-14 21:46:18 -04:00
Dan Mulloy b4f9c501b3 1.12 hotfix: delay injection for network manager
Fixes #332, fixes #330
2017-05-14 21:37:36 -04:00
Dan Mulloy 1738c6f243 Stop testing with Java 7 2017-05-14 14:37:55 -04:00
Dan Mulloy abea7441a4 Merge branch 'master' of git+ssh://git@github.com/dmulloy2/ProtocolLib 2017-05-14 14:30:21 -04:00
Dan Mulloy 3887ba27d2 Update to the 1.12 pre-release
- Now requires Java 8
- Added new packets
- Added ChatType enum (replaces magic value)
- Missing protocol version
2017-05-14 14:28:56 -04:00
games647 76a3af84a1 Strictly match the sendPacket method
Related to #322
2017-04-27 20:49:37 -04:00
Dan Mulloy be5d42ee19 Minecraft 1.12 will use Java 8 2017-04-27 20:48:02 -04:00
Dan Mulloy 790711c16e Update version to 4.2.2-SNAPSHOT 2017-04-27 20:46:04 -04:00
Dan Mulloy 8c3127dee1 Release version 4.2.1 2017-04-09 11:56:53 -04:00
Dan Mulloy 5ec87c9d76 Fix issues with logging custom payload packets 2017-03-20 21:42:46 -04:00
Dan Mulloy 2205ce639e Merge pull request #305 from aadnk/master
Branch hiccup
2017-03-18 19:33:14 -04:00
Dan Mulloy 2844d75607 Merge pull request #127 from dmulloy2/master
Branch hiccup
2017-03-18 19:32:12 -04:00
Dan Mulloy a6810ea874 Merge branch 'master' of git+ssh://git@github.com/dmulloy2/ProtocolLib 2017-03-18 19:29:43 -04:00
Dan Mulloy aaf1af8e41 Don't worry if we can't determine the Java version 2017-03-18 19:29:16 -04:00
Dan Mulloy b8dd43aeed Merge pull request #126 from joeypoulissen/master
Added missing fallingdust particle as seen at http://wiki.vg/Protocol#Particle
2017-03-12 18:42:29 -04:00
Joey e959efc5af Added fallingdust particle as seen at http://wiki.vg/Protocol#Particle 2017-03-11 13:59:25 +01:00
Dan Mulloy 73ce01bbde Make packet logging more robust 2017-03-09 10:53:06 -05:00
Dan Mulloy b30628f6db Make hex dump more readable, match more packet names 2017-03-08 09:08:29 -05:00
Dan Mulloy 9289825d87 Add packet logging for debugging 2017-03-01 17:02:46 -05:00
Dan Mulloy 57cfbc4f81 Merge branch 'master' of git+ssh://git@github.com/dmulloy2/ProtocolLib 2017-02-04 12:12:54 -05:00
Dan Mulloy 3ab2026d62 People don't care if updater sites are down 2017-02-04 12:12:31 -05:00
Dan Mulloy e439c778a6 Use the correct JsonReader constructor in 1.8
Fixes aadnk#121
2017-01-01 16:13:47 -05:00
Dan Mulloy 98413c917e Update packet IDs 2016-12-22 12:24:18 -05:00
Dan Mulloy 540a5e53c4 Make Sound handling more robust
Fixes aadnk#119
2016-12-22 11:42:52 -05:00
Dan Mulloy 27047f83a5 Fix erroneous startup message 2016-12-22 11:33:55 -05:00
Dan Mulloy 222b535c15 Update version to 4.2.1-SNAPSHOT 2016-12-22 11:33:10 -05:00
Dan Mulloy 3f31af6b70 I'll look into signing releases later 2016-12-21 14:20:56 -05:00
Dan Mulloy b6a054b766 Release version 4.2.0 2016-12-21 14:16:57 -05:00
Dan Mulloy 3b7b692e80 Update to 1.11.2 2016-12-21 14:02:32 -05:00
Dan Mulloy c6788addeb Mark 1.11.1 as officially supported 2016-12-20 23:37:35 -05:00
Dan Mulloy 5b38bc7f38 Update to 1.11.1 2016-12-20 16:14:13 -05:00
Dan Mulloy 33bb12713d Restore ItemStack to CraftItemStack conversion 2016-12-16 12:36:35 -05:00
Dan Mulloy d175a7655e Refactor package caching, account for some edge cases 2016-11-29 19:39:11 -05:00
Dan Mulloy 4afb38aae1 Merge pull request #115 from Mast3rPlan/master
Fix performance issue
2016-11-27 12:41:02 -05:00
Emiel Tasseel 36b5670b3d Fix performance issue where classes that don't exist in the current environment endlessly get looked up over and over again 2016-11-26 12:50:27 +01:00
Dan Mulloy 7b61796506 Add mechanism to clone NonNullLists 2016-11-22 17:36:49 -05:00
Dan Mulloy 684b687e42 Rework ItemStack handling for 1.11
Note to developers: You should never supply a null ItemStack to any
method. ProtocolLib will never return a null ItemStack. Update your
plugins accordingly.
2016-11-20 16:29:23 -05:00
Dan Mulloy 7a9b9afe2e Add modifier for item lists 2016-11-19 19:18:35 -05:00
Dan Mulloy 7d382279ad Update to Minecraft 1.11 2016-11-16 21:56:46 -05:00
Dan Mulloy b4f5f18283 Strongly recommend Java 8
If you must use Java 7, set 'ignoreJava: true' in the config.
2016-10-14 19:28:17 -04:00
Dan Mulloy 17e150393a Avoid throwing errors with invalid entities 2016-10-14 19:20:47 -04:00
Dan Mulloy b5ecfb9c5f Update version to 4.2.0-SNAPSHOT 2016-10-14 19:20:16 -04:00
Dan Mulloy 31a0c9b10c Update version in plugin.yml 2016-09-18 15:27:49 -04:00
Dan Mulloy e4d95e09cf Update version to 4.1.0 for release 2016-09-18 15:27:01 -04:00
Dan Mulloy d173be0db5 Actually use UpdateSign when it exists 2016-09-18 14:42:40 -04:00
Dan Mulloy 051989a396 Merge pull request #265 from faradize/master
Added the ability of reading/writing lists of NBT classes!
2016-09-11 17:00:25 -04:00
Dan Mulloy 795c77e943 Fix minor example issue
Closes aadnk#113
2016-09-11 16:56:05 -04:00
Dan Mulloy 1de6bbc9dc Make sure we use the update sign packet when it exists
Should fix #263
2016-09-11 16:52:45 -04:00
verbuchselt 474c74b1f9 Added the ability of reading/writing lists of NBT classes!
Works perfectly with MapChunk-Packet's TileEntity-Data!
2016-09-07 11:37:30 +02:00
Dan Mulloy caaa57c915 Add basic TileEntityTest 2016-08-27 13:08:22 -04:00
Dan Mulloy 588f736348 Fix missing TileEntity write methods
Fixes #249
2016-08-27 13:07:49 -04:00
Dan Mulloy 828302150a Deal with plugins that create proxy player objects
As I was writing this I realized it sounded like Bungee support, but it
isn't
2016-08-13 13:19:13 -04:00
Dan Mulloy 144723af18 Ensure we're always using leniency with components
Fixes #252
2016-08-06 14:40:49 -04:00
Dan Mulloy 087913ab3a Standardize equals and hashCode for wrappers 2016-08-06 13:19:14 -04:00
Dan Mulloy 64942cbb5e Make much of ProtocolLib locale independent
Fixes #242
2016-07-25 14:09:23 -04:00
Dan Mulloy 97430a8e42 Add renamed OPEN_SIGN_ENTITY packet for backwards compat
Fixes #243
2016-07-25 13:47:56 -04:00
Dan Mulloy 1bdd200794 Try to fix a weird null case 2016-07-16 16:03:01 -04:00
Dan Mulloy 679035c3bf Fix an error with wire packets
Addresses #224
2016-07-16 15:46:23 -04:00
Dan Mulloy bd4352f041 Fix cloning data watchers
Addresses #224
2016-07-12 16:15:46 -04:00
Dan Mulloy 05ffeb8e7f Restore compatibility with 1.8
1.8.8 is still one of the most popular server versions. As a result,
many servers were not receiving important fixes and new APIs.

I was able to accomplish this with minimal bloat, making it worth it.

Upon release, 4.1.0 will become the recommended version for 1.8 thru the
current Spigot build.
2016-07-12 13:37:55 -04:00
Dan Mulloy 6c982a83f0 Cache null classes
This should prevent multiple unnecessary calls to the expensive
loadClass method

Fixes #236
2016-07-09 15:32:35 -04:00
Dan Mulloy 9860fbaec6 Fix API versioning 2016-07-07 12:19:10 -04:00
Dan Mulloy 26c29d9c85 Add conversion methods to WirePacket 2016-07-06 15:47:43 -04:00
Dan Mulloy 242b25eb1e Wrap all serializable objects in data watchers 2016-07-06 15:47:24 -04:00
Dan Mulloy c13b8d4fc6 Add modifiers for UUIDs and Directions 2016-07-06 15:46:42 -04:00
Dan Mulloy 12e9c08a1a Update version to 4.1.0-SNAPSHOT 2016-07-06 15:44:41 -04:00
Dan Mulloy 98a0528806 Update version to 4.0.2 for release 2016-07-06 13:42:57 -04:00
Dan Mulloy 015a6067fd Replace some debug info with the actual cause 2016-07-05 22:54:25 -04:00
Dan Mulloy e34105e754 Rework the component array modifier to work in 1.9.4 and up
Fixes #215
2016-07-03 13:12:24 -04:00
Dan Mulloy a995866d5b Add block data to the cloning mechanism 2016-06-30 12:34:13 -04:00
Dan Mulloy a88347dfe6 Add some more specific error messages for entity tracking
Addresses #229
2016-06-30 12:22:48 -04:00
Dan Mulloy 4f404a41c6 Update to 1.10.2
No changes, yay!
2016-06-26 23:06:00 -04:00
Dan Mulloy 88444dcf74 Fix another entity issue with Paper
Fixes #220
2016-06-20 20:50:26 -04:00
Dan Mulloy 4f5ab9eb8c Wrap and unwrap values in Optionals 2016-06-20 20:41:40 -04:00
Dan Mulloy f51427b63c Update to 1.10 2016-06-08 22:28:53 -04:00
Dan Mulloy cdcb6a6007 Update version to 4.0.2-SNAPSHOT 2016-06-08 11:12:46 -04:00
Dan Mulloy ac7e17d0a6 Update version to 4.0.1 for release 2016-05-22 17:31:42 -04:00
Dan Mulloy 402390866a Fix a few issues with debug logging
Also add a warning if the updater section is missing
2016-05-22 17:26:36 -04:00
Dan Mulloy cc362a1b7f Ensure the modification count is checked correctly
Fixes #202
2016-05-21 17:44:25 -04:00
Dan Mulloy 1ca7973b77 Correct line endings
Also ensure every file ends with a new line for consistency
2016-05-21 17:37:13 -04:00
Dan Mulloy 9ecbea68ca Disable auto download by default 2016-05-21 16:04:57 -04:00
Dan Mulloy e5bc602af3 Fix a few issues with the registry 2016-05-18 21:03:14 -04:00
Dan Mulloy a9aa406d29 Missing return statement
Also, why is git showing whole-class diffs? Must be the dang line
endings again
2016-05-18 20:48:59 -04:00
Dan Mulloy c1ae6f14fc Add some debug info for #202
Also /really/ make sure it's only called once
2016-05-18 20:47:08 -04:00
Dan Mulloy 411b7a2446 Catch the right exception 2016-05-17 17:04:19 -04:00
Dan Mulloy 869b457810 Fix a false positive with the updater 2016-05-16 17:43:58 -04:00
Dan Mulloy 4330bae47f Add some debug info for #208 2016-05-16 16:27:05 -04:00
Dan Mulloy 1c36c41050 Update version to 4.0.1-SNAPSHOT 2016-05-16 16:26:40 -04:00
Dan Mulloy bea4356aca Update version to 4.0.0 for release 2016-05-15 17:43:20 -04:00
0x277F 32f51c612a Add contributing guidelines and issue template 2016-05-14 17:12:51 -04:00
Dan Mulloy 355d00d951 Complete 1.9.4 update
Fixes #204
2016-05-13 17:12:21 -04:00
Dan Mulloy bf56f3919f Merge pull request #205 from 0x277F/mc-1.9.4
Update to 1.9.4
2016-05-13 16:52:50 -04:00
0x277F d876580ddf Update to 1.9.4 2016-05-12 16:30:49 -06:00
Dan Mulloy 90f36198d2 Add plugin caller to setPacket warning
Fixes #201
2016-05-02 22:04:10 -04:00
Dan Mulloy e542f3c9d3 Add back a missing data watcher constructor
Also bolstered some of the unit tests
Fixes #191
2016-04-16 21:24:58 -04:00
Dan Mulloy 87c56d0248 We support 1.9.2 2016-04-10 21:28:52 -04:00
Dan Mulloy 8c928cb237 Allow the usage of user-created enums
Basically this will allow developers to create their own enums instead
of having to wait on me to make them. The only caveat is that enum
constants will have to match up exactly with their NMS counterparts
2016-04-06 22:55:14 -04:00
Dan Mulloy 6030992af4 Add modifiers for Sounds and Hands 2016-04-04 21:37:45 -04:00
Dan Mulloy 688da1a1bb Add protocol version for 1.9.2 2016-04-03 00:49:04 -04:00
Dan Mulloy ceecd51982 Update to 1.9.2 2016-04-02 23:01:19 -04:00
Dan Mulloy c77a700442 Add wrapper for ItemSlot
Closes #183
2016-04-02 14:54:31 -04:00
Dan Mulloy 10ded26d60 Documentation improvements 2016-04-02 14:47:54 -04:00
Dan Mulloy 74adaba8ac Update packet types and IDs for 1.9
A few packet names have changed, they're now deprecated
2016-03-20 17:46:23 -04:00
Dan Mulloy 19c57b0e5e Restore disabled tests, fix block data 2016-03-20 13:35:59 -04:00
Dan Mulloy f561057311 Fix an error with TinyProtocol reflection
Fixes aadnk#103
2016-03-19 22:36:25 -04:00
Dan Mulloy 0e6a7a39a0 Add modifiers for SoundCategory and MobEffectList
Fixes #156
2016-03-19 22:30:01 -04:00
Dan Mulloy 13b905e762 Fix a few issues with loading 2016-03-19 16:41:02 -04:00
Dan Mulloy b4c0cc5a27 Split API off into a separate module 2016-03-19 16:01:38 -04:00
Dan Mulloy a042c8bb3c Update the dig type enum for 1.9 2016-03-12 15:54:57 -05:00
Dan Mulloy 286a642739 Fix false update notifications with beta releases
Fixes #173
2016-03-12 15:51:12 -05:00
Dan Mulloy 513a83c4b0 Fix block positions in watchers and issues with components
Fixes #170
2016-03-12 15:35:34 -05:00
Dan Mulloy 9b2c8826b1 Fix a typo
That wouldn't be a terrible name for the class though
2016-03-11 14:15:14 -05:00
Dan Mulloy 413a3c27a4 Fix an issue with deep cloning data watchers
Fixes #172
2016-03-11 14:06:43 -05:00
Dan Mulloy c9328d98d7 Return to normal versioning 2016-03-09 22:02:35 -05:00
Dan Mulloy f6c0751ce3 Update version to 3.7.0-BETA for beta release 2016-03-07 19:08:16 -05:00
Dan Mulloy 16c7ebef73 A few minor tweaks 2016-03-07 19:05:58 -05:00
Dan Mulloy ec38ac7292 Revert changes to EntityUtilities
Citizens fixed the problem on their end
2016-03-06 18:32:39 -05:00
Dan Mulloy b8497a91a6 Disable updater tests
They're too prone to failure due to HTTP errors
2016-03-06 14:11:56 -05:00
Dan Mulloy 5115bcaf98 Add an optional cloner, fix sound cloning, clean up the data watcher 2016-03-06 14:02:45 -05:00
Dan Mulloy 7077037bb7 The serializer can be null
But this will cause issues when trying to register objects
2016-03-05 23:53:55 -05:00
Dan Mulloy 11ba322b5f Fix an issue with cloning metadata packets
Also improved some documentation and tests
2016-03-05 23:28:48 -05:00
Dan Mulloy a39a37ec51 Allow new entries to be created in the data watcher
Addresses #160
2016-03-05 20:36:54 -05:00
Dan Mulloy ec8fa0d1fe Add wrapper for MinecraftKey, more work on data watchers 2016-03-04 21:24:12 -05:00
Dan Mulloy 5efc4ffee3 Update player actions for 1.9
Fixes #161
2016-03-04 17:32:43 -05:00
Dan Mulloy c2d028df4f Fix a few issues with data watchers 2016-03-04 17:16:50 -05:00
Dan Mulloy 9b838df17d Fix a few errors with data watchers
This is why we have unit tests lol
2016-03-03 21:27:05 -05:00
Dan Mulloy a20ff4645d Add wrappers for data watcher objects, serializers, and the registry
Thanks @NavidK0 for help with the design
2016-03-03 21:18:51 -05:00
Dan Mulloy 850e3431da Restore a few more methods, add some documentation 2016-03-02 20:47:00 -05:00
Dan Mulloy 072a60516e Update particles for 1.9 2016-03-02 18:48:47 -05:00
Dan Mulloy 9b3feb995a Restore some methods to the data watcher wrappers 2016-03-02 18:27:12 -05:00
Dan Mulloy d359f7455f [Breaking] Update data watchers for 1.9
Basically I had to rewrite the classes since Mojang decided to muck the
whole thing up. If there are any methods necessary, I'll try to readd
them.
2016-03-02 18:08:01 -05:00
Dan Mulloy 4987cd188a Comment out data watcher exception
There's a chance that the fallbacks will actually work properly, it's
worth a try until I can find a permanent solution.
2016-03-01 18:34:35 -05:00
Dan Mulloy 019e45572d 1.9 update: Fix entity modifiers
Fixes #153
2016-03-01 16:07:59 -05:00
Dan Mulloy d87e877a27 Update internal versioning for 1.9
It looks like most things are stable at this point, just have to figure
out data watchers
2016-02-29 19:15:54 -05:00
Dan Mulloy 05c7da17b9 1.9 update: It compiles!
Note: This is an untested build, use with caution!
2016-02-29 18:55:29 -05:00
Dan Mulloy 8c21f75e6d Update readme links 2016-02-27 22:48:54 -05:00
Dan Mulloy 615a4e6e37 Use the correct Gson class in 1.7.10 2016-02-27 22:48:11 -05:00
Dan Mulloy 11ca1bf51e Merge pull request #150 from iNevet/master
Add the actual creation of the packet
2016-02-25 13:51:15 -05:00
iNevet 7fabfad65d Better code example 2016-02-23 15:28:14 +08:00
Dan Mulloy ce4779f49d Revert "Fix spelling mistake in PacketAdapter"
This reverts commit cc4d035b63.
2016-02-19 12:56:57 -05:00
Dan Mulloy a88b919e60 Make update checking more robust 2016-02-17 21:48:24 -05:00
Dan Mulloy cc4d035b63 Fix spelling mistake in PacketAdapter
Fixes #113

Thanks @Sheigutn and @NavidK0
2016-02-17 21:10:25 -05:00
Dan Mulloy 12b78eb1d7 Switch to Java 7
This shouldn't be an issue as Java 6 has been EOL'd for years now. Heck,
even Java 7 has been EOL'd

Also updated maven plugin versions
2016-02-17 21:03:26 -05:00
Dan Mulloy 8a5267ab76 Update version to 3.7-SNAPSHOT 2016-02-17 20:52:11 -05:00
Dan Mulloy a189947617 Fix issue with entity tracking on PaperSpigot 2016-02-16 15:43:23 -05:00
Dan Mulloy f01b3999ff Update version to 3.6.6-SNAPSHOT 2016-02-16 15:41:55 -05:00
359 changed files with 8444 additions and 11509 deletions

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
Contributing to ProtocolLib
===========================
This page will detail specific things that must be done if you intend to contribute to this project.
## Updating ProtocolLib to a New Protocol Version
#### Before we get started:
1. **When do we need to update the protocol version?**
_A Minecraft protocol version is a number for each specification of the Minecraft protocol.
This means it is incremented when there is a change to the [Protocol Specification](http://wiki.vg/Protocol),
but not necessarily for each Minecraft version update. If the latest Minecraft version contains a protocol change,
that means ProtocolLib needs to be updated._
2. **When do we need to update other parts of ProtocolLib?**
_When the package version guard changes. The package version guard is the version string inserted
into the package identifier for CraftBukkit and net.minecraft.server (e.g. v1_9_R2). It is incremented
by Spigot if there is a major breaking change in the internal server code. This is to encourage plugins
that interact directly with CraftBukkit/nms code to update more specifically. However, since most of
ProtocolLib uses reflection, and the structure of packet classes is generally static, one will have
to go through the code and change imports from nms/CraftBukkit._
#### 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)
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
(or had their ID changed), make sure to update this list. If a packet was removed
in favor of usage of another packet, instead of removing it, move it to the bottom of the list
in its section, add a deprecation warning to it, and redirect it to the packet that replaced it.
4. `mvn` in the root directory to build the project.
5. If tests fail in the maven build, go through the tests to make sure you removed references to any removed packets
and changed the NMS version guards.
6. Increment the package version in `com.comphenix.protocol.utility.Constants`.
7. `com.comphenix.protocol.ProtocolLibrary` contains several constants that must be updated, including the Minecraft version
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!
+10
View File
@@ -0,0 +1,10 @@
_Follow this template except for feature requests. Use pastebin when providing /protocol dump and any relevant errors._
Make sure you've done the following:
- [ ] You're using the latest build for your server version
- [ ] This isn't an issue caused by another plugin
- [ ] You've checked for duplicate issues
Debug paste link:
Description and relevant errors:
+4
View File
@@ -7,6 +7,10 @@
.classpath
.settings/
bin/
.idea/
*.iml
.ipr
.iws
*.pydevproject
.metadata
+2 -3
View File
@@ -1,9 +1,8 @@
language: java
jdk:
- oraclejdk8
- oraclejdk7
script: mvn clean test -U
before_install: cd ProtocolLib
script: mvn clean test
#before_install: cd ProtocolLib
install: true
notifications:
email:
-167
View File
@@ -1,167 +0,0 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
target/
.gitignore
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
/target
/target
@@ -1,58 +0,0 @@
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol;
import org.bukkit.Bukkit;
/**
* Ignore this class.
*
* @author Kristian
*/
public class Application {
private static Thread mainThread;
private static boolean primaryMethod = true;
public static void main(String[] args) {
// For now, though we might consider making a proper application
System.out.println("This is a Bukkit library. Place it in the plugin-folder and restart the server!");
}
/**
* Determine if we are running on the main thread.
* @return TRUE if we are, FALSE otherwise.
*/
public static boolean isPrimaryThread() {
if (primaryMethod) {
try {
return Bukkit.isPrimaryThread();
} catch (LinkageError e) {
primaryMethod = false;
}
}
// Fallback method
return Thread.currentThread().equals(mainThread);
}
/**
* Register the calling thread as the primary thread.
*/
static void registerPrimaryThread() {
mainThread = Thread.currentThread();
}
}
@@ -1,67 +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.compat.guava;
import java.io.DataInputStream;
import java.util.Set;
import java.util.logging.Level;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.collect.Range;
/**
* @author dmulloy2
*/
public class Guava {
private static GuavaCompat compat;
static {
try {
Range.closed(1, 2);
compat = new Guava17();
} catch (Throwable ex) {
try {
Class<?> clazz = Class.forName("com.comphenix.protocol.compat.guava.Guava10");
compat = (GuavaCompat) clazz.newInstance();
} catch (Throwable ex1) {
ProtocolLibrary.log(Level.SEVERE, "Failed to create Guava 10 compat:", ex1);
}
}
}
private static GuavaCompat getCompat() {
return compat;
}
public static <C extends Comparable<C>> Range<C> closedRange(C lower, C upper) {
return getCompat().closedRange(lower, upper);
}
public static <C extends Comparable<C>> Range<C> singleton(C singleton) {
return getCompat().singletonRange(singleton);
}
public static Set<Integer> toSet(Range<Integer> range) {
return getCompat().toSet(range);
}
public static DataInputStream addHeader(DataInputStream input, PacketType type) {
return getCompat().addHeader(input, type);
}
}
@@ -1,76 +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.compat.guava;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;
import com.google.common.io.ByteSource;
/**
* @author dmulloy2
*/
public class Guava17 implements GuavaCompat {
@Override
public <C extends Comparable<C>> Range<C> closedRange(C lower, C upper) {
return Range.closed(lower, upper);
}
@Override
public <C extends Comparable<C>> Range<C> singletonRange(C singleton) {
return Range.singleton(singleton);
}
@Override
public Set<Integer> toSet(Range<Integer> range) {
return ContiguousSet.create(range, DiscreteDomain.integers());
}
@Override
public DataInputStream addHeader(final DataInputStream input, final PacketType type) {
ByteSource header = new ByteSource() {
@Override
public InputStream openStream() throws IOException {
byte[] data = new byte[] { (byte) type.getLegacyId() };
return new ByteArrayInputStream(data);
}
};
ByteSource data = new ByteSource() {
@Override
public InputStream openStream() throws IOException {
return input;
}
};
// Combine them into a single stream
try {
return new DataInputStream(ByteSource.concat(header, data).openStream());
} catch (IOException e) {
throw new RuntimeException("Cannot add header.", e);
}
}
}
@@ -1,38 +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.compat.guava;
import java.io.DataInputStream;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.google.common.collect.Range;
/**
* @author dmulloy2
*/
public interface GuavaCompat {
<C extends Comparable<C>> Range<C> closedRange(C lower, C upper);
<C extends Comparable<C>> Range<C> singletonRange(C singleton);
Set<Integer> toSet(Range<Integer> range);
DataInputStream addHeader(DataInputStream input, PacketType type);
}
@@ -1,28 +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.compat.netty;
import com.comphenix.protocol.injector.netty.Injector;
/**
* @author dmulloy2
*/
public interface ChannelInjector extends Injector {
WrappedChannel getChannel();
}
@@ -1,103 +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.compat.netty;
import java.util.List;
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.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
/**
* @author dmulloy2
*/
public class LegacyProtocolRegistry extends ProtocolRegistry {
public LegacyProtocolRegistry() {
super();
}
@Override
protected void initialize() {
final Object[] protocols = enumProtocol.getEnumConstants();
List<Map<Integer, Class<?>>> serverMaps = Lists.newArrayList();
List<Map<Integer, Class<?>>> clientMaps = Lists.newArrayList();
StructureModifier<Object> modifier = null;
// Result
Register result = new Register();
for (Object protocol : protocols) {
if (modifier == null)
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
StructureModifier<Map<Integer, Class<?>>> maps = modifier.withTarget(protocol).withType(Map.class);
serverMaps.add(maps.read(0));
clientMaps.add(maps.read(1));
}
// Maps we have to occationally check have changed
for (Map<Integer, Class<?>> map : Iterables.concat(serverMaps, clientMaps)) {
result.containers.add(new MapContainer(map));
}
// Heuristic - there are more server packets than client packets
if (sum(clientMaps) > sum(serverMaps)) {
// Swap if this is violated
List<Map<Integer, Class<?>>> temp = serverMaps;
serverMaps = clientMaps;
clientMaps = temp;
}
for (int i = 0; i < protocols.length; i++) {
Enum<?> enumProtocol = (Enum<?>) protocols[i];
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
// Associate known types
associatePackets(result, serverMaps.get(i), equivalent, Sender.SERVER);
associatePackets(result, clientMaps.get(i), equivalent, Sender.CLIENT);
}
// Exchange (thread safe, as we have only one writer)
this.register = result;
}
@Override
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
PacketType type = PacketType.fromID(protocol, sender, entry.getKey(), 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 (IllegalArgumentException ex) {
// Sometimes this happens with fake packets, just ignore it
}
}
}
}
@@ -1,99 +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.compat.netty;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.logging.Level;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.compat.netty.independent.IndependentNetty;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
/**
* @author dmulloy2
*/
public class Netty {
private static NettyCompat compat;
static {
try {
Class.forName("io.netty.buffer.ByteBuf");
compat = new IndependentNetty();
} catch (ClassNotFoundException ex) {
try {
Class<?> clazz = Class.forName("com.comphenix.protocol.compat.netty.shaded.ShadedNetty");
compat = (NettyCompat) clazz.newInstance();
} catch (Exception ex1) {
ProtocolLibrary.log(Level.SEVERE, "Failed to create legacy netty compat:", ex1);
}
}
}
private static NettyCompat getCompat() {
return compat;
}
public static boolean isIndependent() {
return compat instanceof IndependentNetty;
}
public static WrappedByteBuf createPacketBuffer() {
return getCompat().createPacketBuffer();
}
public static Class<?> getGenericFutureListenerArray() {
return getCompat().getGenericFutureListenerArray();
}
public static Class<?> getChannelHandlerContext() {
return getCompat().getChannelHandlerContext();
}
public static String toEncodedText(CompressedImage image) {
return getCompat().toEncodedText(image);
}
public static WrappedByteBuf decode(byte[] encoded) {
return getCompat().decode(encoded);
}
public static ProtocolInjector getProtocolInjector(Plugin library, PacketFilterManager packetFilterManager, ErrorReporter reporter) {
return getCompat().getProtocolInjector(library, packetFilterManager, reporter);
}
public static WrappedByteBuf packetReader(DataInputStream input) {
return getCompat().packetReader(input);
}
public static WrappedByteBuf packetWriter(DataOutputStream output) {
return getCompat().packetWriter(output);
}
public static WrappedByteBuf copiedBuffer(byte[] array) {
return getCompat().copiedBuffer(array);
}
public static WrappedByteBuf buffer() {
return getCompat().buffer();
}
}
@@ -1,55 +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.compat.netty;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
/**
* @author dmulloy2
*/
// TODO: Sort out packet readers/writers
public interface NettyCompat {
WrappedByteBuf createPacketBuffer();
WrappedByteBuf copiedBuffer(byte[] array);
WrappedByteBuf buffer();
Class<?> getGenericFutureListenerArray();
Class<?> getChannelHandlerContext();
String toEncodedText(CompressedImage image);
WrappedByteBuf decode(byte[] encoded);
ProtocolInjector getProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter);
WrappedByteBuf packetReader(DataInputStream input);
WrappedByteBuf packetWriter(DataOutputStream output);
}
@@ -1,38 +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.compat.netty;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
/**
* @author dmulloy2
*/
public interface ProtocolInjector extends ChannelListener {
PlayerInjectionHandler getPlayerInjector();
PacketInjector getPacketInjector();
void setDebug(boolean debug);
void inject();
void close();
}
@@ -1,46 +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.compat.netty;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author dmulloy2
*/
public interface WrappedByteBuf {
void writeBytes(ObjectInputStream input, int id) throws IOException;
Object getHandle();
int readableBytes();
void readBytes(ObjectOutputStream output, int readableBytes) throws IOException;
void readBytes(byte[] data);
void writeByte(byte b);
void writeByte(int i);
void writeBytes(byte[] bytes);
byte[] array();
}
@@ -1,26 +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.compat.netty;
/**
* @author dmulloy2
*/
public interface WrappedChannel {
void writeAndFlush(Object packet);
}
@@ -1,105 +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.compat.netty.independent;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.base64.Base64;
import io.netty.util.concurrent.GenericFutureListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.compat.netty.NettyCompat;
import com.comphenix.protocol.compat.netty.ProtocolInjector;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
import com.google.common.base.Charsets;
/**
* @author dmulloy2
*/
public class IndependentNetty implements NettyCompat {
@Override
public WrappedByteBuf createPacketBuffer() {
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
Class<?> packetSerializer = MinecraftReflection.getPacketDataSerializerClass();
try {
return new NettyByteBuf((ByteBuf) packetSerializer.getConstructor(ByteBuf.class).newInstance(buffer));
} catch (Exception e) {
throw new RuntimeException("Cannot construct packet serializer.", e);
}
}
@Override
public Class<?> getGenericFutureListenerArray() {
return GenericFutureListener[].class;
}
@Override
public Class<?> getChannelHandlerContext() {
return ChannelHandlerContext.class;
}
@Override
public String toEncodedText(CompressedImage image) {
final ByteBuf buffer = Unpooled.wrappedBuffer(image.getDataCopy());
String computed = "data:" + image.getMime() + ";base64," +
Base64.encode(buffer).toString(Charsets.UTF_8);
return computed;
}
@Override
public WrappedByteBuf decode(byte[] encoded) {
return new NettyByteBuf(Base64.decode(Unpooled.wrappedBuffer(encoded)));
}
@Override
public ProtocolInjector getProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter) {
return new NettyProtocolInjector(plugin, invoker, reporter);
}
@Override
public WrappedByteBuf packetReader(DataInputStream input) {
return new NettyByteBuf(NettyByteBufAdapter.packetReader(input));
}
@Override
public WrappedByteBuf packetWriter(DataOutputStream output) {
return new NettyByteBuf(NettyByteBufAdapter.packetWriter(output));
}
@Override
public WrappedByteBuf copiedBuffer(byte[] array) {
return new NettyByteBuf(Unpooled.copiedBuffer(array));
}
@Override
public WrappedByteBuf buffer() {
return new NettyByteBuf(Unpooled.buffer());
}
}
@@ -1,83 +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.compat.netty.independent;
import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.ref.WeakReference;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
/**
* @author dmulloy2
*/
public class NettyByteBuf implements WrappedByteBuf {
private WeakReference<ByteBuf> handle;
public NettyByteBuf(ByteBuf handle) {
this.handle = new WeakReference<ByteBuf>(handle);
}
@Override
public void writeBytes(ObjectInputStream input, int id) throws IOException {
handle.get().writeBytes(input, id);
}
@Override
public Object getHandle() {
return handle.get();
}
@Override
public int readableBytes() {
return handle.get().readableBytes();
}
@Override
public void readBytes(ObjectOutputStream output, int readableBytes) throws IOException {
handle.get().readBytes(output, readableBytes);
}
@Override
public void readBytes(byte[] data) {
handle.get().readBytes(data);
}
@Override
public void writeByte(byte b) {
handle.get().writeByte(b);
}
@Override
public void writeByte(int i) {
handle.get().writeByte(i);
}
@Override
public void writeBytes(byte[] bytes) {
handle.get().writeBytes(bytes);
}
@Override
public byte[] array() {
return handle.get().array();
}
}
@@ -1,55 +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 com.comphenix.protocol.compat.netty.WrappedByteBuf;
/**
* @author dmulloy2
*/
public class WirePacket {
private final int id;
private final byte[] bytes;
public WirePacket(int id, byte[] bytes) {
this.id = id;
this.bytes = bytes;
}
public int getId() {
return id;
}
public byte[] getBytes() {
return bytes;
}
public void writeId(WrappedByteBuf output) {
int i = id;
while ((i & -128) != 0) {
output.writeByte(i & 127 | 128);
i >>>= 7;
}
output.writeByte(i);
}
public void writeBytes(WrappedByteBuf output) {
output.writeBytes(bytes);
}
}
@@ -1,92 +0,0 @@
package com.comphenix.protocol.utility;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
/**
* Allows us to stay backwards compatible with older versions of Bukkit.
*
* @author Kristian
*/
public class WrappedScheduler {
/**
* Represents a backwards compatible Bukkit task.
*/
public static interface TaskWrapper {
/**
* Cancel the current task.
*/
public void cancel();
}
/**
* Schedule a given task for a single asynchronous execution.
* @param plugin - the owner plugin.
* @param runnable - the task to run.
* @param firstDelay - the amount of time to wait until executing the task.
* @return A cancel token.
*/
public static TaskWrapper runAsynchronouslyOnce(final Plugin plugin, Runnable runnable, long firstDelay) {
return runAsynchronouslyRepeat(plugin, plugin.getServer().getScheduler(), runnable, firstDelay, -1L);
}
/**
* Schedule a given task for multiple asynchronous executions.
* @param plugin - the owner plugin.
* @param runnable - the task to run.
* @param firstDelay - the amount of time to wait until executing the task for the first time.
* @param repeatDelay - the amount of time inbetween each execution. If less than zero, the task is only executed once.
* @return A cancel token.
*/
public static TaskWrapper runAsynchronouslyRepeat(final Plugin plugin, Runnable runnable, long firstDelay, long repeatDelay) {
return runAsynchronouslyRepeat(plugin, plugin.getServer().getScheduler(), runnable, firstDelay, repeatDelay);
}
/**
* Schedule a given task for asynchronous execution.
* @param plugin - the owner plugin.
* @param scheduler - the current Bukkit scheduler.
* @param runnable - the task to run.
* @param firstDelay - the amount of time to wait until executing the task for the first time.
* @param repeatDelay - the amount of time inbetween each execution. If less than zero, the task is only executed once.
* @return A cancel token.
*/
public static TaskWrapper runAsynchronouslyRepeat(final Plugin plugin, final BukkitScheduler scheduler, Runnable runnable, long firstDelay, long repeatDelay) {
try {
@SuppressWarnings("deprecation")
final int taskID = scheduler.scheduleAsyncRepeatingTask(plugin, runnable, firstDelay, repeatDelay);
// Return the cancellable object
return new TaskWrapper() {
@Override
public void cancel() {
scheduler.cancelTask(taskID);
}
};
} catch (NoSuchMethodError e) {
return tryUpdatedVersion(plugin, scheduler, runnable, firstDelay, repeatDelay);
}
}
/**
* Attempt to do the same with the updated scheduling method.
* @param plugin - the owner plugin.
* @param scheduler - the current Bukkit scheduler.
* @param runnable - the task to run.
* @param firstDelay - the amount of time to wait until executing the task for the first time.
* @param repeatDelay - the amount of time inbetween each execution. If less than zero, the task is only executed once.
* @return A cancel token.
*/
private static TaskWrapper tryUpdatedVersion(final Plugin plugin, final BukkitScheduler scheduler, Runnable runnable, long firstDelay, long repeatDelay) {
final BukkitTask task = scheduler.runTaskTimerAsynchronously(plugin, runnable, firstDelay, repeatDelay);
return new TaskWrapper() {
@Override
public void cancel() {
task.cancel();
}
};
}
}
@@ -1,924 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.Nullable;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.injector.BukkitUnwrapper;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FieldUtils;
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.ReadOnlyFieldAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.collection.ConvertedMap;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
/**
* Wraps a DataWatcher that is used to transmit arbitrary key-value pairs with a given entity.
*
* @author Kristian
*/
public class WrappedDataWatcher extends AbstractWrapper implements Iterable<WrappedWatchableObject> {
/**
* Every custom watchable type in the Spigot protocol hack.
* @author Kristian
*/
public enum CustomType {
BYTE_SHORT("org.spigotmc.ProtocolData$ByteShort", 0, short.class),
DUAL_BYTE("org.spigotmc.ProtocolData$DualByte", 0, byte.class, byte.class),
HIDDEN_BYTE("org.spigotmc.ProtocolData$HiddenByte", 0, byte.class),
INT_BYTE("org.spigotmc.ProtocolData$IntByte", 2, int.class, byte.class),
DUAL_INT("org.spigotmc.ProtocolData$DualInt", 2, int.class, int.class);
private Class<?> spigotClass;
private ConstructorAccessor constructor;
private FieldAccessor secondaryValue;
private int typeId;
private CustomType(String className, int typeId, Class<?>... parameters) {
try {
this.spigotClass = Class.forName(className);
this.constructor = Accessors.getConstructorAccessor(spigotClass, parameters);
this.secondaryValue = parameters.length > 1 ? Accessors.getFieldAccessor(spigotClass, "value2", true) : null;
} catch (ClassNotFoundException e) {
// ProtocolLibrary.log(Level.WARNING, "Unable to find " + className);
this.spigotClass = null;
}
this.typeId = typeId;
}
/**
* Construct a new instance of this Spigot type.
* @param value - the value. Cannot be NULL.
* @return The instance to construct.
*/
Object newInstance(Object value) {
return newInstance(value, null);
}
/**
* Construct a new instance of this Spigot type.
* <p>
* The secondary value may be NULL if this custom type does not contain a secondary value.
* @param value - the value.
* @param secondary - optional secondary value.
* @return
*/
Object newInstance(Object value, Object secondary) {
Preconditions.checkNotNull(value, "value cannot be NULL.");
if (hasSecondary()) {
return constructor.invoke(value, secondary);
} else {
if (secondary != null) {
throw new IllegalArgumentException("Cannot construct " + this + " with a secondary value");
}
return constructor.invoke(value);
}
}
/**
* Set the secondary value of a given type.
* @param instance - the instance.
* @param secondary - the secondary value.
*/
void setSecondary(Object instance, Object secondary) {
if (!hasSecondary()) {
throw new IllegalArgumentException(this + " does not have a secondary value.");
}
secondaryValue.set(instance, secondary);
}
/**
* Get the secondary value of a type.
* @param instance - the instance.
* @return The secondary value.
*/
Object getSecondary(Object instance) {
if (!hasSecondary()) {
throw new IllegalArgumentException(this + " does not have a secondary value.");
}
return secondaryValue.get(instance);
}
/**
* Determine if this type has a secondary value.
* @return TRUE if it does, FALSE otherwise.
*/
public boolean hasSecondary() {
return secondaryValue != null;
}
/**
* Underlying Spigot class.
* @return The class.
*/
public Class<?> getSpigotClass() {
return spigotClass;
}
/**
* The equivalent type ID.
* @return The equivalent ID.
*/
public int getTypeId() {
return typeId;
}
/**
* Retrieve the custom Spigot type of a value.
* @param value - the value.
* @return The Spigot type, or NULL if not found.
*/
public static CustomType fromValue(Object value) {
for (CustomType type : CustomType.values()) {
if (type.getSpigotClass().isInstance(value)) {
return type;
}
}
return null;
}
}
/**
* Used to assign integer IDs to given types.
*/
private static Map<Class<?>, Integer> TYPE_MAP;
/**
* Custom types in the bountiful update.
*/
private static Map<Class<?>, Integer> CUSTOM_MAP;
// Accessors
private static FieldAccessor TYPE_MAP_ACCESSOR;
private static FieldAccessor VALUE_MAP_ACCESSOR;
// Fields
private static Field READ_WRITE_LOCK_FIELD;
private static Field ENTITY_FIELD;
// Methods
private static Method CREATE_KEY_VALUE_METHOD;
private static Method UPDATE_KEY_VALUE_METHOD;
private static Method GET_KEY_VALUE_METHOD;
// Constructors
private static Constructor<?> CREATE_DATA_WATCHER_CONSTRUCTOR;
// Entity methods
private volatile static Field ENTITY_DATA_FIELD;
/**
* Whether or not this class has already been initialized.
*/
private static boolean HAS_INITIALIZED;
// Lock
private ReadWriteLock readWriteLock;
// Map of watchable objects
private Map<Integer, Object> watchableObjects;
// A map view of all the watchable objects
private Map<Integer, WrappedWatchableObject> mapView;
/**
* Initialize a new data watcher.
* @throws FieldAccessException If we're unable to wrap a DataWatcher.
*/
public WrappedDataWatcher() {
super(MinecraftReflection.getDataWatcherClass());
// Just create a new watcher
try {
if (MinecraftReflection.isUsingNetty()) {
setHandle(newEntityHandle(null));
} else {
setHandle(getHandleType().newInstance());
}
initialize();
} catch (Exception e) {
throw new RuntimeException("Unable to construct DataWatcher.", e);
}
}
/**
* Create a wrapper for a given data watcher.
* @param handle - the data watcher to wrap.
* @throws FieldAccessException If we're unable to wrap a DataWatcher.
*/
public WrappedDataWatcher(Object handle) {
super(MinecraftReflection.getDataWatcherClass());
setHandle(handle);
initialize();
}
/**
* Construct a new data watcher with the given entity.
* <p>
* In 1.6.4 and ealier, this will fall back to using {@link #WrappedDataWatcher()}.
* @param entity - the entity.
* @return The wrapped data watcher.
*/
public static WrappedDataWatcher newWithEntity(Entity entity) {
// Use the old constructor
if (!MinecraftReflection.isUsingNetty())
return new WrappedDataWatcher();
return new WrappedDataWatcher(newEntityHandle(entity));
}
/**
* Construct a new native DataWatcher with the given entity.
* <p>
* Warning: This is only supported in 1.7.2 and above.
* @param entity - the entity, or NULL.
* @return The data watcher.
*/
private static Object newEntityHandle(Entity entity) {
Class<?> dataWatcher = MinecraftReflection.getDataWatcherClass();
try {
if (CREATE_DATA_WATCHER_CONSTRUCTOR == null)
CREATE_DATA_WATCHER_CONSTRUCTOR = dataWatcher.getConstructor(MinecraftReflection.getEntityClass());
return CREATE_DATA_WATCHER_CONSTRUCTOR.newInstance(
BukkitUnwrapper.getInstance().unwrapItem(entity)
);
} catch (Exception e) {
throw new RuntimeException("Cannot construct data watcher.", e);
}
}
/**
* Create a new data watcher for a list of watchable objects.
* <p>
* Note that the watchable objects are not cloned, and will be modified in place. Use "deepClone" if
* that is not desirable.
* <p>
* The {@link #removeObject(int)} method will not modify the given list, however.
*
* @param watchableObjects - list of watchable objects that will be copied.
* @throws FieldAccessException Unable to read watchable objects.
*/
public WrappedDataWatcher(List<WrappedWatchableObject> watchableObjects) throws FieldAccessException {
this();
Lock writeLock = getReadWriteLock().writeLock();
Map<Integer, Object> map = getWatchableObjectMap();
writeLock.lock();
try {
// Add the watchable objects by reference
for (WrappedWatchableObject watched : watchableObjects) {
map.put(watched.getIndex(), watched.handle);
}
} finally {
writeLock.unlock();
}
}
/**
* Retrieve the ID of a given type, if it's allowed to be watched.
* @param clazz - Class to check for.
* @return The ID, or NULL if it cannot be watched.
* @throws FieldAccessException If we cannot initialize the reflection machinery.
*/
public static Integer getTypeID(Class<?> clazz) throws FieldAccessException {
initialize();
Integer result = TYPE_MAP.get(WrappedWatchableObject.getUnwrappedType(clazz));
if (result == null) {
result = CUSTOM_MAP.get(clazz);
}
return result;
}
/**
* Retrieve the type of a given ID, if it's allowed to be watched.
* @param id - id to get type for
* @return The type using a given ID, or NULL if it cannot be watched.
* @throws FieldAccessException If we cannot initialize the reflection machinery.
*/
public static Class<?> getTypeClass(int id) throws FieldAccessException {
initialize();
for (Map.Entry<Class<?>, Integer> entry : TYPE_MAP.entrySet()) {
if (Objects.equal(entry.getValue(), id)) {
return entry.getKey();
}
}
// Unknown class type
return null;
}
/**
* Get a watched byte.
* @param index - index of the watched byte.
* @return The watched byte, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public Byte getByte(int index) throws FieldAccessException {
return (Byte) getObject(index);
}
/**
* Get a watched short.
* @param index - index of the watched short.
* @return The watched short, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public Short getShort(int index) throws FieldAccessException {
return (Short) getObject(index);
}
/**
* Get a watched integer.
* @param index - index of the watched integer.
* @return The watched integer, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public Integer getInteger(int index) throws FieldAccessException {
return (Integer) getObject(index);
}
/**
* Get a watched float.
* @param index - index of the watched float.
* @return The watched float, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public Float getFloat(int index) throws FieldAccessException {
return (Float) getObject(index);
}
/**
* Get a watched string.
* @param index - index of the watched string.
* @return The watched string, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public String getString(int index) throws FieldAccessException {
return (String) getObject(index);
}
/**
* Get a watched string.
* @param index - index of the watched string.
* @return The watched string, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public ItemStack getItemStack(int index) throws FieldAccessException {
return (ItemStack) getObject(index);
}
/**
* Get a watched string.
* @param index - index of the watched string.
* @return The watched string, or NULL if this value doesn't exist.
* @throws FieldAccessException Cannot read underlying field.
*/
public WrappedChunkCoordinate getChunkCoordinate(int index) throws FieldAccessException {
return (WrappedChunkCoordinate) getObject(index);
}
/**
* Retrieve a watchable object by index.
* @param index - index of the object to retrieve.
* @return The watched object.
* @throws FieldAccessException Cannot read underlying field.
*/
public Object getObject(int index) throws FieldAccessException {
Object watchable = getWatchedObject(index);
if (watchable != null) {
return new WrappedWatchableObject(watchable).getValue();
} else {
return null;
}
}
/**
* Retrieve every watchable object in this watcher.
* @return Every watchable object.
* @throws FieldAccessException If reflection failed.
*/
public List<WrappedWatchableObject> getWatchableObjects() throws FieldAccessException {
Lock readLock = getReadWriteLock().readLock();
readLock.lock();
try {
List<WrappedWatchableObject> result = new ArrayList<WrappedWatchableObject>();
// Add each watchable object to the list
for (Object watchable : getWatchableObjectMap().values()) {
if (watchable != null) {
result.add(new WrappedWatchableObject(watchable));
} else {
result.add(null);
}
}
return result;
} finally {
readLock.unlock();
}
}
@Override
public boolean equals(Object obj) {
// Quick checks
if (obj == this)
return true;
if (obj == null)
return false;
if (obj instanceof WrappedDataWatcher) {
WrappedDataWatcher other = (WrappedDataWatcher) obj;
Iterator<WrappedWatchableObject> first = iterator(), second = other.iterator();
// Make sure they're the same size
if (size() != other.size())
return false;
for (; first.hasNext() && second.hasNext(); ) {
// See if the two elements are equal
if (!first.next().equals(second.next()))
return false;
}
return true;
}
return false;
}
@Override
public int hashCode() {
return getWatchableObjects().hashCode();
}
/**
* Retrieve a copy of every index associated with a watched object.
* @return Every watched object index.
* @throws FieldAccessException If we're unable to read the underlying object.
*/
public Set<Integer> indexSet() throws FieldAccessException {
Lock readLock = getReadWriteLock().readLock();
readLock.lock();
try {
return new HashSet<Integer>(getWatchableObjectMap().keySet());
} finally {
readLock.unlock();
}
}
/**
* Clone the content of the current DataWatcher.
* @return A cloned data watcher.
*/
public WrappedDataWatcher deepClone() {
WrappedDataWatcher clone = new WrappedDataWatcher();
// Make a new copy instead
for (WrappedWatchableObject watchable : this) {
clone.setObject(watchable.getIndex(), watchable.getClonedValue());
}
return clone;
}
/**
* Retrieve the number of watched objects.
* @return Watched object count.
* @throws FieldAccessException If we're unable to read the underlying object.
*/
public int size() throws FieldAccessException {
Lock readLock = getReadWriteLock().readLock();
readLock.lock();
try {
return getWatchableObjectMap().size();
} finally {
readLock.unlock();
}
}
/**
* Remove a given object from the underlying DataWatcher.
* @param index - index of the object to remove.
* @return The watchable object that was removed, or NULL If none could be found.
*/
public WrappedWatchableObject removeObject(int index) {
Lock writeLock = getReadWriteLock().writeLock();
writeLock.lock();
try {
Object removed = getWatchableObjectMap().remove(index);
return removed != null ? new WrappedWatchableObject(removed) : null;
} finally {
writeLock.unlock();
}
}
/**
* Set a watched byte.
* @param index - index of the watched byte.
* @param newValue - the new watched value.
* @throws FieldAccessException Cannot read underlying field.
*/
public void setObject(int index, Object newValue) throws FieldAccessException {
setObject(index, newValue, true);
}
/**
* Set a watched byte.
* @param index - index of the watched byte.
* @param newValue - the new watched value.
* @param update - whether or not to refresh every listening client.
* @throws FieldAccessException Cannot read underlying field.
*/
public void setObject(int index, Object newValue, boolean update) throws FieldAccessException {
// Aquire write lock
Lock writeLock = getReadWriteLock().writeLock();
writeLock.lock();
try {
Object watchable = getWatchedObject(index);
if (watchable != null) {
new WrappedWatchableObject(watchable).setValue(newValue, update);
} else {
CREATE_KEY_VALUE_METHOD.invoke(handle, index, WrappedWatchableObject.getUnwrapped(newValue));
}
// Handle invoking the method
} catch (IllegalArgumentException e) {
throw new FieldAccessException("Cannot convert arguments.", e);
} catch (IllegalAccessException e) {
throw new FieldAccessException("Illegal access.", e);
} catch (InvocationTargetException e) {
throw new FieldAccessException("Checked exception in Minecraft.", e);
} finally {
writeLock.unlock();
}
}
/**
* Set a watched byte with an optional secondary value.
* @param index - index of the watched byte.
* @param newValue - the new watched value.
* @param secondary - optional secondary value.
* @param update - whether or not to refresh every listening client.
* @param type - custom type.
* @throws FieldAccessException If we cannot read the underlying field.
*/
public void setObject(int index, Object newValue, Object secondary, boolean update, CustomType type) throws FieldAccessException {
Object created = type.newInstance(newValue, secondary);
// Now update the watcher
setObject(index, created, update);
}
private Object getWatchedObject(int index) throws FieldAccessException {
// We use the get-method first and foremost
if (GET_KEY_VALUE_METHOD != null) {
try {
return GET_KEY_VALUE_METHOD.invoke(handle, index);
} catch (Exception e) {
throw new FieldAccessException("Cannot invoke get key method for index " + index, e);
}
} else {
try {
getReadWriteLock().readLock().lock();
return getWatchableObjectMap().get(index);
} finally {
getReadWriteLock().readLock().unlock();
}
}
}
/**
* Retrieve the current read write lock.
* @return Current read write lock.
* @throws FieldAccessException If we're unable to read the underlying field.
*/
protected ReadWriteLock getReadWriteLock() throws FieldAccessException {
try {
// Cache the read write lock
if (readWriteLock != null)
return readWriteLock;
else if (READ_WRITE_LOCK_FIELD != null)
return readWriteLock = (ReadWriteLock) FieldUtils.readField(READ_WRITE_LOCK_FIELD, handle, true);
else
return readWriteLock = new ReentrantReadWriteLock();
} catch (IllegalAccessException e) {
throw new FieldAccessException("Unable to read lock field.", e);
}
}
/**
* Retrieve the underlying map of key values that stores watchable objects.
* @return A map of watchable objects.
* @throws FieldAccessException If we don't have permission to perform reflection.
*/
@SuppressWarnings("unchecked")
protected Map<Integer, Object> getWatchableObjectMap() throws FieldAccessException {
if (watchableObjects == null)
watchableObjects = (Map<Integer, Object>) VALUE_MAP_ACCESSOR.get(handle);
return watchableObjects;
}
/**
* Retrieve the data watcher associated with an entity.
* @param entity - the entity to read from.
* @return Associated data watcher.
* @throws FieldAccessException Reflection failed.
*/
public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException {
if (ENTITY_DATA_FIELD == null)
ENTITY_DATA_FIELD = FuzzyReflection.fromClass(MinecraftReflection.getEntityClass(), true).
getFieldByType("datawatcher", MinecraftReflection.getDataWatcherClass());
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
try {
Object nsmWatcher = FieldUtils.readField(ENTITY_DATA_FIELD, unwrapper.unwrapItem(entity), true);
if (nsmWatcher != null)
return new WrappedDataWatcher(nsmWatcher);
else
return null;
} catch (IllegalAccessException e) {
throw new FieldAccessException("Cannot access DataWatcher field.", e);
}
}
/**
* Invoked when a data watcher is first used.
*/
@SuppressWarnings("unchecked")
private static void initialize() throws FieldAccessException {
// This method should only be run once, even if an exception is thrown
if (!HAS_INITIALIZED)
HAS_INITIALIZED = true;
else
return;
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getDataWatcherClass(), true);
for (Field lookup : fuzzy.getFieldListByType(Map.class)) {
if (Modifier.isStatic(lookup.getModifiers())) {
// This must be the type map
TYPE_MAP_ACCESSOR = Accessors.getFieldAccessor(lookup, true);
} else {
// If not, then we're probably dealing with the value map
VALUE_MAP_ACCESSOR = Accessors.getFieldAccessor(lookup, true);
}
}
// Spigot workaround (not necessary
initializeSpigot(fuzzy);
// Any custom types
CUSTOM_MAP = initializeCustom();
// Initialize static type type
TYPE_MAP = (Map<Class<?>, Integer>) TYPE_MAP_ACCESSOR.get(null);
try {
READ_WRITE_LOCK_FIELD = fuzzy.getFieldByType("readWriteLock", ReadWriteLock.class);
} catch (IllegalArgumentException e) {
// It's not a big deal
}
// Check for the entity field as well
if (MinecraftReflection.isUsingNetty()) {
ENTITY_FIELD = fuzzy.getFieldByType("entity", MinecraftReflection.getEntityClass());
ENTITY_FIELD.setAccessible(true);
}
initializeMethods(fuzzy);
}
// For Spigot's bountiful update patch
private static Map<Class<?>, Integer> initializeCustom() {
Map<Class<?>, Integer> map = Maps.newHashMap();
for (CustomType type : CustomType.values()) {
if (type.getSpigotClass() != null) {
map.put(type.getSpigotClass(), type.getTypeId());
}
}
return map;
}
// TODO: Remove, as this was fixed in build #1189 of Spigot
private static void initializeSpigot(FuzzyReflection fuzzy) {
// See if the workaround is needed
if (TYPE_MAP_ACCESSOR != null && VALUE_MAP_ACCESSOR != null)
return;
for (Field lookup : fuzzy.getFields()) {
final Class<?> type = lookup.getType();
if (TroveWrapper.isTroveClass(type)) {
// Create a wrapper accessor
final ReadOnlyFieldAccessor accessor = TroveWrapper.wrapMapField(
Accessors.getFieldAccessor(lookup, true), new Function<Integer, Integer>() {
@Override
public Integer apply(@Nullable Integer value) {
// Do not use zero for no entry value
if (value == 0)
return -1;
return value;
}
});
if (Modifier.isStatic(lookup.getModifiers())) {
TYPE_MAP_ACCESSOR = accessor;
} else {
VALUE_MAP_ACCESSOR = accessor;
}
}
}
if (TYPE_MAP_ACCESSOR == null)
throw new IllegalArgumentException("Unable to find static type map.");
if (VALUE_MAP_ACCESSOR == null)
throw new IllegalArgumentException("Unable to find static value map.");
}
private static void initializeMethods(FuzzyReflection fuzzy) {
List<Method> candidates = fuzzy.getMethodListByParameters(Void.TYPE,
new Class<?>[] { int.class, Object.class});
// Load the get-method
try {
GET_KEY_VALUE_METHOD = fuzzy.getMethodByParameters(
"getWatchableObject", MinecraftReflection.getWatchableObjectClass(), new Class[] { int.class });
GET_KEY_VALUE_METHOD.setAccessible(true);
} catch (IllegalArgumentException e) {
// Use the fallback method
}
for (Method method : candidates) {
if (!method.getName().startsWith("watch")) {
CREATE_KEY_VALUE_METHOD = method;
} else {
UPDATE_KEY_VALUE_METHOD = method;
}
}
// Did we succeed?
if (UPDATE_KEY_VALUE_METHOD == null || CREATE_KEY_VALUE_METHOD == null) {
// Go by index instead
if (candidates.size() > 1) {
CREATE_KEY_VALUE_METHOD = candidates.get(0);
UPDATE_KEY_VALUE_METHOD = candidates.get(1);
} else {
throw new IllegalStateException("Unable to find create and update watchable object. Update ProtocolLib.");
}
// Be a little scientist - see if this in fact IS the right way around
try {
WrappedDataWatcher watcher = new WrappedDataWatcher();
watcher.setObject(0, 0);
watcher.setObject(0, 1);
if (watcher.getInteger(0) != 1) {
throw new IllegalStateException("This cannot be!");
}
} catch (Exception e) {
// Nope
UPDATE_KEY_VALUE_METHOD = candidates.get(0);
CREATE_KEY_VALUE_METHOD = candidates.get(1);
}
}
}
@Override
public Iterator<WrappedWatchableObject> iterator() {
// We'll wrap the iterator instead of creating a new list every time
return Iterators.transform(getWatchableObjectMap().values().iterator(),
new Function<Object, WrappedWatchableObject>() {
@Override
public WrappedWatchableObject apply(@Nullable Object item) {
if (item != null)
return new WrappedWatchableObject(item);
else
return null;
}
});
}
/**
* Retrieve a view of this DataWatcher as a map.
* <p>
* Any changes to the map will be reflected in this DataWatcher, and vice versa.
* @return A view of the data watcher as a map.
*/
public Map<Integer, WrappedWatchableObject> asMap() {
// Construct corresponding map
if (mapView == null) {
mapView = new ConvertedMap<Integer, Object, WrappedWatchableObject>(getWatchableObjectMap()) {
@Override
protected Object toInner(WrappedWatchableObject outer) {
if (outer == null)
return null;
return outer.getHandle();
}
@Override
protected WrappedWatchableObject toOuter(Object inner) {
if (inner == null)
return null;
return new WrappedWatchableObject(inner);
}
};
}
return mapView;
}
@Override
public String toString() {
return asMap().toString();
}
/**
* Retrieve the entity associated with this data watcher.
* <p>
* <b>Warning:</b> This is only supported on 1.7.2 and above.
* @return The entity, or NULL.
*/
public Entity getEntity() {
if (!MinecraftReflection.isUsingNetty())
throw new IllegalStateException("This method is only supported on 1.7.2 and above.");
try {
return (Entity) MinecraftReflection.getBukkitEntity(ENTITY_FIELD.get(handle));
} catch (Exception e) {
throw new RuntimeException("Unable to retrieve entity.", e);
}
}
/**
* Set the entity associated with this data watcher.
* <p>
* <b>Warning:</b> This is only supported on 1.7.2 and above.
* @param entity - the new entity.
*/
public void setEntity(Entity entity) {
if (!MinecraftReflection.isUsingNetty())
throw new IllegalStateException("This method is only supported on 1.7.2 and above.");
try {
ENTITY_FIELD.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity));
} catch (Exception e) {
throw new RuntimeException("Unable to set entity.", e);
}
}
}
@@ -1,467 +0,0 @@
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Constructor;
import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Objects;
/**
* Represents a watchable object.
*
* @author Kristian
*/
public class WrappedWatchableObject extends AbstractWrapper {
// Whether or not the reflection machinery has been initialized
private static boolean hasInitialized;
// The field containing the value itself
private static StructureModifier<Object> baseModifier;
// Used to create new watchable objects
private static Constructor<?> watchableConstructor;
// The watchable object class type
private static Class<?> watchableObjectClass;
protected StructureModifier<Object> modifier;
// Type of the stored value
private Class<?> typeClass;
/**
* Wrap a given raw Minecraft watchable object.
* @param handle - the raw watchable object to wrap.
*/
public WrappedWatchableObject(Object handle) {
super(MinecraftReflection.getWatchableObjectClass());
load(handle);
}
/**
* Construct a watchable object from an index and a given value.
* @param index - the index.
* @param value - non-null value of specific types.
*/
public WrappedWatchableObject(int index, Object value) {
super(MinecraftReflection.getWatchableObjectClass());
if (value == null)
throw new IllegalArgumentException("Value cannot be NULL.");
// Get the correct type ID
Integer typeID = WrappedDataWatcher.getTypeID(value.getClass());
if (typeID != null) {
if (watchableConstructor == null) {
try {
watchableConstructor = MinecraftReflection.getWatchableObjectClass().
getConstructor(int.class, int.class, Object.class);
} catch (Exception e) {
throw new RuntimeException("Cannot get the WatchableObject(int, int, Object) constructor.", e);
}
}
// Create the object
try {
load(watchableConstructor.newInstance(typeID, index, getUnwrapped(value)));
} catch (Exception e) {
throw new RuntimeException("Cannot construct underlying WatchableObject.", e);
}
} else {
throw new IllegalArgumentException("Cannot watch the type " + value.getClass());
}
}
// /**
// * Construct a custom watchable object from an index, value and custom type.
// * @param index - the index.
// * @param primary - non-null value of specific types.
// * @param secondary - optional secondary value, if the type can store it.
// * @param type - the custom Spigot type.
// */
// public WrappedWatchableObject(int index, Object value, Object secondary, CustomType type) {
// this(index, type.newInstance(value, secondary));
// }
// Wrap a NMS object
private void load(Object handle) {
initialize();
this.handle = handle;
this.modifier = baseModifier.withTarget(handle);
// Make sure the type is correct
if (!watchableObjectClass.isAssignableFrom(handle.getClass())) {
throw new ClassCastException("Cannot cast the class " + handle.getClass().getName() +
" to " + watchableObjectClass.getName());
}
}
/**
* Initialize reflection machinery.
*/
private static void initialize() {
if (!hasInitialized) {
hasInitialized = true;
watchableObjectClass = MinecraftReflection.getWatchableObjectClass();
baseModifier = new StructureModifier<Object>(watchableObjectClass, null, false);
}
}
// /**
// * Retrieve the custom type of this object.
// * @return The custom type, or NULL if not applicable.
// */
// public CustomType getCustomType() {
// return CustomType.fromValue(getValue());
// }
/**
* Retrieve the correct super type of the current value.
* @return Super type.
* @throws FieldAccessException Unable to read values.
*/
public Class<?> getType() throws FieldAccessException {
return getWrappedType(getTypeRaw());
}
/**
* Retrieve the correct super type of the current value, given the raw NMS object.
* @return Super type.
* @throws FieldAccessException Unable to read values.
*/
private Class<?> getTypeRaw() throws FieldAccessException {
if (typeClass == null) {
typeClass = WrappedDataWatcher.getTypeClass(getTypeID());
if (typeClass == null) {
throw new IllegalStateException("Unrecognized data type: " + getTypeID());
}
}
return typeClass;
}
/**
* Retrieve the index of this watchable object. This is used to identify a value.
* @return Object index.
* @throws FieldAccessException Reflection failed.
*/
public int getIndex() throws FieldAccessException {
return modifier.<Integer>withType(int.class).read(1);
}
/**
* Set the the index of this watchable object.
* @param index - the new object index.
* @throws FieldAccessException Reflection failed.
*/
public void setIndex(int index) throws FieldAccessException {
modifier.<Integer>withType(int.class).write(1, index);
}
/**
* Retrieve the type ID of a watchable object.
* <table border=1>
* <caption>Type to Value</caption>
* <tbody>
* <tr>
* <th>Type ID</th>
* <th>Data Type</th>
* </tr>
* <tr>
* <td>0</td>
* <td>Byte</td>
* </tr>
* <tr>
* <td>1</td>
* <td>Short</td>
* </tr>
* <tr>
* <td>2</td>
* <td>Int</td>
* </tr>
* <tr>
* <td>3</td>
* <td>Float</td>
* </tr>
* <tr>
* <td>4</td>
* <td>{@link String}</td>
* </tr>
* <tr>
* <td>5</td>
* <td>{@link org.bukkit.inventory.ItemStack ItemStack}</td>
* </tr>
* <tr>
* <td>6<sup>*</sup></td>
* <td>{@link com.comphenix.protocol.wrappers.ChunkPosition ChunkPosition}</td>
* </tr>
* </tbody>
* </table>
* @return Type ID that identifies the type of the value.
* @throws FieldAccessException Reflection failed.
*/
public int getTypeID() throws FieldAccessException {
return modifier.<Integer>withType(int.class).read(0);
}
/**
* Set the type ID of a watchable object.
* @param id - the new ID.
* @throws FieldAccessException Reflection failed.
* @see #getTypeID()
*/
public void setTypeID(int id) throws FieldAccessException {
modifier.<Integer>withType(int.class).write(0, id);
}
/**
* Update the value field.
* @param newValue - new value.
* @throws FieldAccessException Unable to use reflection.
*/
public void setValue(Object newValue) throws FieldAccessException {
setValue(newValue, true);
}
/**
* Update the value field.
* @param newValue - new value.
* @param updateClient - whether or not to update listening clients.
* @throws FieldAccessException Unable to use reflection.
*/
public void setValue(Object newValue, boolean updateClient) throws FieldAccessException {
// Verify a few quick things
if (newValue == null)
throw new IllegalArgumentException("Cannot watch a NULL value.");
if (!getType().isAssignableFrom(newValue.getClass()))
throw new IllegalArgumentException("Object " + newValue + " must be of type " + getType().getName());
// See if we should update the client to
if (updateClient)
setDirtyState(true);
// Use the modifier to set the value
modifier.withType(Object.class).write(0, getUnwrapped(newValue));
}
/**
* Read the underlying value field.
* @return The underlying value.
*/
private Object getNMSValue() {
return modifier.withType(Object.class).read(0);
}
/**
* Read the value field.
* @return The watched value.
* @throws FieldAccessException Unable to use reflection.
*/
public Object getValue() throws FieldAccessException {
return getWrapped(modifier.withType(Object.class).read(0));
}
// /**
// * Retrieve the secondary value associated with this watchable object.
// * <p>
// * This is only applicable for certain {@link CustomType}.
// * @return The secondary value, or NULL if not found.
// */
// public Object getSecondaryValue() {
// CustomType type = getCustomType();
// return type != null ? type.getSecondary(getValue()) : null;
// }
//
// /**
// * Set the secondary value.
// * @param secondary - the secondary value.
// * @throws IllegalStateException If this watchable object does not have a secondary value.
// */
// public void setSecondaryValue(Object secondary) {
// CustomType type = getCustomType();
//
// if (type == null) {
// throw new IllegalStateException(this + " does not have a custom type.");
// }
// type.setSecondary(getValue(), secondary);
// }
/**
* Set whether or not the value must be synchronized with the client.
* @param dirty - TRUE if the value should be synchronized, FALSE otherwise.
* @throws FieldAccessException Unable to use reflection.
*/
public void setDirtyState(boolean dirty) throws FieldAccessException {
modifier.<Boolean>withType(boolean.class).write(0, dirty);
}
/**
* Retrieve whether or not the value must be synchronized with the client.
* @return TRUE if the value should be synchronized, FALSE otherwise.
* @throws FieldAccessException Unable to use reflection.
*/
public boolean getDirtyState() throws FieldAccessException {
return modifier.<Boolean>withType(boolean.class).read(0);
}
/**
* Retrieve the wrapped object value, if needed.
* @param value - the raw NMS object to wrap.
* @return The wrapped object.
*/
@SuppressWarnings("rawtypes")
static Object getWrapped(Object value) {
// Handle the special cases
if (MinecraftReflection.isItemStack(value)) {
return BukkitConverters.getItemStackConverter().getSpecific(value);
} else if (MinecraftReflection.isChunkCoordinates(value)) {
return new WrappedChunkCoordinate((Comparable) value);
} else {
return value;
}
}
/**
* Retrieve the wrapped type, if needed.
* @param wrapped - the wrapped class type.
* @return The wrapped class type.
*/
static Class<?> getWrappedType(Class<?> unwrapped) {
if (unwrapped.equals(MinecraftReflection.getChunkPositionClass()))
return ChunkPosition.class;
else if (unwrapped.equals(MinecraftReflection.getBlockPositionClass()))
return BlockPosition.class;
else if (unwrapped.equals(MinecraftReflection.getChunkCoordinatesClass()))
return WrappedChunkCoordinate.class;
else if (unwrapped.equals(MinecraftReflection.getItemStackClass()))
return ItemStack.class;
else
return unwrapped;
}
/**
* Retrieve the raw NMS value.
* @param wrapped - the wrapped position.
* @return The raw NMS object.
*/
static Object getUnwrapped(Object wrapped) {
// Convert special cases
if (wrapped instanceof ChunkPosition)
return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped);
else if (wrapped instanceof BlockPosition)
return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped);
else if (wrapped instanceof WrappedChunkCoordinate)
return ((WrappedChunkCoordinate) wrapped).getHandle();
else if (wrapped instanceof ItemStack)
return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped);
else
return wrapped;
}
/**
* Retrieve the unwrapped type, if needed.
* @param wrapped - the unwrapped class type.
* @return The unwrapped class type.
*/
static Class<?> getUnwrappedType(Class<?> wrapped) {
if (wrapped.equals(ChunkPosition.class))
return MinecraftReflection.getChunkPositionClass();
else if (wrapped.equals(BlockPosition.class))
return MinecraftReflection.getBlockPositionClass();
else if (wrapped.equals(WrappedChunkCoordinate.class))
return MinecraftReflection.getChunkCoordinatesClass();
else if (ItemStack.class.isAssignableFrom(wrapped))
return MinecraftReflection.getItemStackClass();
else
return wrapped;
}
/**
* Clone the current wrapped watchable object, along with any contained objects.
* @return A deep clone of the current watchable object.
* @throws FieldAccessException If we're unable to use reflection.
*/
public WrappedWatchableObject deepClone() throws FieldAccessException {
WrappedWatchableObject clone = new WrappedWatchableObject(
DefaultInstances.DEFAULT.getDefault(MinecraftReflection.getWatchableObjectClass()));
clone.setDirtyState(getDirtyState());
clone.setIndex(getIndex());
clone.setTypeID(getTypeID());
clone.setValue(getClonedValue(), false);
return clone;
}
// Helper
Object getClonedValue() throws FieldAccessException {
Object value = getNMSValue();
// Only a limited set of references types are supported
if (MinecraftReflection.isBlockPosition(value)) {
EquivalentConverter<BlockPosition> converter = BlockPosition.getConverter();
return converter.getGeneric(MinecraftReflection.getBlockPositionClass(), converter.getSpecific(value));
} else if (MinecraftReflection.isChunkPosition(value)) {
EquivalentConverter<ChunkPosition> converter = ChunkPosition.getConverter();
return converter.getGeneric(MinecraftReflection.getChunkPositionClass(), converter.getSpecific(value));
} else if (MinecraftReflection.isItemStack(value)) {
return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(value).clone());
} else {
// A string or primitive wrapper, which are all immutable.
return value;
}
}
@Override
public boolean equals(Object obj) {
// Quick checks
if (obj == this)
return true;
if (obj == null)
return false;
if (obj instanceof WrappedWatchableObject) {
WrappedWatchableObject other = (WrappedWatchableObject) obj;
return Objects.equal(getIndex(), other.getIndex()) &&
Objects.equal(getTypeID(), other.getTypeID()) &&
Objects.equal(getValue(), other.getValue());
}
// No, this is not equivalent
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(getIndex(), getTypeID(), getValue());
}
@Override
public String toString() {
return String.format("[%s: %s (%s)]", getIndex(), getValue(), getType().getSimpleName());
}
}
@@ -1,40 +0,0 @@
package com.comphenix.protocol;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.compat.netty.independent.NettyProtocolRegistry;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
public class PacketTypeTest {
@BeforeClass
public static void initializeReflection() {
BukkitInitialization.initializePackage();
}
@Test
public void testFindCurrent() {
assertEquals(PacketType.Play.Client.STEER_VEHICLE, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
}
@Test
public void ensureAllExist() {
ProtocolRegistry registry = new NettyProtocolRegistry();
Map<PacketType, Class<?>> lookup = registry.getPacketTypeLookup();
for (Entry<PacketType, Class<?>> entry : lookup.entrySet()) {
PacketType type = entry.getKey();
Class<?> clazz = entry.getValue();
assertFalse("Packet " + clazz + " does not have a corresponding PacketType!", type.isDynamic());
}
}
}
@@ -1,25 +0,0 @@
package com.comphenix.protocol.reflect.cloning;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
public class AggregateClonerTest {
@BeforeClass
public static void initializeBukkit() {
BukkitInitialization.initializePackage();
}
@Test
public void testArrays() {
List<Integer> input = Arrays.asList(1, 2, 3);
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
}
}
+6 -5
View File
@@ -15,8 +15,8 @@ Currently maintained by dmulloy2 on behalf of [Spigot](http://www.spigotmc.org/)
### Resources
* [Resource Page](http://www.spigotmc.org/resources/protocollib.1997/)
* [Downloads](http://ci.shadowvolt.com/job/ProtocolLib)
* [JavaDoc](http://ci.shadowvolt.com/job/ProtocolLib/javadoc)
* [Dev Builds](http://ci.dmulloy2.net/job/ProtocolLib)
* [JavaDoc](http://ci.dmulloy2.net/job/ProtocolLib/javadoc)
### Compilation
@@ -47,13 +47,13 @@ You can also add ProtocolLib as a Maven dependency:
<url>http://repo.dmulloy2.net/content/groups/public/</url>
</repository>
...
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>3.6.4</version>
<version>3.6.5</version>
</dependency>
</dependencies>
````
@@ -131,6 +131,7 @@ you don't have to create an ArrayList with this version:
````java
PacketContainer fakeExplosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
fakeExplosion.getDoubles().
write(0, player.getLocation().getX()).
write(1, player.getLocation().getY()).
@@ -159,4 +160,4 @@ types. It's remarkably consistent across different versions.
### Incompatibility
The following plugins (to be expanded) are not compatible with ProtocolLib:
* TagAPI
* TagAPI
+194 -274
View File
@@ -1,275 +1,195 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>ProtocolLib-v1_7_R4</artifactId>
<name>ProtocolLib-v1_7_R4</name>
<version>3.6.5</version>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>http://www.spigotmc.org/resources/protocollib.1997/</url>
<packaging>jar</packaging>
<parent>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib-Parent</artifactId>
<version>v3-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.number></project.build.number>
</properties>
<repositories>
<repository>
<id>md_5-repo</id>
<url>http://repo.md-5.net/content/groups/public/</url>
</repository>
</repositories>
<build>
<defaultGoal>clean install</defaultGoal>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>false</shadedArtifactAttached>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>net.sf</pattern>
<shadedPattern>com.comphenix.net.sf</shadedPattern>
</relocation>
</relocations>
<artifactSet>
<excludes>
<exclude>org.spigotmc:spigot</exclude>
<exclude>org.spigotmc:spigot-api</exclude>
<exclude>junit:junit</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifestEntries>
<Main-Class>com.comphenix.protocol.Application</Main-Class>
<Implementation-Title>ProtocolLib</Implementation-Title>
<Implementation-Version>${project.version}${project.build.number}</Implementation-Version>
<Implementation-Vendor>dmulloy2</Implementation-Vendor>
</manifestEntries>
</archive>
<finalName>ProtocolLib</finalName>
<outputDirectory>../../target/</outputDirectory>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-javadocs</id>
</execution>
</executions>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<threshold>High</threshold>
<effort>Default</effort>
</configuration>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>jenkins</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
</properties>
</profile>
<profile>
<id>release-sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<scm>
<connection>scm:git:git://github.com/dmulloy2/ProtocolLib.git</connection>
<developerConnection>scm:git:git@github.com:dmulloy2/ProtocolLib.git</developerConnection>
<url>https://github.com/dmulloy2/ProtocolLib</url>
</scm>
<licenses>
<license>
<name>GNU GENERAL PUBLIC LICENSE - Version 2, June 1991</name>
<url>http://www.gnu.org/licenses/gpl-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>dmulloy2</id>
<name>Dan Mulloy</name>
<url>http://dmulloy2.net/</url>
<roles>
<role>developer</role>
<role>maintainer</role>
</roles>
</developer>
<developer>
<id>aadnk</id>
<name>Kristian S. Stangeland</name>
<email>kr_stang@hotmail.com</email>
<url>http://comphenix.net/</url>
<roles>
<role>former author</role>
</roles>
<timezone>1</timezone>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.comphenix.executors</groupId>
<artifactId>BukkitExecutors</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>ProtocolLib-API</artifactId>
<name>ProtocolLib-API</name>
<version>${minorVersion}</version>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>http://www.spigotmc.org/resources/protocollib.1997/</url>
<packaging>jar</packaging>
<parent>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib-Parent</artifactId>
<version>v4-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.number></project.build.number>
<project.fullVersion>${project.version}</project.fullVersion>
<spigotVersion>1.12-pre2-SNAPSHOT</spigotVersion>
</properties>
<build>
<defaultGoal>clean install</defaultGoal>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestEntries>
<Main-Class>com.comphenix.protocol.Application</Main-Class>
<Implementation-Title>ProtocolLib</Implementation-Title>
<Implementation-Version>${project.fullVersion}</Implementation-Version>
<Implementation-Vendor>dmulloy2</Implementation-Vendor>
</manifestEntries>
</archive>
<finalName>ProtocolLib</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.10</version>
<configuration>
<systemProperties>
<property>
<name>projectVersion</name>
<value>${project.version}</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>jenkins</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>
</properties>
</profile>
<profile>
<id>release-sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<properties>
<project.fullVersion>${project.version}</project.fullVersion>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- TODO: Look into signing releases
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
-->
</plugins>
</build>
</profile>
</profiles>
<scm>
<connection>scm:git:git://github.com/dmulloy2/ProtocolLib.git</connection>
<developerConnection>scm:git:git@github.com:dmulloy2/ProtocolLib.git</developerConnection>
<url>https://github.com/dmulloy2/ProtocolLib</url>
</scm>
<licenses>
<license>
<name>GNU GENERAL PUBLIC LICENSE - Version 2, June 1991</name>
<url>http://www.gnu.org/licenses/gpl-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>dmulloy2</id>
<name>Dan Mulloy</name>
<url>http://dmulloy2.net/</url>
<roles>
<role>developer</role>
<role>maintainer</role>
</roles>
</developer>
<developer>
<id>aadnk</id>
<name>Kristian S. Stangeland</name>
<email>kr_stang@hotmail.com</email>
<url>http://comphenix.net/</url>
<roles>
<role>former author</role>
</roles>
<timezone>1</timezone>
</developer>
</developers>
</project>
@@ -152,4 +152,4 @@ public interface AsynchronousManager {
* @return Set of every asynchronous packet listener.
*/
public abstract Set<PacketListener> getAsyncHandlers();
}
}
@@ -1,9 +1,14 @@
package com.comphenix.protocol;
import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
@@ -15,7 +20,6 @@ import org.bukkit.Bukkit;
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.reflect.ObjectEnum;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Objects;
@@ -31,12 +35,12 @@ import com.google.common.util.concurrent.Futures;
* Note that vanilla Minecraft reuses packet IDs per protocol (ping, game, login) and IDs are subject to change, so they are not reliable.
* @author Kristian
*/
public class PacketType implements Serializable, Comparable<PacketType> {
public class PacketType implements Serializable, Cloneable, Comparable<PacketType> {
// Increment whenever the type changes
private static final long serialVersionUID = 1L;
/**
* Represents an unknown legacy packet ID.
* Represents an unknown packet ID.
*/
public static final int UNKNOWN_PACKET = -1;
@@ -51,17 +55,15 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Incoming packets.
* @author Kristian
*/
public static class Client extends ObjectEnum<PacketType> {
public static class Client extends PacketTypeEnum {
private final static Sender SENDER = Sender.CLIENT;
/**
* Legacy name: HANDSHAKE.
*/
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 2, "SetProtocol");
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "SetProtocol");
private final static Client INSTANCE = new Client();
// Prevent accidental construction
private Client() { super(PacketType.class); }
private Client() { super(); }
public static Client getInstance() {
return INSTANCE;
@@ -75,10 +77,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* An empty enum, as the server will not send any packets in this protocol.
* @author Kristian
*/
public static class Server extends ObjectEnum<PacketType> {
public static class Server extends PacketTypeEnum {
private final static Sender SENDER = Sender.CLIENT;
private final static Server INSTANCE = new Server();
private Server() { super(PacketType.class); }
private Server() { super(); }
public static Server getInstance() {
return INSTANCE;
@@ -104,101 +106,148 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Outgoing packets.
* @author Kristian
*/
public static class Server extends ObjectEnum<PacketType> {
public static class Server extends PacketTypeEnum {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0, "KeepAlive");
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x01, 1, "Login");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x02, 3, "Chat");
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x03, 4, "UpdateTime");
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x04, 5, "EntityEquipment");
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x05, 6, "SpawnPosition");
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x06, 8, "UpdateHealth");
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x07, 9, "Respawn");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x08, 13, "Position");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16, "HeldItemSlot");
/**
* Note that this was Packets.Server.ENTITY_LOCATION_ACTION.
*/
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x0A, 17, "Bed");
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0B, 18, "Animation");
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x0C, 20, "NamedEntitySpawn");
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x0D, 22, "Collect");
public static final PacketType SPAWN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0E, 23, "SpawnEntity");
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x0F, 24, "SpawnEntityLiving");
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x10, 25, "SpawnEntityPainting");
public static final PacketType SPAWN_ENTITY_EXPERIENCE_ORB =
new PacketType(PROTOCOL, SENDER, 0x11, 26, "SpawnEntityExperienceOrb");
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x12, 28, "EntityVelocity");
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x13, 29, "EntityDestroy");
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x14, 30, "Entity");
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x15, 31, "RelEntityMove");
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x16, 32, "EntityLook");
public static final PacketType ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x17, 33, "RelEntityMoveLook");
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x18, 34, "EntityTeleport");
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x19, 35, "EntityHeadRotation");
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1A, 38, "EntityStatus");
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x1B, 39, "AttachEntity");
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x1C, 40, "EntityMetadata");
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1D, 41, "EntityEffect");
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1E, 42, "RemoveEntityEffect");
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x1F, 43, "Experience");
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x20, 44, "UpdateAttributes");
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x21, 51, "MapChunk");
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x22, 52, "MultiBlockChange");
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x23, 53, "BlockChange");
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x24, 54, "BlockAction");
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x25, 55, "BlockBreakAnimation");
public static final PacketType MAP_CHUNK_BULK = new PacketType(PROTOCOL, SENDER, 0x26, 56, "MapChunkBulk");
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x27, 60, "Explosion");
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x28, 61, "WorldEvent");
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x29, 62, "NamedSoundEffect");
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x2A, 63, "WorldParticles");
/**
* Note that this was Packets.Server.BED.
*/
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x2B, 70, "GameStateChange");
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x2C, 71, "SpawnEntityWeather");
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2D, 100, "OpenWindow");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2E, 101, "CloseWindow");
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x2F, 103, "SetSlot");
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x30, 104, "WindowItems");
/**
* Should be WINDOW_DATA.
*/
public static final PacketType CRAFT_PROGRESS_BAR = new PacketType(PROTOCOL, SENDER, 0x31, 105, "WindowData");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x32, 106, "Transaction");
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x33, 130, "UpdateSign");
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x34, 131, "Map");
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x35, 132, "TileEntityData");
public static final PacketType OPEN_SIGN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x36, 133, "OpenSignEditor");
public static final PacketType STATISTICS = new PacketType(PROTOCOL, SENDER, 0x37, 200, "Statistic");
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x38, 201, "PlayerInfo");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x39, 202, "Abilities");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x3A, 203, "TabComplete");
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x3B, 206, "ScoreboardObjective");
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x3C, 207, "ScoreboardScore");
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE =
new PacketType(PROTOCOL, SENDER, 0x3D, 208, "ScoreboardDisplayObjective");
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x3E, 209, "ScoreboardTeam");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x3F, 250, "CustomPayload");
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x40, 255, "KickDisconnect");
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x41, -1, "ServerDifficulty");
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 0x42, -1, "CombatEvent");
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x43, -1, "Camera");
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 0x44, -1, "WorldBorder");
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x45, -1, "Title");
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x46, -1, "SetCompression");
public static final PacketType PLAYER_LIST_HEADER_FOOTER =
new PacketType(PROTOCOL, SENDER, 0x47, -1, "PlayerListHeaderFooter");
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x48, -1, "ResourcePackSend");
public static final PacketType UPDATE_ENTITY_NBT = new PacketType(PROTOCOL, SENDER, 0x49, -1, "UpdateEntityNBT");
public static final PacketType SPAWN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x00, 0x0E, "SpawnEntity");
public static final PacketType SPAWN_ENTITY_EXPERIENCE_ORB = new PacketType(PROTOCOL, SENDER, 0x01, 0x11, "SpawnEntityExperienceOrb");
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x02, 0x2C, "SpawnEntityWeather");
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x03, 0x0F, "SpawnEntityLiving");
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x04, 0x10, "SpawnEntityPainting");
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x05, 0x0C, "NamedEntitySpawn");
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x06, 0x0B, "Animation");
public static final PacketType STATISTIC = new PacketType(PROTOCOL, SENDER, 0x07, 0x37, "Statistic");
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x08, 0x25, "BlockBreakAnimation");
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x09, 0x35, "TileEntityData");
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x0A, 0x24, "BlockAction");
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x0B, 0x23, "BlockChange");
public static final PacketType BOSS = new PacketType(PROTOCOL, SENDER, 0x0C, 0xFF, "Boss");
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x0D, 0x41, "ServerDifficulty");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x0E, 0x3A, "TabComplete");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x0F, 0x02, "Chat");
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x10, 0x22, "MultiBlockChange");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x11, 0x32, "Transaction");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x12, 0x2E, "CloseWindow");
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x13, 0x2D, "OpenWindow");
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x14, 0x30, "WindowItems");
public static final PacketType WINDOW_DATA = new PacketType(PROTOCOL, SENDER, 0x15, 0x31, "WindowData");
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x16, 0x2F, "SetSlot");
public static final PacketType SET_COOLDOWN = new PacketType(PROTOCOL, SENDER, 0x17, 0xFC, "SetCooldown");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x18, 0x3F, "CustomPayload");
public static final PacketType CUSTOM_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x19, 0xFD, "CustomSoundEffect");
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x1A, 0x40, "KickDisconnect");
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1B, 0x1A, "EntityStatus");
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x1C, 0x27, "Explosion");
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x1D, 0xFA, "UnloadChunk");
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x1E, 0x2B, "GameStateChange");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x1F, 0x00, "KeepAlive");
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x20, 0x21, "MapChunk");
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x21, 0x28, "WorldEvent");
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x22, 0x2A, "WorldParticles");
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x23, 0x01, "Login");
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x24, 0x34, "Map");
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x25, 0x14, "Entity");
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x26, 0x15, "RelEntityMove");
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x27, 0x17, "RelEntityMoveLook");
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x28, 0x16, "EntityLook");
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x29, 0xFE, "VehicleMove");
public static final PacketType OPEN_SIGN_EDITOR = new PacketType(PROTOCOL, SENDER, 0x2A, 0x36, "OpenSignEditor");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x2B, 0x39, "Abilities");
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 0x2C, 0x42, "CombatEvent");
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x2D, 0x38, "PlayerInfo");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x2E, 0x08, "Position");
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x2F, 0x0A, "Bed");
public static final PacketType RECIPES = new PacketType(PROTOCOL, SENDER, 0x30, -1, "Recipes");
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x31, 0x13, "EntityDestroy");
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x32, 0x1E, "RemoveEntityEffect");
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x33, 0x48, "ResourcePackSend");
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x34, 0x07, "Respawn");
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x35, 0x19, "EntityHeadRotation");
public static final PacketType SELECT_ADVANCEMENT_TAB = new PacketType(PROTOCOL, SENDER, 0x36, -1, "SelectAdvancementTab");
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 0x37, 0x44, "WorldBorder");
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x38, 0x43, "Camera");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x39, 0x09, "HeldItemSlot");
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x3A, 0x3D, "ScoreboardDisplayObjective");
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x3B, 0x1C, "EntityMetadata");
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x3C, 0x1B, "AttachEntity");
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x3D, 0x12, "EntityVelocity");
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x3E, 0x04, "EntityEquipment");
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x3F, 0x1F, "Experience");
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x40, 0x06, "UpdateHealth");
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x41, 0x3B, "ScoreboardObjective");
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x42, 0xFB, "Mount");
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x43, 0x3E, "ScoreboardTeam");
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x44, 0x3C, "ScoreboardScore");
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x45, 0x05, "SpawnPosition");
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x46, 0x03, "UpdateTime");
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x47, 0x45, "Title");
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x48, 0x29, "NamedSoundEffect");
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x49, 0x47, "PlayerListHeaderFooter");
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x4A, 0x0D, "Collect");
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x4B, 0x18, "EntityTeleport");
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x4C, -1, "Advancements");
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x4D, 0x20, "UpdateAttributes");
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x4E, 0x1D, "EntityEffect");
// ---- Removed in 1.9
/**
* @deprecated Removed in 1.9
*/
@Deprecated
public static final PacketType MAP_CHUNK_BULK = new PacketType(PROTOCOL, SENDER, 255, 255, "MapChunkBulk");
/**
* @deprecated Removed in 1.9
*/
@Deprecated
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 254, 254, "SetCompression");
/**
* @deprecated Removed in 1.9
*/
@Deprecated
public static final PacketType UPDATE_ENTITY_NBT = new PacketType(PROTOCOL, SENDER, 253, 253, "UpdateEntityNBT");
// ----- Renamed packets
/**
* @deprecated Renamed to {@link #WINDOW_DATA}
*/
@Deprecated
public static final PacketType CRAFT_PROGRESS_BAR = WINDOW_DATA.clone();
/**
* @deprecated Renamed to {@link #REL_ENTITY_MOVE_LOOK}
*/
@Deprecated
public static final PacketType ENTITY_MOVE_LOOK = REL_ENTITY_MOVE_LOOK.clone();
/**
* @deprecated Renamed to {@link #STATISTIC}
*/
@Deprecated
public static final PacketType STATISTICS = STATISTIC.clone();
/**
* @deprecated Renamed to {@link #OPEN_SIGN_EDITOR}
*/
@Deprecated
public static final PacketType OPEN_SIGN_ENTITY = OPEN_SIGN_EDITOR.clone();
// ----- Replaced in 1.9.4
/**
* @deprecated Replaced by {@link #TILE_ENTITY_DATA}
*/
@Deprecated
public static final PacketType UPDATE_SIGN = MinecraftReflection.signUpdateExists() ? new PacketType(PROTOCOL, SENDER, 252, 252, "UpdateSign") :
TILE_ENTITY_DATA.clone();
// The instance must
private final static Server INSTANCE = new Server();
// Prevent accidental construction
private Server() { super(PacketType.class); }
private Server() { super(); }
public static Sender getSender() {
return SENDER;
@@ -212,40 +261,47 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Incoming packets.
* @author Kristian
*/
public static class Client extends ObjectEnum<PacketType> {
public static class Client extends PacketTypeEnum {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0, "KeepAlive");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x01, 3, "Chat");
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x02, 7, "UseEntity");
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x03, 10, "Flying");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x04, 11, "Position");
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x05, 12, "Look");
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x06, 13, "PositionLook");
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x07, 14, "BlockDig");
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x08, 15, "BlockPlace");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16, "HeldItemSlot");
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0A, 18, "ArmAnimation");
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x0B, 19, "EntityAction");
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x0C, 27, "SteerVehicle");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x0D, 101, "CloseWindow");
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x0E, 102, "WindowClick");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x0F, 106, "Transaction");
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x10, 107, "SetCreativeSlot");
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x11, 108, "EnchantItem");
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x12, 130, "UpdateSign");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x13, 202, "Abilities");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x14, 203, "TabComplete");
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x15, 204, "Settings");
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x16, 205, "ClientCommand");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x17, 250, "CustomPayload");
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x18, -1, "Spectate");
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x19, -1, "ResourcePackStatus");
public static final PacketType TELEPORT_ACCEPT = new PacketType(PROTOCOL, SENDER, 0x00, 0xF9, "TeleportAccept");
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x01, -1, "AutoRecipe");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x02, 0x14, "TabComplete");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x03, 0x01, "Chat");
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x04, 0x16, "ClientCommand");
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x05, 0x15, "Settings");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x06, 0x0F, "Transaction");
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x07, 0x11, "EnchantItem");
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x08, 0x0E, "WindowClick");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x09, 0x0D, "CloseWindow");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x0A, 0x17, "CustomPayload");
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0B, 0x02, "UseEntity");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x0C, 0x00, "KeepAlive");
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x0D, 0x03, "Flying");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x0E, 0x04, "Position");
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x0F, 0x06, "PositionLook");
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x10, 0x05, "Look");
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x11, 0xF8, "VehicleMove");
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x12, 0xF7, "BoatMove");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x13, 0x13, "Abilities");
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x14, 0x07, "BlockDig");
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x15, 0x0B, "EntityAction");
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x16, 0x0C, "SteerVehicle");
public static final PacketType RECIPE_DISPLAYED = new PacketType(PROTOCOL, SENDER, 0x17, -1, "RecipeDisplayed");
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x18, 0x19, "ResourcePackStatus");
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x19, -1, "Advancements");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x1A, 0x09, "HeldItemSlot");
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x1B, 0x10, "SetCreativeSlot");
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x1C, 0x12, "UpdateSign");
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x1D, 0x0A, "ArmAnimation");
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x1E, 0x18, "Spectate");
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x1F, 0xF6, "UseItem");
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x20, 0x08, "BlockPlace");
private final static Client INSTANCE = new Client();
// Prevent accidental construction
private Client() { super(PacketType.class); }
private Client() { super(); }
public static Sender getSender() {
return SENDER;
@@ -271,16 +327,24 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Outgoing packets.
* @author Kristian
*/
public static class Server extends ObjectEnum<PacketType> {
public static class Server extends PacketTypeEnum {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType OUT_SERVER_INFO = new PacketType(PROTOCOL, SENDER, 0x00, 255, "ServerInfo").forceAsync(true);
public static final PacketType OUT_PING = new PacketType(PROTOCOL, SENDER, 0x01, 230, "Pong");
@ForceAsync
public static final PacketType SERVER_INFO = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "ServerInfo");
public static final PacketType PONG = new PacketType(PROTOCOL, SENDER, 0x01, 0x01, "Pong");
/**
* @deprecated Renamed to {@link #SERVER_INFO}
*/
@Deprecated
@ForceAsync
public static final PacketType OUT_SERVER_INFO = SERVER_INFO.clone();
private final static Server INSTANCE = new Server();
// Prevent accidental construction
private Server() { super(PacketType.class); }
private Server() { super(); }
public static Sender getSender() {
return SENDER;
@@ -294,16 +358,16 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Incoming packets.
* @author Kristian
*/
public static class Client extends ObjectEnum<PacketType> {
public static class Client extends PacketTypeEnum {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType IN_START = new PacketType(PROTOCOL, SENDER, 0x00, 254, "Start");
public static final PacketType IN_PING = new PacketType(PROTOCOL, SENDER, 0x01, 230, "Ping");
public static final PacketType START = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "Start");
public static final PacketType PING = new PacketType(PROTOCOL, SENDER, 0x01, 0x01, "Ping");
private final static Client INSTANCE = new Client();
// Prevent accidental construction
private Client() { super(PacketType.class); }
private Client() { super(); }
public static Sender getSender() {
return SENDER;
@@ -329,18 +393,18 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Outgoing packets.
* @author Kristian
*/
public static class Server extends ObjectEnum<PacketType> {
public static class Server extends PacketTypeEnum {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x00, 255, "Disconnect");
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 253, "EncryptionBegin");
public static final PacketType SUCCESS = new PacketType(PROTOCOL, SENDER, 0x02, 232, "Success");
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x03, -1, "SetCompression");
public static final PacketType DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "Disconnect");
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 0x01, "EncryptionBegin");
public static final PacketType SUCCESS = new PacketType(PROTOCOL, SENDER, 0x02, 0x02, "Success");
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x03, 0x03, "SetCompression");
private final static Server INSTANCE = new Server();
// Prevent accidental construction
private Server() { super(PacketType.class); }
private Server() { super(); }
public static Sender getSender() {
return SENDER;
@@ -354,16 +418,16 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Incoming packets.
* @author Kristian
*/
public static class Client extends ObjectEnum<PacketType> {
public static class Client extends PacketTypeEnum {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType START = new PacketType(PROTOCOL, SENDER, 0x00, 231, "Start");
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 252, "EncryptionBegin");
public static final PacketType START = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "Start");
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 0x01, "EncryptionBegin");
private final static Client INSTANCE = new Client();
// Prevent accidental construction
private Client() { super(PacketType.class); }
private Client() { super(); }
public static Sender getSender() {
return SENDER;
@@ -390,7 +454,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @author Kristian
*/
// Missing server packets: [10, 11, 12, 21, 107, 252]
public static class Server extends ObjectEnum<PacketType> {
public static class Server extends PacketTypeEnum {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType PLAYER_FLYING = PacketType.newLegacy(SENDER, 10);
@@ -414,7 +478,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
// Prevent accidental construction
private Server() {
super(PacketType.class);
super();
}
public static Sender getSender() {
@@ -430,7 +494,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @author Kristian
*/
// Missing client packets: [1, 9, 255]
public static class Client extends ObjectEnum<PacketType> {
public static class Client extends PacketTypeEnum {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType LOGIN = PacketType.newLegacy(SENDER, 1);
@@ -440,7 +504,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
private final static Client INSTANCE = new Client();
// Prevent accidental construction
private Client() { super(PacketType.class); }
private Client() { super(); }
public static Sender getSender() {
return SENDER;
@@ -490,7 +554,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
}
public String getPacketName() {
return WordUtils.capitalize(name().toLowerCase());
return WordUtils.capitalize(name().toLowerCase(Locale.ENGLISH));
}
}
@@ -523,13 +587,20 @@ public class PacketType implements Serializable, Comparable<PacketType> {
}
}
/**
* Whether or not packets of this type must be handled asynchronously.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ForceAsync { }
// Lookup of packet types
private static PacketTypeLookup LOOKUP;
/**
* Protocol version of all the current IDs.
*/
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.BOUNTIFUL_UPDATE;
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.EXPLORATION_UPDATE;
private final Protocol protocol;
private final Sender sender;
@@ -538,7 +609,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
private final MinecraftVersion version;
private final String[] classNames;
private String name;
private boolean deprecated;
private boolean forceAsync;
private boolean dynamic;
/**
@@ -590,7 +664,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param packetId - the legacy packet ID.
* @return The corresponding packet type.
* @throws IllegalArgumentException If the legacy packet could not be found.
* @deprecated Legacy IDs haven't functioned properly for some time
*/
@Deprecated
public static PacketType findLegacy(int packetId) {
PacketType type = getLookup().getFromLegacy(packetId);
@@ -605,7 +681,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param preference - the preferred sender, or NULL for any arbitrary sender.
* @return The corresponding packet type.
* @throws IllegalArgumentException If the legacy packet could not be found.
* @deprecated Legacy IDs haven't functioned properly for some time
*/
@Deprecated
public static PacketType findLegacy(int packetId, Sender preference) {
if (preference == null)
return findLegacy(packetId);
@@ -620,7 +698,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* Determine if the given legacy packet exists.
* @param packetId - the legacy packet ID.
* @return TRUE if it does, FALSE otherwise.
* @deprecated Legacy IDs haven't functioned properly for some time
*/
@Deprecated
public static boolean hasLegacy(int packetId) {
return getLookup().getFromLegacy(packetId) != null;
}
@@ -628,18 +708,19 @@ public class PacketType implements Serializable, Comparable<PacketType> {
/**
* Retrieve a packet type from a protocol, sender and packet ID.
* <p>
* It is usually better to access the packet types statically, like so:
* It is almost always better to access the packet types statically, like so:
* <ul>
* <li>{@link PacketType.Play.Server#SPAWN_ENTITY}
* </ul>
* However there are some valid uses for packet IDs. Please note that IDs
* change almost every Minecraft version.
*
* @param protocol - the current protocol.
* @param sender - the sender.
* @param packetId - the packet ID.
* @return The corresponding packet type.
* @throws IllegalArgumentException If the current packet could not be found.
* @deprecated IDs are no longer reliable
*/
@Deprecated
public static PacketType findCurrent(Protocol protocol, Sender sender, int packetId) {
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
@@ -665,7 +746,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
if (name.contains("Packet"))
return name;
return String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), name);
return String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), WordUtils.capitalize(name));
}
/**
@@ -674,9 +755,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param sender - the sender.
* @param packetId - the packet ID.
* @return TRUE if it exists, FALSE otherwise.
* @deprecated IDs are no longer reliable
*/
@Deprecated
public static boolean hasCurrent(Protocol protocol, Sender sender, int packetId) {
return getLookup().getFromCurrent(protocol, sender, packetId) != null;
}
@@ -689,7 +768,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param sender - the sender of the packet, or NULL if unknown.
* @return The packet type.
* @throws IllegalArgumentException If the sender is NULL and the packet doesn't exist.
* @deprecated Legacy IDs haven't functioned properly for some time
*/
@Deprecated
public static PacketType fromLegacy(int id, Sender sender) {
PacketType type = getLookup().getFromLegacy(id, sender);
@@ -743,24 +824,11 @@ public class PacketType implements Serializable, Comparable<PacketType> {
Map<String, PacketType> map = lookup.getMap(protocol, sender);
// Check the map first
String className = packetClass.getSimpleName();
PacketType type = map.get(className);
String clazz = packetClass.getSimpleName();
PacketType type = find(map, clazz);
if (type == null) {
// Then check any aliases
for (PacketType check : map.values()) {
String[] aliases = check.getClassNames();
if (aliases.length > 1) {
for (String alias : aliases) {
if (alias.equals(className)) {
// We have a match!
type = check;
}
}
}
}
// Guess we don't support this packet :/
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, className);
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, clazz);
type.dynamic = true;
// Many may be scheduled, but only the first will be executed
@@ -770,6 +838,28 @@ public class PacketType implements Serializable, Comparable<PacketType> {
return type;
}
private static PacketType find(Map<String, PacketType> map, String clazz) {
PacketType ret = map.get(clazz);
if (ret != null) {
return ret;
}
// Check any aliases
for (PacketType check : map.values()) {
String[] aliases = check.getClassNames();
if (aliases.length > 1) {
for (String alias : aliases) {
if (alias.equals(clazz)) {
// We have a match!
return check;
}
}
}
}
return null;
}
/**
* Lookup a packet type from a packet class.
* @param packetClass - the packet class.
@@ -815,7 +905,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
Callable<Boolean> callable = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
ObjectEnum<PacketType> objEnum;
PacketTypeEnum objEnum;
// A bit ugly, but performance is critical
objEnum = getObjectEnum(type);
@@ -829,7 +919,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
};
// Execute in the main thread if possible
if (Bukkit.getServer() == null || Application.isPrimaryThread()) {
if (Bukkit.getServer() == null || Bukkit.isPrimaryThread()) {
try {
return Futures.immediateFuture(callable.call());
} catch (Exception e) {
@@ -844,7 +934,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param type - the packet type.
* @return The corresponding object enum.
*/
public static ObjectEnum<PacketType> getObjectEnum(final PacketType type) {
public static PacketTypeEnum getObjectEnum(final PacketType type) {
switch (type.getProtocol()) {
case HANDSHAKING:
return type.isClient() ? Handshake.Client.getInstance() : Handshake.Server.getInstance();
@@ -948,11 +1038,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* <p>
* This is only unique within a specific protocol and target.
* <p>
* It is only unknown if the packet was removed in Minecraft 1.7.2.
* It is unknown if the packet was removed at any point.
* @return The current ID, or {@link #UNKNOWN_PACKET} if unknown.
* @deprecated IDs are subject to change
*/
@Deprecated
public int getCurrentId() {
return currentId;
}
@@ -973,12 +1061,47 @@ public class PacketType implements Serializable, Comparable<PacketType> {
}
}
// Only used by Enum processor
void setName(String name) {
this.name = name;
}
/**
* Retrieve the declared enum name of this packet type.
* @return The enum name.
*/
public String name() {
return getObjectEnum(this).getDeclaredName(this);
return name;
}
// Only used by enum processor
void setDeprecated() {
this.deprecated = true;
}
/**
* Whether or not this packet is deprecated. Deprecated packet types have either been renamed, replaced, or removed.
* Kind of like the thing they use to tell children to recycle except with packets you probably shouldn't be using.
*
* @return True if the type is deprecated, false if not
*/
public boolean isDeprecated() {
return deprecated;
}
// Only used by enum processor
void forceAsync() {
this.forceAsync = true;
}
/**
* Whether or not the processing of this packet must take place on a thread different than the main thread. You don't
* get a choice. If this is false it's up to you.
*
* @return True if async processing is forced, false if not.
*/
public boolean isAsyncForced() {
return forceAsync;
}
/**
@@ -994,7 +1117,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* <p>
* This ID is globally unique.
* @return The legacy ID, or {@link #UNKNOWN_PACKET} if unknown.
* @deprecated Legacy IDs haven't functioned properly for some time
*/
@Deprecated
public int getLegacyId() {
return legacyId;
}
@@ -1007,22 +1132,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
return dynamic;
}
private PacketType forceAsync(boolean forceAsync) {
this.forceAsync = forceAsync;
return this;
}
/**
* Whether or not this packet must be processed asynchronously.
* @return True if it must be, false if not.
*/
public boolean forceAsync() {
return forceAsync;
}
@Override
public int hashCode() {
return Objects.hashCode(protocol, sender, currentId, legacyId);
return Objects.hashCode(protocol, sender, currentId);
}
@Override
@@ -1034,8 +1146,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
PacketType other = (PacketType) obj;
return protocol == other.protocol &&
sender == other.sender &&
currentId == other.currentId &&
legacyId == other.legacyId;
currentId == other.currentId;
}
return false;
}
@@ -1046,7 +1157,6 @@ public class PacketType implements Serializable, Comparable<PacketType> {
compare(protocol, other.getProtocol()).
compare(sender, other.getSender()).
compare(currentId, other.getCurrentId()).
compare(legacyId, other.getLegacyId()).
result();
}
@@ -1055,8 +1165,17 @@ public class PacketType implements Serializable, Comparable<PacketType> {
Class<?> clazz = getPacketClass();
if (clazz == null)
return "UNREGISTERED[" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + ", classNames: " + Arrays.toString(classNames) + "]";
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", classNames: " + Arrays.toString(classNames) + " (unregistered)]";
else
return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]";
return name() + "[class=" + clazz.getSimpleName() + ", id=" + currentId + "]";
}
}
@Override
public PacketType clone() {
try {
return (PacketType) super.clone();
} catch (CloneNotSupportedException ex) {
throw new Error("This shouldn't happen", ex);
}
}
}
@@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.comphenix.protocol.reflect;
package com.comphenix.protocol;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -23,8 +23,10 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
/**
* Represents a more modern object-based enum.
@@ -33,41 +35,53 @@ import com.google.common.collect.HashBiMap;
* want to prevent the creation of additional members dynamically.
* @author Kristian
*/
public class ObjectEnum<T> implements Iterable<T> {
public class PacketTypeEnum implements Iterable<PacketType> {
// Used to convert between IDs and names
protected BiMap<T, String> members = HashBiMap.create();
protected Set<PacketType> members = Sets.newHashSet();
/**
* Registers every declared integer field.
* @param fieldType Field type
* Registers every declared PacketType field.
*/
public ObjectEnum(Class<T> fieldType) {
registerAll(fieldType);
public PacketTypeEnum() {
registerAll();
}
/**
* Registers every public assignable static field as a member.
* @param fieldType Field type
*/
@SuppressWarnings("unchecked")
protected void registerAll(Class<T> fieldType) {
protected void registerAll() {
try {
// Register every int field
// Register every non-deprecated field
for (Field entry : this.getClass().getFields()) {
if (Modifier.isStatic(entry.getModifiers()) && fieldType.isAssignableFrom(entry.getType())) {
T value = (T) entry.get(null);
if (value == null)
throw new IllegalArgumentException("Field " + entry + " was NULL. Remember to " +
"construct the object after the field has been declared.");
registerMember(value, entry.getName());
if (Modifier.isStatic(entry.getModifiers()) && PacketType.class.isAssignableFrom(entry.getType())) {
PacketType value = (PacketType) entry.get(null);
if (value == null) {
throw new IllegalArgumentException("Field " + entry.getName() + " was null!");
}
value.setName(entry.getName());
if (entry.getAnnotation(PacketType.ForceAsync.class) != null) {
value.forceAsync();
}
boolean deprecated = entry.getAnnotation(Deprecated.class) != null;
if (deprecated) value.setDeprecated();
if (members.contains(value)) {
// Replace potentially deprecated packet types with non-deprecated ones
if (!deprecated) {
members.remove(value);
members.add(value);
}
} else {
members.add(value);
}
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@@ -77,11 +91,14 @@ public class ObjectEnum<T> implements Iterable<T> {
* @param name - name of member.
* @return TRUE if the member was registered, FALSE otherwise.
*/
public boolean registerMember(T instance, String name) {
if (!members.containsKey(instance)) {
members.put(instance, name);
public boolean registerMember(PacketType instance, String name) {
instance.setName(name);
if (!members.contains(instance)) {
members.add(instance);
return true;
}
return false;
}
@@ -90,38 +107,36 @@ public class ObjectEnum<T> implements Iterable<T> {
* @param member - the member to check.
* @return TRUE if the given member has been registered, FALSE otherwise.
*/
public boolean hasMember(T member) {
return members.containsKey(member);
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
*/
public T valueOf(String name) {
return members.inverse().get(name);
@Deprecated
public PacketType valueOf(String name) {
for (PacketType member : members) {
if (member.name().equals(name))
return member;
}
return null;
}
/**
* Retrieve the name of the given member.
* @param member - the member to retrieve.
* @return Declared name of the member, or NULL if not found.
*/
public String getDeclaredName(T member) {
return members.get(member);
}
/**
* Retrieve every registered member.
* @return Enumeration of every value.
*/
public Set<T> values() {
return new HashSet<T>(members.keySet());
public Set<PacketType> values() {
return new HashSet<>(members);
}
@Override
public Iterator<T> iterator() {
return members.keySet().iterator();
public Iterator<PacketType> iterator() {
return members.iterator();
}
}
@@ -17,10 +17,6 @@
package com.comphenix.protocol;
import java.util.Set;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.IntEnum;
/**
@@ -165,30 +161,7 @@ public final class Packets {
public static Server getRegistry() {
return INSTANCE;
}
/**
* Determine if the given packet is a valid server packet in the current version of Minecraft.
* <p>
* Use {@link PacketType#isSupported()} instead.
* @param packetID - the packet to test.
* @return TRUE if this packet is supported, FALSE otherwise.
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
*/
@Deprecated
public static boolean isSupported(int packetID) throws FieldAccessException {
return PacketFilterManager.getServerPackets().contains(packetID);
}
/**
* Retrieve every client packet the current version of Minecraft is aware of.
* @return Every supported server packet.
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
*/
@Deprecated
public static Set<Integer> getSupported() throws FieldAccessException {
return PacketFilterManager.getServerPackets();
}
// We only allow a single instance of this class
private Server() {
super();
@@ -262,26 +235,7 @@ public final class Packets {
public static Client getRegistry() {
return INSTANCE;
}
/**
* Determine if the given packet is a valid client packet in the current version of Minecraft.
* @param packetID - the packet to test.
* @return TRUE if this packet is supported, FALSE otherwise.
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
*/
public static boolean isSupported(int packetID) throws FieldAccessException {
return PacketFilterManager.getClientPackets().contains(packetID);
}
/**
* Retrieve every client packet the current version of Minecraft is aware of.
* @return Every supported client packet.
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
*/
public static Set<Integer> getSupported() throws FieldAccessException {
return PacketFilterManager.getClientPackets();
}
// Like above
private Client() {
super();
@@ -20,12 +20,13 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.PlayerInjectHooks;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -157,6 +158,9 @@ public class ProtocolConfig {
}
if (global != null) {
updater = global.getConfigurationSection(SECTION_AUTOUPDATER);
if (updater.getValues(true).isEmpty()) {
plugin.getLogger().warning("Updater section is missing, regenerate your config!");
}
}
// Automatically copy defaults
@@ -256,7 +260,7 @@ public class ProtocolConfig {
* @return TRUE if it should, FALSE otherwise.
*/
public boolean isAutoDownload() {
return updater != null && getUpdaterValue(UPDATER_DOWNLAD, true);
return updater != null && getUpdaterValue(UPDATER_DOWNLAD, false);
}
/**
@@ -461,7 +465,7 @@ public class ProtocolConfig {
PlayerInjectHooks hook = getDefaultMethod();
if (text != null)
hook = PlayerInjectHooks.valueOf(text.toUpperCase().replace(" ", "_"));
hook = PlayerInjectHooks.valueOf(text.toUpperCase(Locale.ENGLISH).replace(" ", "_"));
return hook;
}
@@ -497,4 +501,4 @@ public class ProtocolConfig {
valuesChanged = false;
configChanged = false;
}
}
}
@@ -0,0 +1,143 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2016 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;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.BasicErrorReporter;
import com.comphenix.protocol.error.ErrorReporter;
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
/**
* The main entry point for ProtocolLib.
* @author dmulloy2
*/
public class ProtocolLibrary {
/**
* The minimum version ProtocolLib has been tested with.
*/
public static final String MINIMUM_MINECRAFT_VERSION = "1.8";
/**
* The maximum version ProtocolLib has been tested with.
*/
public static final String MAXIMUM_MINECRAFT_VERSION = "1.12";
/**
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.12) was released.
*/
public static final String MINECRAFT_LAST_RELEASE_DATE = "2017-06-07";
/**
* Plugins that are currently incompatible with ProtocolLib.
*/
public static final List<String> INCOMPATIBLE = Arrays.asList("TagAPI");
private static Plugin plugin;
private static ProtocolConfig config;
private static ProtocolManager manager;
private static ErrorReporter reporter = new BasicErrorReporter();
private static ListeningScheduledExecutorService executorAsync;
private static ListeningScheduledExecutorService executorSync;
private static boolean updatesDisabled;
private static boolean initialized;
protected static void init(Plugin plugin, ProtocolConfig config, ProtocolManager manager, ErrorReporter reporter,
ListeningScheduledExecutorService executorAsync, ListeningScheduledExecutorService executorSync) {
Validate.isTrue(!initialized, "ProtocolLib has already been initialized.");
ProtocolLibrary.plugin = plugin;
ProtocolLibrary.config = config;
ProtocolLibrary.manager = manager;
ProtocolLibrary.reporter = reporter;
ProtocolLibrary.executorAsync = executorAsync;
ProtocolLibrary.executorSync = executorSync;
initialized = true;
}
/**
* Gets the ProtocolLib plugin instance.
* @return The plugin instance
*/
public static Plugin getPlugin() {
return plugin;
}
/**
* Gets ProtocolLib's configuration
* @return The config
*/
public static ProtocolConfig getConfig() {
return config;
}
/**
* Retrieves the packet protocol manager.
* @return Packet protocol manager
*/
public static ProtocolManager getProtocolManager() {
return manager;
}
/**
* Retrieve the current error reporter.
* @return Current error reporter.
*/
public static ErrorReporter getErrorReporter() {
return reporter;
}
/**
* Retrieve an executor service for performing asynchronous tasks on the behalf of ProtocolLib.
* <p>
* Note that this service is NULL if ProtocolLib has not been initialized yet.
* @return The executor service, or NULL.
*/
public static ListeningScheduledExecutorService getExecutorAsync() {
return executorAsync;
}
/**
* Retrieve an executor service for performing synchronous tasks (main thread) on the behalf of ProtocolLib.
* <p>
* Note that this service is NULL if ProtocolLib has not been initialized yet.
* @return The executor service, or NULL.
*/
public static ListeningScheduledExecutorService getExecutorSync() {
return executorSync;
}
/**
* Disables the ProtocolLib update checker.
*/
public static void disableUpdates() {
updatesDisabled = true;
}
/**
* Whether or not updates are currently disabled.
* @return True if it is, false if not
*/
public static boolean updatesDisabled() {
return updatesDisabled;
}
}
@@ -0,0 +1,82 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2016 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;
import java.text.MessageFormat;
import java.util.logging.Level;
import org.bukkit.plugin.Plugin;
/**
* @author dmulloy2
*/
public class ProtocolLogger {
private static Plugin plugin;
protected static void init(Plugin plugin) {
ProtocolLogger.plugin = plugin;
}
private static boolean isDebugEnabled() {
try {
return plugin.getConfig().getBoolean("global.debug", false);
} catch (Throwable ex) { // Maybe we're testing or something
return false;
}
}
/**
* Logs a message to console with a given level.
* @param level Logging level
* @param message Message to log
* @param args Arguments to format in
*/
public static void log(Level level, String message, Object... args) {
plugin.getLogger().log(level, MessageFormat.format(message, args));
}
/**
* Logs a method to console with the INFO level.
* @param message Message to log
* @param args Arguments to format in
*/
public static void log(String message, Object... args) {
log(Level.INFO, message, args);
}
/**
* Logs a message to console with a given level and exception.
* @param level Logging level
* @param message Message to log
* @param ex Exception to log
*/
public static void log(Level level, String message, Throwable ex) {
plugin.getLogger().log(level, message, ex);
}
public static void debug(String message, Object... args) {
if (isDebugEnabled()) {
log("[Debug] " + message, args);
}
}
public static void debug(String message, Throwable ex) {
if (isDebugEnabled()) {
plugin.getLogger().log(Level.WARNING, "[Debug] " + message, ex);
}
}
}
@@ -29,6 +29,7 @@ import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.PacketConstructor;
@@ -279,4 +280,6 @@ public interface ProtocolManager extends PacketStream {
* @return Asynchronous packet manager.
*/
public AsynchronousManager getAsynchronousManager();
}
public void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist);
}
@@ -35,7 +35,6 @@ import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.injector.PrioritizedListener;
import com.comphenix.protocol.injector.SortedPacketListenerList;
import com.comphenix.protocol.injector.packet.PacketRegistry;
@@ -181,11 +180,11 @@ public class AsyncFilterManager implements AsynchronousManager {
// Add listener to either or both processing queue
if (hasValidWhitelist(sendingWhitelist)) {
PacketFilterManager.verifyWhitelist(listener, sendingWhitelist);
manager.verifyWhitelist(listener, sendingWhitelist);
serverProcessingQueue.addListener(handler, sendingWhitelist);
}
if (hasValidWhitelist(receivingWhitelist)) {
PacketFilterManager.verifyWhitelist(listener, receivingWhitelist);
manager.verifyWhitelist(listener, receivingWhitelist);
clientProcessingQueue.addListener(handler, receivingWhitelist);
}
@@ -24,8 +24,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
@@ -36,10 +34,11 @@ import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.timing.TimedListenerManager;
import com.comphenix.protocol.timing.TimedListenerManager.ListenerType;
import com.comphenix.protocol.timing.TimedTracker;
import com.comphenix.protocol.utility.WrappedScheduler;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import org.bukkit.plugin.Plugin;
/**
* Represents a handler for an asynchronous event.
* <p>
@@ -345,8 +344,7 @@ public class AsyncListenerHandler {
}
private void scheduleAsync(Runnable runnable) {
// Handle deprecation
WrappedScheduler.runAsynchronouslyRepeat(listener.getPlugin(), filterManager.getScheduler(), runnable, 0L, -1L);
listener.getPlugin().getServer().getScheduler().runTaskAsynchronously(listener.getPlugin(), runnable);
}
/**
@@ -28,7 +28,7 @@ import java.util.logging.Level;
import com.comphenix.protocol.PacketStream;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PrioritizedListener;
@@ -429,15 +429,17 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
// Incoming chat packets are async only if they aren't commands
return ! content.startsWith("/");
} else {
ProtocolLibrary.log(Level.WARNING, "Failed to determine contents of incoming chat packet!");
ProtocolLogger.log(Level.WARNING, "Failed to determine contents of incoming chat packet!");
alwaysSync = true;
}
} else if (event.getPacketType() == PacketType.Status.Server.SERVER_INFO) {
return true;
} else {
// TODO: Find more cases of async packets
return false;
}
} else {
ProtocolLibrary.log(Level.INFO, "Could not determine asynchronous state of packets (this can probably be ignored)");
ProtocolLogger.log(Level.INFO, "Could not determine asynchronous state of packets (this can probably be ignored)");
alwaysSync = true;
}
}
@@ -243,4 +243,4 @@ public class ExpireHashMap<K, V> {
return valueView.toString();
}
}
@@ -23,7 +23,6 @@ import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import com.comphenix.protocol.compat.guava.Guava;
import com.google.common.base.Objects;
import com.google.common.collect.Range;
@@ -68,7 +67,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
@Override
public Range<TKey> getKey() {
return Guava.closedRange(left.key, right.key);
return Range.closed(left.key, right.key);
}
@Override
@@ -35,7 +35,7 @@ import org.apache.commons.lang.builder.ToStringStyle;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.collections.ExpireHashMap;
import com.comphenix.protocol.error.Report.ReportBuilder;
import com.comphenix.protocol.events.PacketAdapter;
@@ -464,13 +464,15 @@ public class DetailedErrorReporter implements ErrorReporter {
} else {
try {
if (!apacheCommonsMissing)
return (ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null));
return ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null);
} catch (LinkageError ex) {
// Apache is probably missing
apacheCommonsMissing = true;
} catch (Exception e) {
} catch (ThreadDeath | OutOfMemoryError e) {
throw e;
} catch (Throwable ex) {
// Don't use the error logger to log errors in error logging (that could lead to infinite loops)
ProtocolLibrary.log(Level.WARNING, "Cannot convert to a String with Apache: " + e.getMessage());
ProtocolLogger.log(Level.WARNING, "Cannot convert to a String with Apache: " + ex.getMessage());
}
// Use our custom object printer instead
@@ -87,4 +87,4 @@ public interface ErrorReporter {
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportDetailed(Object sender, ReportBuilder reportBuilder);
}
}
@@ -2,6 +2,7 @@ package com.comphenix.protocol.events;
import com.comphenix.protocol.injector.GamePhase;
/**
* Represents additional options a listener may require.
*
@@ -238,12 +238,7 @@ public class ListeningWhitelist {
if (this == EMPTY_WHITELIST)
return "EMPTY_WHITELIST";
else
return Objects.toStringHelper(this).
add("priority", priority).
add("packets", types).
add("gamephase", gamePhase).
add("options", options).
toString();
return "ListeningWhitelist[priority=" + priority + ", packets=" + types + ", gamephase=" + gamePhase + ", options=" + options + "]";
}
/**
@@ -33,22 +33,23 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.compat.netty.Netty;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
import com.comphenix.protocol.injector.StructureCache;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
@@ -61,6 +62,7 @@ import com.comphenix.protocol.reflect.cloning.Cloner;
import com.comphenix.protocol.reflect.cloning.CollectionCloner;
import com.comphenix.protocol.reflect.cloning.FieldCloner;
import com.comphenix.protocol.reflect.cloning.ImmutableDetector;
import com.comphenix.protocol.reflect.cloning.OptionalCloner;
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
@@ -72,11 +74,16 @@ import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.EnumWrappers.ChatType;
import com.comphenix.protocol.wrappers.EnumWrappers.ChatVisibility;
import com.comphenix.protocol.wrappers.EnumWrappers.ClientCommand;
import com.comphenix.protocol.wrappers.EnumWrappers.CombatEventType;
import com.comphenix.protocol.wrappers.EnumWrappers.Difficulty;
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
import com.comphenix.protocol.wrappers.EnumWrappers.EnumConverter;
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
import com.comphenix.protocol.wrappers.EnumWrappers.ItemSlot;
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
import com.comphenix.protocol.wrappers.EnumWrappers.Particle;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerAction;
@@ -84,6 +91,7 @@ import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
import com.comphenix.protocol.wrappers.EnumWrappers.ResourcePackStatus;
import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction;
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction;
import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction;
import com.comphenix.protocol.wrappers.MultiBlockChangeInfo;
@@ -97,11 +105,16 @@ import com.comphenix.protocol.wrappers.WrappedServerPing;
import com.comphenix.protocol.wrappers.WrappedStatistic;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
/**
* Represents a Minecraft packet indirectly.
*
@@ -125,6 +138,7 @@ public class PacketContainer implements Serializable {
instanceProvider(DefaultInstances.DEFAULT).
andThen(BukkitCloner.class).
andThen(ImmutableDetector.class).
andThen(OptionalCloner.class).
andThen(CollectionCloner.class).
andThen(getSpecializedDeepClonerFactory()).
build();
@@ -147,8 +161,8 @@ public class PacketContainer implements Serializable {
// Packets that cannot be cloned by our default deep cloner
private static final Set<PacketType> CLONING_UNSUPPORTED = Sets.newHashSet(
PacketType.Play.Server.UPDATE_ATTRIBUTES, PacketType.Status.Server.OUT_SERVER_INFO);
PacketType.Play.Server.UPDATE_ATTRIBUTES, PacketType.Status.Server.SERVER_INFO);
/**
* Creates a packet container for a new packet.
* <p>
@@ -321,7 +335,15 @@ public class PacketContainer implements Serializable {
public StructureModifier<String> getStrings() {
return structureModifier.withType(String.class);
}
/**
* Retrieves a read/write structure for every UUID field.
* @return A modifier for every UUID field.
*/
public StructureModifier<UUID> getUUIDs() {
return structureModifier.withType(UUID.class);
}
/**
* Retrieves a read/write structure for every String array field.
* @return A modifier for every String array field.
@@ -357,7 +379,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for ItemStack.
* <p>
* This modifier will automatically marshall between the Bukkit ItemStack and the
* This modifier will automatically marshal between the Bukkit ItemStack and the
* internal Minecraft ItemStack.
* @return A modifier for ItemStack fields.
*/
@@ -370,7 +392,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for arrays of ItemStacks.
* <p>
* This modifier will automatically marshall between the Bukkit ItemStack and the
* This modifier will automatically marshal between the Bukkit ItemStack and the
* internal Minecraft ItemStack.
* @return A modifier for ItemStack array fields.
*/
@@ -380,7 +402,25 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getItemStackArrayClass(),
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
}
/**
* Retrieves a read/write structure for lists of ItemStacks.
* <p>
* This modifier will automatically marshal between the Bukkit ItemStack and the
* internal Minecraft ItemStack.
* @return A modifier for ItemStack list fields.
*/
public StructureModifier<List<ItemStack>> getItemListModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.withType(
List.class,
BukkitConverters.getListConverter(
MinecraftReflection.getItemStackClass(),
BukkitConverters.getItemStackConverter()
)
);
}
/**
* Retrieve a read/write structure for maps of statistics.
* <p>
@@ -399,7 +439,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for the world type enum.
* <p>
* This modifier will automatically marshall between the Bukkit world type and the
* This modifier will automatically marshal between the Bukkit world type and the
* internal Minecraft world type.
* @return A modifier for world type fields.
*/
@@ -499,6 +539,21 @@ public class PacketContainer implements Serializable {
BukkitConverters.getNbtConverter());
}
/**
* Retrieves a read/write structure for lists of NBT classes.
* @return A modifier for lists of NBT classes.
*/
public StructureModifier<List<NbtBase<?>>> getListNbtModifier() {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getNBTBaseClass(),
BukkitConverters.getNbtConverter()
)
);
}
/**
* Retrieves a read/write structure for Vectors.
* @return A modifier for Vectors.
@@ -513,7 +568,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for collections of attribute snapshots.
* <p>
* This modifier will automatically marshall between the visible ProtocolLib WrappedAttribute and the
* This modifier will automatically marshal between the visible ProtocolLib WrappedAttribute and the
* internal Minecraft AttributeSnapshot.
* @return A modifier for AttributeSnapshot collection fields.
*/
@@ -530,7 +585,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for collections of chunk positions.
* <p>
* This modifier will automatically marshall between the visible ProtocolLib ChunkPosition and the
* This modifier will automatically marshal between the visible ProtocolLib ChunkPosition and the
* internal Minecraft ChunkPosition.
*
* @return A modifier for ChunkPosition list fields.
@@ -548,7 +603,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for collections of chunk positions.
* <p>
* This modifier will automatically marshall between the visible ProtocolLib BlockPosition and the
* This modifier will automatically marshal between the visible ProtocolLib BlockPosition and the
* internal Minecraft BlockPosition.
*
* @return A modifier for ChunkPosition list fields.
@@ -566,7 +621,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for collections of watchable objects.
* <p>
* This modifier will automatically marshall between the visible WrappedWatchableObject and the
* This modifier will automatically marshal between the visible WrappedWatchableObject and the
* internal Minecraft WatchableObject.
* @return A modifier for watchable object list fields.
*/
@@ -575,16 +630,15 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getWatchableObjectClass(),
MinecraftReflection.getDataWatcherItemClass(),
BukkitConverters.getWatchableObjectConverter())
);
}
/**
* Retrieves a read/write structure for block fields.
* <p>
* This modifier will automatically marshall between Material and the
* This modifier will automatically marshal between Material and the
* internal Minecraft Block.
* @return A modifier for GameProfile fields.
*/
@@ -597,7 +651,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for game profiles in Minecraft 1.7.2.
* <p>
* This modifier will automatically marshall between WrappedGameProfile and the
* This modifier will automatically marshal between WrappedGameProfile and the
* internal Minecraft GameProfile.
* @return A modifier for GameProfile fields.
*/
@@ -610,7 +664,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for BlockData in Minecraft 1.8.
* <p>
* This modifier will automatically marshall between WrappedBlockData and the
* This modifier will automatically marshal between WrappedBlockData and the
* internal Minecraft IBlockData.
* @return A modifier for BlockData fields.
*/
@@ -623,7 +677,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for MultiBlockChangeInfo arrays in Minecraft 1.8.
* <p>
* This modifier will automatically marshall between MultiBlockChangeInfo and the
* This modifier will automatically marshal between MultiBlockChangeInfo and the
* internal Minecraft MultiBlockChangeInfo.
* @return A modifier for BlockData fields.
*/
@@ -638,7 +692,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for chat components in Minecraft 1.7.2.
* <p>
* This modifier will automatically marshall between WrappedChatComponent and the
* This modifier will automatically marshal between WrappedChatComponent and the
* internal Minecraft IChatBaseComponent.
* @return A modifier for ChatComponent fields.
*/
@@ -651,15 +705,19 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for arrays of chat components.
* <p>
* This modifier will automatically marshall between WrappedChatComponent and the
* internal Minecraft IChatBaseComponent.
* This modifier will automatically marshal between WrappedChatComponent and the
* internal Minecraft IChatBaseComponent (1.9.2 and below) or the internal
* NBTCompound (1.9.4 and up).
* <p>
* Note that in 1.9.4 and up this modifier only works properly with sign
* tile entities.
* @return A modifier for ChatComponent array fields.
*/
public StructureModifier<WrappedChatComponent[]> getChatComponentArrays() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedChatComponent[]>withType(
MinecraftReflection.getIChatBaseComponentArrayClass(),
BukkitConverters.getIgnoreNull(new WrappedChatComponentArrayConverter()));
ComponentArrayConverter.getGenericType(),
BukkitConverters.getIgnoreNull(new ComponentArrayConverter()));
}
/**
@@ -842,6 +900,99 @@ public class PacketContainer implements Serializable {
EnumWrappers.getParticleClass(), EnumWrappers.getParticleConverter());
}
/**
* Retrieve a read/write structure for the MobEffectList class in 1.9.
* @return A modifier for MobEffectList fields.
*/
public StructureModifier<PotionEffectType> getEffectTypes() {
// Convert to and from Bukkit
return structureModifier.<PotionEffectType>withType(
MinecraftReflection.getMobEffectListClass(), BukkitConverters.getEffectTypeConverter());
}
/**
* Retrieve a read/write structure for the SoundCategory enum in 1.9.
* @return A modifier for SoundCategory enum fields.
*/
public StructureModifier<SoundCategory> getSoundCategories() {
// Convert to and from the enums
return structureModifier.<SoundCategory>withType(
EnumWrappers.getSoundCategoryClass(), EnumWrappers.getSoundCategoryConverter());
}
/**
* Retrieve a read/write structure for the SoundEffect enum in 1.9.
* @return A modifier for SoundEffect enum fields.
*/
public StructureModifier<Sound> getSoundEffects() {
// Convert to and from Bukkit
return structureModifier.<Sound>withType(
MinecraftReflection.getSoundEffectClass(), BukkitConverters.getSoundConverter());
}
/**
* Retrieve a read/write structure for the ItemSlot enum in 1.9.
* @return A modifier for ItemSlot enum fields.
*/
public StructureModifier<ItemSlot> getItemSlots() {
return structureModifier.<ItemSlot>withType(
EnumWrappers.getItemSlotClass(), EnumWrappers.getItemSlotConverter());
}
/**
* Retrieve a read/write structure for the Hand enum in 1.9.
* @return A modifier for Hand enum fields.
*/
public StructureModifier<Hand> getHands() {
return structureModifier.<Hand>withType(
EnumWrappers.getHandClass(), EnumWrappers.getHandConverter());
}
/**
* Retrieve a read/write structure for the Direction enum in 1.10.
* @return A modifier for Direction enum fields.
*/
public StructureModifier<Direction> getDirections() {
return structureModifier.<Direction>withType(
EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter());
}
/**
* Retrieve a read/write structure for the ChatType enum in 1.12.
* @return A modifier for ChatType enum fields.
*/
public StructureModifier<ChatType> getChatTypes() {
return structureModifier.<ChatType>withType(
EnumWrappers.getChatTypeClass(), EnumWrappers.getChatTypeConverter());
}
/**
* Retrieve a read/write structure for an enum. This allows for the use of
* user-created enums that may not exist in ProtocolLib. The specific (user
* created) enum constants must match up perfectly with their generic (NMS)
* counterparts.
*
* @param enumClass The specific Enum class
* @param nmsClass The generic Enum class
* @return The modifier
*/
public <T extends Enum<T>> StructureModifier<T> getEnumModifier(Class<T> enumClass, Class<?> nmsClass) {
return structureModifier.<T>withType(nmsClass, new EnumConverter<T>(enumClass));
}
/**
* Retrieve a read/write structure for an enum. This method is for convenience,
* see {@link #getEnumModifier(Class, Class)} for more information.
*
* @param enumClass The specific Enum class
* @param index Index of the generic Enum
* @return The modifier
* @see #getEnumModifier(Class, Class)
*/
public <T extends Enum<T>> StructureModifier<T> getEnumModifier(Class<T> enumClass, int index) {
return getEnumModifier(enumClass, structureModifier.getField(index).getType());
}
/**
* Retrieves the ID of this packet.
* <p>
@@ -928,8 +1079,8 @@ public class PacketContainer implements Serializable {
try {
if (MinecraftReflection.isUsingNetty()) {
WrappedByteBuf buffer = createPacketBuffer();
MinecraftMethods.getPacketWriteByteBufMethod().invoke(handle, buffer.getHandle());
ByteBuf buffer = createPacketBuffer();
MinecraftMethods.getPacketWriteByteBufMethod().invoke(handle, buffer);
output.writeInt(buffer.readableBytes());
buffer.readBytes(output, buffer.readableBytes());
@@ -965,10 +1116,10 @@ public class PacketContainer implements Serializable {
// Call the read method
try {
if (MinecraftReflection.isUsingNetty()) {
WrappedByteBuf buffer = createPacketBuffer();
ByteBuf buffer = createPacketBuffer();
buffer.writeBytes(input, input.readInt());
MinecraftMethods.getPacketReadByteBufMethod().invoke(handle, buffer.getHandle());
MinecraftMethods.getPacketReadByteBufMethod().invoke(handle, buffer);
} else {
if (input.readInt() != -1)
throw new IllegalArgumentException("Cannot load a packet from 1.7.2 in 1.6.4.");
@@ -993,8 +1144,15 @@ public class PacketContainer implements Serializable {
* Construct a new packet data serializer.
* @return The packet data serializer.
*/
private WrappedByteBuf createPacketBuffer() {
return Netty.createPacketBuffer();
public static ByteBuf createPacketBuffer() {
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
Class<?> packetSerializer = MinecraftReflection.getPacketDataSerializerClass();
try {
return (ByteBuf) packetSerializer.getConstructor(ByteBuf.class).newInstance(buffer);
} catch (Exception e) {
throw new RuntimeException("Cannot construct packet serializer.", e);
}
}
// ---- Metadata
@@ -1134,11 +1292,11 @@ public class PacketContainer implements Serializable {
* Represents an equivalent converter for ChatComponent arrays.
* @author dmulloy2
*/
private static class WrappedChatComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
private static class LegacyComponentConverter implements EquivalentConverter<WrappedChatComponent[]> {
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
@Override
public Object getGeneric(Class<?>genericType, WrappedChatComponent[] specific) {
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
@@ -1167,8 +1325,95 @@ public class PacketContainer implements Serializable {
}
}
/**
* Converts from NBT to WrappedChatComponent arrays
* @author dmulloy2
*/
private static class NBTComponentConverter implements EquivalentConverter<WrappedChatComponent[]> {
private EquivalentConverter<NbtBase<?>> nbtConverter = BukkitConverters.getNbtConverter();
private final int lines = 4;
@Override
public WrappedChatComponent[] getSpecific(Object generic) {
NbtBase<?> nbtBase = nbtConverter.getSpecific(generic);
NbtCompound compound = (NbtCompound) nbtBase;
WrappedChatComponent[] components = new WrappedChatComponent[lines];
for (int i = 0; i < lines; i++) {
if (compound.containsKey("Text" + (i + 1))) {
components[i] = WrappedChatComponent.fromJson(compound.getString("Text" + (i + 1)));
} else {
components[i] = WrappedChatComponent.fromText("");
}
}
return components;
}
@Override
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
NbtCompound compound = NbtFactory.ofCompound("");
for (int i = 0; i < lines; i++) {
WrappedChatComponent component;
if (i < specific.length && specific[i] != null) {
component = specific[i];
} else {
component = WrappedChatComponent.fromText("");
}
compound.put("Text" + (i + 1), component.getJson());
}
return nbtConverter.getGeneric(genericType, compound);
}
@Override
public Class<WrappedChatComponent[]> getSpecificType() {
return WrappedChatComponent[].class;
}
}
/**
* A delegated converter that supports NBT to Component Array and regular Component Array
* @author dmulloy2
*/
private static class ComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
private static final EquivalentConverter<WrappedChatComponent[]> DELEGATE;
static {
if (!PacketType.Play.Server.UPDATE_SIGN.isDeprecated()) {
DELEGATE = new LegacyComponentConverter();
} else {
DELEGATE = new NBTComponentConverter();
}
}
@Override
public WrappedChatComponent[] getSpecific(Object generic) {
return DELEGATE.getSpecific(generic);
}
@Override
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
return DELEGATE.getGeneric(genericType, specific);
}
@Override
public Class<WrappedChatComponent[]> getSpecificType() {
return DELEGATE.getSpecificType();
}
public static Class<?> getGenericType() {
if (DELEGATE instanceof NBTComponentConverter) {
return MinecraftReflection.getNBTCompoundClass();
} else {
return MinecraftReflection.getIChatBaseComponentArrayClass();
}
}
}
@Override
public String toString() {
return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]";
}
}
}
@@ -23,13 +23,14 @@ import java.io.ObjectOutputStream;
import java.lang.ref.WeakReference;
import java.util.EventObject;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import com.comphenix.protocol.Application;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.error.PluginContext;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.google.common.base.Objects;
@@ -202,7 +203,7 @@ public class PacketEvent extends EventObject implements Cancellable {
* @return TRUE if we are, FALSE otherwise.
*/
public boolean isAsync() {
return !Application.isPrimaryThread();
return !Bukkit.isPrimaryThread();
}
/**
@@ -231,7 +232,7 @@ public class PacketEvent extends EventObject implements Cancellable {
if (CHANGE_WARNINGS.put(oldType, newType)) {
ProtocolLibrary.getErrorReporter().reportWarning(this,
Report.newBuilder(REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING).
messageParam(oldType, newType).
messageParam(PluginContext.getPluginCaller(new Exception()), oldType, newType).
build());
}
}
@@ -452,4 +453,4 @@ public class PacketEvent extends EventObject implements Cancellable {
public String toString() {
return "PacketEvent[player=" + getPlayer() + ", packet=" + packet + "]";
}
}
}
@@ -7,7 +7,6 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketStream;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
/**
@@ -138,10 +137,6 @@ public class ScheduledPacket {
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("packet", packet)
.add("target", target)
.add("filtered", filtered)
.toString();
return "ScheduledPacket[packet=" + packet + ", target=" + target + ", filtered=" + filtered + "]";
}
}
@@ -139,7 +139,6 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
return banned;
}
@Override
public void setBanned(boolean banned) {
this.banned = banned;
}
@@ -24,6 +24,9 @@ import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
@@ -31,6 +34,7 @@ import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.primitives.Primitives;
/**
@@ -182,20 +186,55 @@ public class BukkitUnwrapper implements Unwrapper {
Report.newBuilder(REPORT_SECURITY_LIMITATION).error(e).callerParam(type)
);
} catch (NoSuchMethodException e) {
// Maybe it's a proxy?
Unwrapper proxyUnwrapper = getProxyUnwrapper(type);
if (proxyUnwrapper != null)
return proxyUnwrapper;
// Try getting the field unwrapper too
Unwrapper fieldUnwrapper = getFieldUnwrapper(type);
if (fieldUnwrapper != null)
return fieldUnwrapper;
else
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
}
// Default method
return null;
}
// Players should /always/ be able to be unwrapped
// We should only get here if the 'Player' is a proxy
private Unwrapper getProxyUnwrapper(final Class<?> type) {
try {
if (Player.class.isAssignableFrom(type)) {
final Method getHandle = MinecraftReflection.getCraftPlayerClass().getMethod("getHandle");
Unwrapper unwrapper = new Unwrapper() {
@Override
public Object unwrapItem(Object wrapped) {
try {
return getHandle.invoke(((Player) wrapped).getPlayer());
} catch (Throwable ex) {
try {
return getHandle.invoke(Bukkit.getPlayer(((Player) wrapped).getUniqueId()));
} catch (ReflectiveOperationException ex1) {
throw new RuntimeException("Failed to unwrap proxy " + wrapped, ex);
}
}
}
};
unwrapperCache.put(type, unwrapper);
return unwrapper;
}
} catch (Throwable ignored) {
}
return null;
}
/**
* Retrieve a cached unwrapper using the handle field.
* @param type - a cached field unwrapper.
@@ -0,0 +1,31 @@
package com.comphenix.protocol.injector;
/**
* Sets the inject hook type. Different types allow for maximum compatibility.
* @author Kristian
*/
public enum PlayerInjectHooks {
/**
* The injection hook that does nothing. Set when every other inject hook fails.
*/
NONE,
/**
* Override the network handler object itself. Only works in 1.3.
* <p>
* Cannot intercept MapChunk packets.
*/
NETWORK_MANAGER_OBJECT,
/**
* Override the packet queue lists in NetworkHandler.
* <p>
* Cannot intercept MapChunk packets.
*/
NETWORK_HANDLER_FIELDS,
/**
* Override the server handler object. Versatile, but a tad slower.
*/
NETWORK_SERVER_OBJECT;
}
@@ -67,9 +67,11 @@ public class StructureCache {
// TODO: Optimize DefaultInstances
Object result = DefaultInstances.DEFAULT.create(clazz);
if (result != null) {
return result;
if (result == null) {
throw new IllegalArgumentException("Failed to create packet for type: " + type);
}
return result;
}
throw new IllegalArgumentException("Cannot find associated packet class: " + type);
}
@@ -172,4 +174,4 @@ public class StructureCache {
}
return result;
}
}
}
@@ -14,7 +14,7 @@
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
package com.comphenix.protocol.injector.netty;
import io.netty.buffer.AbstractByteBuf;
import io.netty.buffer.ByteBuf;
@@ -28,6 +28,7 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.channels.WritableByteChannel;
@@ -44,6 +45,7 @@ import com.google.common.io.ByteStreams;
* all indexing in the byte buffer.
* @author Kristian
*/
@SuppressWarnings("unused")
public class NettyByteBufAdapter extends AbstractByteBuf {
private DataInputStream input;
private DataOutputStream output;
@@ -214,7 +216,7 @@ public class NettyByteBufAdapter extends AbstractByteBuf {
@Override
public ByteBufAllocator alloc() {
return null;
return ByteBufAllocator.DEFAULT;
}
@Override
@@ -389,4 +391,48 @@ public class NettyByteBufAdapter extends AbstractByteBuf {
public ByteBuf retain() {
return this;
}
}
protected int _getIntLE(int arg0) {
return 0;
}
protected long _getLongLE(int arg0) {
return 0;
}
protected short _getShortLE(int arg0) {
return 0;
}
protected int _getUnsignedMediumLE(int arg0) {
return 0;
}
protected void _setIntLE(int arg0, int arg1) {
}
protected void _setLongLE(int arg0, long arg1) {
}
protected void _setMediumLE(int arg0, int arg1) {
}
protected void _setShortLE(int arg0, int arg1) {
}
public int getBytes(int arg0, FileChannel arg1, long arg2, int arg3) throws IOException {
return 0;
}
public int setBytes(int arg0, FileChannel arg1, long arg2, int arg3) throws IOException {
return 0;
}
public ByteBuf touch() {
return null;
}
public ByteBuf touch(Object arg0) {
return null;
}
}
@@ -1,104 +1,108 @@
/**
* 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.compat.netty.independent;
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.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.google.common.collect.Maps;
/**
* @author dmulloy2
*/
public class NettyProtocolRegistry extends ProtocolRegistry {
@Override
protected synchronized void initialize() {
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 occationally check have changed
for (Map<Integer, Class<?>> map : serverMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Map<Integer, Class<?>> map : clientMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (int i = 0; i < protocols.length; i++) {
Object protocol = protocols[i];
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;
}
@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());
try {
register.typeToClass.put(type, entry.getValue());
if (sender == Sender.SERVER)
register.serverPackets.add(type);
if (sender == Sender.CLIENT)
register.clientPackets.add(type);
} catch (IllegalArgumentException ex) {
// Sometimes this happens with fake packets, just ignore it
}
}
}
}
/**
* 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.util.Map;
import java.util.Map.Entry;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.google.common.collect.Maps;
/**
* @author dmulloy2
*/
public class NettyProtocolRegistry extends ProtocolRegistry {
public NettyProtocolRegistry() {
super();
}
@Override
protected synchronized void initialize() {
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 (Map<Integer, Class<?>> map : serverMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Map<Integer, Class<?>> 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;
}
@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());
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);
}
}
}
}
@@ -19,7 +19,7 @@ import com.google.common.collect.Sets;
* Represents a way of accessing the new netty Protocol enum.
* @author Kristian
*/
// TODO: Handle modifications to the BiMap
public abstract class ProtocolRegistry {
/**
* Represents a register we are currently building.
@@ -97,7 +97,7 @@ public abstract class ProtocolRegistry {
* This operation may block the calling thread.
*/
public synchronized void synchronize() {
// See if the register is outdated
// Check if the packet registry has changed
if (register.isOutdated()) {
initialize();
}
@@ -122,4 +122,4 @@ public abstract class ProtocolRegistry {
count += map.size();
return count;
}
}
}
@@ -0,0 +1,255 @@
/**
* 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 static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import java.util.Arrays;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* A packet represented only by its id and bytes.
* @author dmulloy2
*/
public class WirePacket {
private final int id;
private final byte[] bytes;
/**
* Constructs a new WirePacket with a given type and contents
* @param type Type of the packet
* @param bytes Contents of the packet
*/
public WirePacket(PacketType type, byte[] bytes) {
this.id = checkNotNull(type, "type cannot be null").getCurrentId();
this.bytes = bytes;
}
/**
* Constructs a new WirePacket with a given id and contents
* @param id ID of the packet
* @param bytes Contents of the packet
*/
public WirePacket(int id, byte[] bytes) {
this.id = id;
this.bytes = bytes;
}
/**
* Gets this packet's ID
* @return The ID
*/
public int getId() {
return id;
}
/**
* Gets this packet's contents as a byte array
* @return The contents
*/
public byte[] getBytes() {
return bytes;
}
/**
* Writes the id of this packet to a given output
* @param output Output to write to
*/
public void writeId(ByteBuf output) {
writeVarInt(output, id);
}
/**
* Writes the contents of this packet to a given output
* @param output Output to write to
*/
public void writeBytes(ByteBuf output) {
checkNotNull(output, "output cannot be null!");
output.writeBytes(bytes);
}
/**
* Fully writes the ID and contents of this packet to a given output
* @param output Output to write to
*/
public void writeFully(ByteBuf output) {
writeId(output);
writeBytes(output);
}
/**
* Serializes this packet into a byte buffer
* @return The buffer
*/
public ByteBuf serialize() {
ByteBuf buffer = Unpooled.buffer();
writeFully(buffer);
return buffer;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof WirePacket) {
WirePacket that = (WirePacket) obj;
return this.id == that.id &&
Arrays.equals(this.bytes, that.bytes);
}
return false;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(bytes);
result = prime * result + id;
return result;
}
@Override
public String toString() {
return "WirePacket[id=" + id + ", bytes=" + Arrays.toString(bytes) + "]";
}
private static byte[] getBytes(ByteBuf buffer) {
byte[] array = new byte[buffer.readableBytes()];
buffer.readBytes(array);
return array;
}
/**
* Creates a WirePacket from an existing PacketContainer
* @param packet Existing packet
* @return The resulting WirePacket
*/
public static WirePacket fromPacket(PacketContainer packet) {
int id = packet.getType().getCurrentId();
return new WirePacket(id, bytesFromPacket(packet));
}
/**
* Creates a byte array from an existing PacketContainer containing all the
* bytes from that packet
*
* @param packet Existing packet
* @return The ByteBuf
*/
public static byte[] bytesFromPacket(PacketContainer packet) {
checkNotNull(packet, "packet cannot be null!");
ByteBuf buffer = PacketContainer.createPacketBuffer();
ByteBuf store = PacketContainer.createPacketBuffer();
// Read the bytes once
Method write = MinecraftMethods.getPacketWriteByteBufMethod();
try {
write.invoke(packet.getHandle(), buffer);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to read packet contents.", ex);
}
byte[] bytes = getBytes(buffer);
// Rewrite them to the packet to avoid issues with certain packets
if (packet.getType() == PacketType.Play.Server.CUSTOM_PAYLOAD
|| packet.getType() == PacketType.Play.Client.CUSTOM_PAYLOAD) {
// Make a copy of the array before writing
byte[] ret = Arrays.copyOf(bytes, bytes.length);
store.writeBytes(bytes);
Method read = MinecraftMethods.getPacketReadByteBufMethod();
try {
read.invoke(packet.getHandle(), store);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to rewrite packet contents.", ex);
}
return ret;
}
return bytes;
}
/**
* Creates a WirePacket from an existing Minecraft packet
* @param packet Existing Minecraft packet
* @return The resulting WirePacket
* @throws IllegalArgumentException If the packet is null or not a Minecraft packet
*/
public static WirePacket fromPacket(Object packet) {
checkNotNull(packet, "packet cannot be null!");
checkArgument(MinecraftReflection.isPacketClass(packet), "packet must be a Minecraft packet");
PacketType type = PacketType.fromClass(packet.getClass());
int id = type.getCurrentId();
ByteBuf buffer = PacketContainer.createPacketBuffer();
Method write = MinecraftMethods.getPacketWriteByteBufMethod();
try {
write.invoke(packet, buffer);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to serialize packet contents.", ex);
}
return new WirePacket(id, getBytes(buffer));
}
public static void writeVarInt(ByteBuf output, int i) {
checkNotNull(output, "output cannot be null!");
while ((i & -128) != 0) {
output.writeByte(i & 127 | 128);
i >>>= 7;
}
output.writeByte(i);
}
public static int readVarInt(ByteBuf input) {
checkNotNull(input, "input cannot be null!");
int i = 0;
int j = 0;
byte b0;
do {
b0 = input.readByte();
i |= (b0 & 127) << j++ * 7;
if (j > 5) {
throw new RuntimeException("VarInt too big");
}
} while ((b0 & 128) == 128);
return i;
}
}
@@ -3,6 +3,7 @@ package com.comphenix.protocol.injector.packet;
import java.lang.reflect.Field;
import com.comphenix.protocol.reflect.FieldUtils;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a class that can detect if a map has changed.
@@ -10,17 +11,20 @@ import com.comphenix.protocol.reflect.FieldUtils;
*/
public class MapContainer {
// For detecting changes
private Field modCountField;
private final Field modCountField;
private int lastModCount;
// The object along with whether or not this is the initial run
private Object source;
private final Object source;
private boolean changed;
public MapContainer(Object source) {
this.source = source;
this.changed = true;
this.modCountField = FieldUtils.getField(source.getClass(), "modCount", true);
this.changed = false;
Field modCountField = FieldUtils.getField(source.getClass(), "modCount", true);
this.modCountField = checkNotNull(modCountField, "Could not obtain modCount field");
this.lastModCount = getModificationCount();
}
/**
@@ -55,13 +59,13 @@ public class MapContainer {
/**
* Retrieve the current modification count.
* @return The current count, or something different than lastModCount if not accessible.
* @return The current count
*/
private int getModificationCount() {
try {
return modCountField != null ? modCountField.getInt(source) : lastModCount + 1;
} catch (Exception e) {
throw new RuntimeException("Unable to retrieve modCount.", e);
return modCountField.getInt(source);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Unable to retrieve modCount.", ex);
}
}
}
}
@@ -18,23 +18,18 @@
package com.comphenix.protocol.injector.packet;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.compat.netty.LegacyProtocolRegistry;
import com.comphenix.protocol.compat.netty.independent.NettyProtocolRegistry;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.InsufficientPacketsException;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.TroveWrapper.CannotFindTroveNoEntryValue;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -50,45 +45,30 @@ public class PacketRegistry {
public static final ReportType REPORT_INSUFFICIENT_SERVER_PACKETS = new ReportType("Too few server packets detected: %s");
public static final ReportType REPORT_INSUFFICIENT_CLIENT_PACKETS = new ReportType("Too few client packets detected: %s");
// Two different packet registry
private static volatile LegacyPacketRegistry LEGACY;
// The Netty packet registry
private static volatile ProtocolRegistry NETTY;
// Cached for legacy
private static volatile Set<PacketType> NETTY_SERVER_PACKETS;
private static volatile Set<PacketType> NETTY_CLIENT_PACKETS;
// Cached for Netty
private static volatile Set<Integer> LEGACY_SERVER_PACKETS;
private static volatile Set<Integer> LEGACY_CLIENT_PACKETS;
private static volatile Map<Integer, Class> LEGACY_PREVIOUS_PACKETS;
// Whether or not the registry has
private static boolean INITIALIZED;
// Whether or not the registry has been initialized
private static volatile boolean INITIALIZED = false;
/**
* Initialize the packet registry.
* Initializes the packet registry.
*/
private static void initialize() {
if (INITIALIZED) {
// Make sure they were initialized
if (NETTY == null && LEGACY == null)
throw new IllegalStateException("No initialized registry.");
if (NETTY == null) {
throw new IllegalStateException("Failed to initialize packet registry.");
}
return;
}
// Check for netty
if (MinecraftReflection.isUsingNetty()) {
if (NETTY == null) {
if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
NETTY = new NettyProtocolRegistry();
} else {
NETTY = new LegacyProtocolRegistry();
}
}
} else {
initializeLegacy();
}
NETTY = new NettyProtocolRegistry();
INITIALIZED = true;
}
/**
@@ -98,41 +78,9 @@ public class PacketRegistry {
*/
public static boolean isSupported(PacketType type) {
initialize();
if (NETTY != null)
return NETTY.getPacketTypeLookup().containsKey(type);
// Look up the correct type
return type.isClient() ?
LEGACY.getClientPackets().contains(type.getLegacyId()) :
LEGACY.getServerPackets().contains(type.getLegacyId());
return NETTY.getPacketTypeLookup().containsKey(type);
}
/**
* Initialize the legacy packet registry.
*/
private static void initializeLegacy() {
if (LEGACY == null) {
try {
LEGACY = new LegacyPacketRegistry();
LEGACY.initialize();
} catch (InsufficientPacketsException e) {
if (e.isClient()) {
ProtocolLibrary.getErrorReporter().reportWarning(
PacketRegistry.class, Report.newBuilder(REPORT_INSUFFICIENT_CLIENT_PACKETS).messageParam(e.getPacketCount())
);
} else {
ProtocolLibrary.getErrorReporter().reportWarning(
PacketRegistry.class, Report.newBuilder(REPORT_INSUFFICIENT_SERVER_PACKETS).messageParam(e.getPacketCount())
);
}
} catch (CannotFindTroveNoEntryValue e) {
ProtocolLibrary.getErrorReporter().reportWarning(PacketRegistry.class,
Report.newBuilder(REPORT_CANNOT_CORRECT_TROVE_MAP).error(e.getCause()));
}
}
}
/**
* Retrieve a map of every packet class to every ID.
* <p>
@@ -142,38 +90,29 @@ public class PacketRegistry {
@Deprecated
public static Map<Class, Integer> getPacketToID() {
initialize();
if (NETTY != null) {
@SuppressWarnings("unchecked")
Map<Class, Integer> result = (Map)Maps.transformValues(NETTY.getPacketClassLookup(), new Function<PacketType, Integer>() {
@Override
public Integer apply(PacketType type) {
return type.getLegacyId();
};
});
return result;
}
return LEGACY.getPacketToID();
@SuppressWarnings("unchecked")
Map<Class, Integer> result = (Map) Maps.transformValues(
NETTY.getPacketClassLookup(),
new Function<PacketType, Integer>() {
@Override
public Integer apply(PacketType type) {
return type.getLegacyId();
};
});
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();
if (NETTY != null) {
@SuppressWarnings("unchecked")
Map<Class, PacketType> result = (Map)NETTY.getPacketClassLookup();
return result;
}
return Maps.transformValues(LEGACY.getPacketToID(), new Function<Integer, PacketType>() {
@Override
public PacketType apply(Integer packetId) {
return PacketType.findLegacy(packetId);
};
});
@SuppressWarnings("unchecked")
Map<Class, PacketType> result = (Map) NETTY.getPacketClassLookup();
return result;
}
/**
@@ -185,12 +124,9 @@ public class PacketRegistry {
@Deprecated
public static Map<Integer, Class> getOverwrittenPackets() {
initialize();
if (LEGACY != null)
return LEGACY.getOverwrittenPackets();
throw new IllegalStateException("Not supported on Netty.");
}
/**
* Retrieve the vanilla classes handling each packet ID.
* @return Vanilla classes.
@@ -198,22 +134,19 @@ public class PacketRegistry {
@Deprecated
public static Map<Integer, Class> getPreviousPackets() {
initialize();
if (NETTY != null) {
// Construct it first
if (LEGACY_PREVIOUS_PACKETS == null) {
Map<Integer, Class> map = Maps.newHashMap();
for (Entry<PacketType, Class<?>> entry : NETTY.getPacketTypeLookup().entrySet()) {
map.put(entry.getKey().getLegacyId(), entry.getValue());
}
LEGACY_PREVIOUS_PACKETS = Collections.unmodifiableMap(map);
// Construct it first
if (LEGACY_PREVIOUS_PACKETS == null) {
Map<Integer, Class> map = Maps.newHashMap();
for (Entry<PacketType, Class<?>> entry : NETTY.getPacketTypeLookup().entrySet()) {
map.put(entry.getKey().getLegacyId(), entry.getValue());
}
return LEGACY_PREVIOUS_PACKETS;
LEGACY_PREVIOUS_PACKETS = Collections.unmodifiableMap(map);
}
return LEGACY.getPreviousPackets();
return LEGACY_PREVIOUS_PACKETS;
}
/**
* Retrieve every known and supported server packet.
* <p>
@@ -223,15 +156,11 @@ public class PacketRegistry {
*/
@Deprecated
public static Set<Integer> getServerPackets() throws FieldAccessException {
initialize();
if (NETTY != null) {
if (LEGACY_SERVER_PACKETS == null) {
LEGACY_SERVER_PACKETS = toLegacy(NETTY.getServerPackets());
}
return LEGACY_SERVER_PACKETS;
if (LEGACY_SERVER_PACKETS == null) {
LEGACY_SERVER_PACKETS = toLegacy(getServerPacketTypes());
}
return LEGACY.getServerPackets();
return LEGACY_SERVER_PACKETS;
}
/**
@@ -240,17 +169,9 @@ public class PacketRegistry {
*/
public static Set<PacketType> getServerPacketTypes() {
initialize();
if (NETTY != null) {
NETTY.synchronize();
return NETTY.getServerPackets();
}
// Handle legacy
if (NETTY_SERVER_PACKETS == null) {
NETTY_SERVER_PACKETS = toPacketTypes(LEGACY.getServerPackets(), Sender.SERVER);
}
return NETTY_SERVER_PACKETS;
NETTY.synchronize();
return NETTY.getServerPackets();
}
/**
@@ -262,15 +183,11 @@ public class PacketRegistry {
*/
@Deprecated
public static Set<Integer> getClientPackets() throws FieldAccessException {
initialize();
if (NETTY != null) {
if (LEGACY_CLIENT_PACKETS == null) {
LEGACY_CLIENT_PACKETS = toLegacy(NETTY.getClientPackets());
}
return LEGACY_CLIENT_PACKETS;
if (LEGACY_CLIENT_PACKETS == null) {
LEGACY_CLIENT_PACKETS = toLegacy(getClientPacketTypes());
}
return LEGACY.getClientPackets();
return LEGACY_CLIENT_PACKETS;
}
/**
@@ -279,17 +196,9 @@ public class PacketRegistry {
*/
public static Set<PacketType> getClientPacketTypes() {
initialize();
if (NETTY != null) {
NETTY.synchronize();
return NETTY.getClientPackets();
}
// Handle legacy
if (NETTY_CLIENT_PACKETS == null) {
NETTY_CLIENT_PACKETS = toPacketTypes(LEGACY.getClientPackets(), Sender.CLIENT);
}
return NETTY_CLIENT_PACKETS;
NETTY.synchronize();
return NETTY.getClientPackets();
}
/**
@@ -338,10 +247,7 @@ public class PacketRegistry {
@Deprecated
public static Class getPacketClassFromID(int packetID) {
initialize();
if (NETTY != null)
return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID));
return LEGACY.getPacketClassFromID(packetID);
return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID));
}
/**
@@ -363,12 +269,26 @@ public class PacketRegistry {
*/
public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) {
initialize();
if (NETTY != null)
return NETTY.getPacketTypeLookup().get(type);
return LEGACY.getPacketClassFromID(type.getLegacyId(), forceVanilla);
// Try the lookup first
Class<?> clazz = NETTY.getPacketTypeLookup().get(type);
if (clazz != null) {
return clazz;
}
// Then try looking up the class names
for (String name : type.getClassNames()) {
try {
clazz = MinecraftReflection.getMinecraftClass(name);
break;
} catch (Exception ex) {
}
}
// TODO Cache the result?
return clazz;
}
/**
* Retrieves the correct packet class from a given packet ID.
* <p>
@@ -380,12 +300,9 @@ public class PacketRegistry {
@Deprecated
public static Class getPacketClassFromID(int packetID, boolean forceVanilla) {
initialize();
if (LEGACY != null)
return LEGACY.getPacketClassFromID(packetID, forceVanilla);
return getPacketClassFromID(packetID);
}
/**
* Retrieve the packet ID of a given packet.
* <p>
@@ -397,12 +314,9 @@ public class PacketRegistry {
@Deprecated
public static int getPacketID(Class<?> packet) {
initialize();
if (NETTY != null)
return NETTY.getPacketClassLookup().get(packet).getLegacyId();
return LEGACY.getPacketID(packet);
return NETTY.getPacketClassLookup().get(packet).getLegacyId();
}
/**
* Retrieve the packet type of a given packet.
* @param packet - the class of the packet.
@@ -420,14 +334,6 @@ public class PacketRegistry {
*/
public static PacketType getPacketType(Class<?> packet, Sender sender) {
initialize();
if (NETTY != null) {
return NETTY.getPacketClassLookup().get(packet);
} else {
final int id = LEGACY.getPacketID(packet);
return PacketType.hasLegacy(id) ?
PacketType.fromLegacy(id, sender) : null;
}
return NETTY.getPacketClassLookup().get(packet);
}
}
@@ -11,4 +11,4 @@
* }
* </pre>
*/
package com.comphenix.protocol;
package com.comphenix.protocol;
@@ -17,10 +17,7 @@
package com.comphenix.protocol.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
@@ -29,6 +26,8 @@ import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.Validate;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
@@ -168,13 +167,42 @@ public class FuzzyReflection {
*/
public Method getMethod(AbstractFuzzyMatcher<MethodInfo> matcher) {
List<Method> result = getMethodList(matcher);
if (result.size() > 0)
if (result.size() > 0) {
return result.get(0);
else
} else {
throw new IllegalArgumentException("Unable to find a method that matches " + matcher);
}
}
/**
* Retrieve a method that matches. If there are multiple methods that match, the first one with the preferred
* name is selected.
* <p>
* ForceAccess must be TRUE in order for this method to access private, protected and package level method.
* @param matcher - the matcher to use.
* @param preferred - the preferred name.
* @return The first method that satisfies the given matcher.
* @throws IllegalArgumentException If the method cannot be found.
*/
public Method getMethod(AbstractFuzzyMatcher<MethodInfo> matcher, String preferred) {
List<Method> result = getMethodList(matcher);
if (result.size() > 1) {
for (Method method : result) {
if (method.getName().equals(preferred)) {
return method;
}
}
}
if (result.size() > 0) {
return result.get(0);
} else {
throw new IllegalArgumentException("Unable to find a method that matches " + matcher);
}
}
/**
* Retrieve a list of every method that matches the given matcher.
* <p>
@@ -390,6 +418,30 @@ public class FuzzyReflection {
return fields;
}
/**
* Retrieves a field with a given type and parameters. This is most useful
* when dealing with Collections.
*
* @param fieldType Type of the field
* @param params Variable length array of type parameters
* @return The field
*
* @throws IllegalArgumentException If the field cannot be found
*/
public Field getParameterizedField(Class<?> fieldType, Class<?>... params) {
for (Field field : getFields()) {
if (field.getType().equals(fieldType)) {
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
if (Arrays.equals(((ParameterizedType) type).getActualTypeArguments(), params))
return field;
}
}
}
throw new IllegalArgumentException("Unable to find a field with type " + fieldType + " and params " + Arrays.toString(params));
}
/**
* Retrieve the first field that matches.
@@ -548,6 +600,8 @@ public class FuzzyReflection {
* @return Every field.
*/
public Set<Field> getFields() {
Validate.notNull(source, "source cannot be null!");
// We will only consider private fields in the declared class
if (forceAccess)
return setUnion(source.getDeclaredFields(), source.getFields());
@@ -603,7 +657,7 @@ public class FuzzyReflection {
// Prevent duplicate fields
// @SafeVarargs
@SafeVarargs
private static <T> Set<T> setUnion(T[]... array) {
Set<T> result = new LinkedHashSet<T>();
Loaded 100 of 359 files, more files were not shown because too many files have changed in this diff. Show more