Compare commits

..
260 Commits
Author SHA1 Message Date
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
Dan Mulloy 11cb603130 Update version to 3.6.5 for release 2016-01-30 12:54:33 -05:00
Dan Mulloy 0dd20f8d08 Add tests for the updaters, improve the check command 2016-01-30 12:33:16 -05:00
Dan Mulloy 7630007833 Cut down on static calls to the main class 2016-01-29 23:41:26 -05:00
Dan Mulloy de8bb2bd66 Switch to HTTPS for Spigot update checking
Should fix the 403 errors
2016-01-29 23:28:10 -05:00
Dan Mulloy 83c2943b48 Update release version in the readme
Closes https://github.com/aadnk/ProtocolLib/pull/98
2016-01-23 19:46:49 -05:00
Dan Mulloy c368251954 Add some more tests for WrappedGameProfile 2016-01-10 15:52:35 -05:00
Dan Mulloy 39998eedf8 Make sure the plugins folder actually exists before iterating 2016-01-09 12:31:20 -05:00
Dan Mulloy 8e8cf54ddd Fix conflict checking with different plugins folders
Fixes #136
2016-01-09 12:28:05 -05:00
Dan Mulloy 5a5cd77bac Temporarily restore Java 6 compatibility
3.6.5 will be the last ProtocolLib release supporting Java 6
2015-11-30 19:03:32 -05:00
Dan Mulloy 125834205a Add md_5's repo for 1.7.10 2015-11-27 18:05:33 -05:00
Dan Mulloy 0c705ef59d Restore backwards compatibility with server pings
I don't know why people are using 1.8.1, but whatever
2015-11-27 17:02:41 -05:00
Dan Mulloy b17af68716 Clean up some less-than-conventional code 2015-11-24 15:35:23 -05:00
Dan Mulloy 3e69dd69ed Actually commit the files
I need to get eclipse to do this automatically
2015-11-14 14:32:51 -05:00
Dan Mulloy 395d77e721 Reimplement auto updater, fix legacy packets
Also a few minor bug fixes and improvements
Fixes #127
2015-11-14 14:31:45 -05:00
Dan Mulloy e84fca699d Whoops, left some debug info in 2015-11-13 20:07:12 -05:00
Dan Mulloy 880cf29fc7 Don't depend on packet IDs anymore for 1.9
Packet IDs will supposedly be shuffled in 1.9, so they are no longer
reliable for our packet associations. This shouldn't affect plugins,
unless you're using IDs, in which case you should stop doing that.

Addresses #128
2015-11-13 20:05:53 -05:00
Dan Mulloy 7dff86cb48 Fix the StreamSerializer
String-based methods will still work, but deserializing from a data
input stream has been deprecated since it depends on hacky code

Fixes #31, Fixes #125
2015-11-02 23:56:41 -05:00
Dan Mulloy 4bb917e596 Stop testing with open jdk 6
Build errors galore
2015-10-31 13:53:31 -04:00
Dan Mulloy bd28035024 Don't load classes when we're checking for them
This causes a ton of lag and doesn't seem to ever work
Addresses #124
2015-10-31 13:47:45 -04:00
Dan Mulloy c40d9c1e6c Add some debug info for issue #109 2015-10-31 13:12:18 -04:00
Dan Mulloy cd7894f9f1 Ignore improperly registered custom packets
Fixes #123
2015-10-23 20:28:49 -04:00
Dan Mulloy 245433b29a Fix server pings and the infamous closed channel exception
As a result, packet listeners for OUT_SERVER_INFO will be processed on
the netty server io thread, so they will have to be thread safe if they
aren't already.
Fixes #119
2015-10-16 22:36:01 -04:00
Dan Mulloy 9433ea5e48 Add some debug info for exception caught messages
Also added support for deprecated block id's and suppressed some
compiler warnings with Java 7.
2015-10-07 18:12:50 -04:00
Dan Mulloy 0d3867c6f1 Add WrappedBlockData.getData(), improve block data test 2015-09-23 20:18:04 -04:00
Dan Mulloy 4e16792450 Delay server channel injection if late bind is detected
Fixes #116
2015-09-22 21:48:55 -04:00
Dan Mulloy a2452cba67 Add BlockPosition#toLocation 2015-08-29 12:42:47 -04:00
Dan Mulloy fc28a9242c Blacklist the UPDATE_ATTRIBUTES packet in the deep clone test 2015-08-21 17:52:20 -04:00
Dan Mulloy 368ed76677 Fix IllegalArgumentException with watchable objects 2015-08-09 18:27:00 -04:00
Dan Mulloy e6c87129bd Add version to stack traces, fix EnumWrappers in pre-1.8 2015-08-09 12:53:27 -04:00
Dan Mulloy 3166241397 Improve server mocking, test lore and material data 2015-07-29 12:29:59 -04:00
Dan Mulloy 8576b7a057 Update to 1.8.8 2015-07-27 15:05:32 -04:00
Dan Mulloy 0b63ae0354 Remove unnecessary method call 2015-07-24 12:40:47 -04:00
Dan Mulloy 0159752687 Fix NoSuchMethodError with pre-1.7.9 versions
Fixes #104
2015-07-24 12:36:26 -04:00
Dan Mulloy 7226e199e5 A few build improvements 2015-07-18 21:35:00 -04:00
Dan Mulloy 4c97c3c7ce Don't build TinyProtocol, it isn't actually a plugin 2015-07-18 21:09:02 -04:00
Dan Mulloy ae47ae3b89 Only suppress ClosedChannelExceptions 2015-07-18 21:07:41 -04:00
Dan Mulloy 900b31e0c9 Include Java versions in errors 2015-07-12 21:49:04 -04:00
Dan Mulloy f77ff6a0a2 Add /protocol dump, should help with debugging 2015-07-12 21:07:09 -04:00
Dan Mulloy 714e631dd0 Attempt to alleviate some issues with backwards compatibility
Addresses #98
2015-07-12 13:58:31 -04:00
Dan Mulloy b50133d322 Bump version to 3.6.5-SNAPSHOT 2015-07-12 12:17:48 -04:00
Dan Mulloy 0dd37bb801 Bump version to 3.6.4 for release 2015-07-11 16:52:27 -04:00
Dan Mulloy 5e703d91db Write Spigot's chat components as null in compiled modifiers too
Fixes #95
2015-07-07 13:55:31 -04:00
Dan Mulloy c7dab69cba Specifically write Spigot's chat components as null 2015-07-06 21:08:14 -04:00
Dan Mulloy 7861a57d37 Fix empty chat messages
Also improved incompatible plugin checking
2015-07-06 02:20:32 -04:00
Dan Mulloy 7b9e0cdb65 Fix timeout error with MCPC 1.6.4
Fixes aadnk#90
2015-06-28 15:55:11 -04:00
Dan Mulloy 74b1d93209 Add PlayerInfoData test 2015-06-26 22:50:31 -04:00
Dan Mulloy f825acb4d6 Revert changes to ItemStack handling, fix StreamSerializer 2015-06-26 22:50:02 -04:00
Dan Mulloy 47632e1fb1 Ignore log files generated by Log4J, fix an error with MCPC 2015-06-25 17:34:34 -04:00
Dan Mulloy b32d0d5fcd Attempt to restore compatibility with MCPC/Cauldron
Addresses aadnk#90, aadnk#83, and aadnk#71
2015-06-25 16:34:09 -04:00
Dan Mulloy 92fabb31b2 Minor restructure - move examples to modules, rename ShadedNetty 2015-06-24 11:48:07 -04:00
Dan Mulloy d012296ee0 Properly link to the Travis build status 2015-06-23 14:01:50 -04:00
Dan Mulloy fbc596d57b Add a generic enum converter and a set converter 2015-06-23 12:59:13 -04:00
Dan Mulloy 1b4a8ec0aa Customize the JavaDocs a bit 2015-06-21 23:36:07 -04:00
Dan Mulloy 63babc4ca1 Allow particles to be looked up using their name 2015-06-21 16:31:55 -04:00
Dan Mulloy 3f5abe8719 Fix a typo in WrappedSignedProperty 2015-06-20 16:19:52 -04:00
Dan Mulloy 84b502cba7 Fix constructor visibility 2015-06-19 22:18:46 -04:00
Dan Mulloy 9fe5df3cfe Properly obtain read/write methods for tile entities 2015-06-19 22:17:34 -04:00
Dan Mulloy e0f7c72e18 Use correct Guava package, fix a few compatibility issues 2015-06-19 13:14:20 -04:00
Dan Mulloy b1b5408c53 Don't fail the build if there are JavaDoc errors 2015-06-18 22:56:12 -04:00
Dan Mulloy 62ebcbb66d Properly aggregate the JavaDocs 2015-06-18 22:48:00 -04:00
Dan Mulloy cb0fdcff9d Set parent version to dev-SNAPSHOT 2015-06-18 22:07:08 -04:00
Dan Mulloy ee3db1e25a Fix netty compat module build failing 2015-06-18 22:04:29 -04:00
Dan Mulloy 165b4d3126 Only test the main plugin, fix JavaDoc errors 2015-06-18 21:54:18 -04:00
Dan Mulloy 25bdcd6bad Add the parent pom 2015-06-18 21:10:04 -04:00
Dan Mulloy 49fb3339be Git decided to ignore a good chunk of the files 2015-06-18 21:09:21 -04:00
Dan Mulloy 325b91fb1f Provide backwards compatibility with 1.7.10 and earlier
Also update the version to 3.6.4 since this was such a massive change
2015-06-18 21:07:32 -04:00
Dan Mulloy 9ce277cd76 Add Java 6 to Travis 2015-06-17 15:33:36 -04:00
Dan Mulloy 6af2d37319 And a few more 2015-06-17 15:23:13 -04:00
Dan Mulloy 273b470140 And a few more 2015-06-17 15:08:58 -04:00
Dan Mulloy bba1054f97 Fix a ton of JavaDoc errors 2015-06-17 14:25:39 -04:00
Dan Mulloy 241003b56a Clean up the pom a bit 2015-06-17 12:42:36 -04:00
Dan Mulloy e6b5d53234 Restore compatibility with Java 6 2015-06-17 12:19:29 -04:00
Dan Mulloy c3dacd06aa Link to Travis 2015-06-16 20:12:43 -04:00
Dan Mulloy 6e553bc59d Properly initialize required internals 2015-06-16 20:09:46 -04:00
Dan Mulloy f5f3eef988 Fix travis builds 2015-06-16 19:50:27 -04:00
Dan Mulloy 4e7bff40c0 Properly encode and decode x and z coordinates 2015-06-16 19:48:30 -04:00
Dan Mulloy 06eac8f67b Add .travis.yml 2015-06-15 17:10:38 -04:00
Dan Mulloy 2c5b3a2a5b Fix odd ArrayStoreException with MultiBlockChangeInfo
Also adapt test to test with arrays
2015-06-15 13:54:34 -04:00
Dan Mulloy 24d5b1739a Fix the MultiBlockChangeInfo wrapper
Also add a few tests to make sure it keeps working
2015-06-15 00:58:16 -04:00
Dan Mulloy 0d18bd2734 Attempt to fix a NPE with packet sending
Addresses #88
2015-06-09 14:19:37 -04:00
Dan Mulloy 423cc320f6 Add ability to convert to and from the BungeeCord Chat API
Fixes #87
2015-06-09 11:08:54 -04:00
Dan Mulloy 594b7ad075 Update to 1.8.7
Yay, no code changes!
2015-06-05 14:07:32 -04:00
Dan Mulloy 270cdfca2f Handle package seal 2015-06-03 16:28:09 -04:00
Dan Mulloy 20247747b5 Fix AttributeSnapshot, rewrite ItemStack handling, add more tests
Fixes #85
2015-06-02 14:57:30 -04:00
Dan Mulloy a718cc9067 Add a test to make sure all packets are registered 2015-05-31 14:42:52 -04:00
Dan Mulloy 9f2141331a Update subprojects to 1.8.6 2015-05-25 11:53:08 -04:00
Dan Mulloy 80fbd3ebc2 Update to 1.8.6 2015-05-25 11:36:05 -04:00
Dan Mulloy e0d4110cd2 Remove debug stacktrace 2015-05-22 14:38:27 -04:00
Dan Mulloy 99dea686a9 Update tests for 1.8.5 2015-05-22 14:35:58 -04:00
Dan Mulloy eca168edcf ProtocolLib works with 1.8.5
Yay no code changes necessary!
2015-05-22 13:47:14 -04:00
Dan Mulloy f89b71c5b4 Use my maven repo, builds exponentially faster now 2015-05-20 19:28:56 -04:00
Dan Mulloy abfb1ce9ac Apparently wrong JavaDocs kill the build now 2015-05-20 18:04:33 -04:00
Dan Mulloy 27f3f76c5e Deploy to my fancy new maven repo 2015-05-20 17:50:07 -04:00
Dan Mulloy 36313eabb1 Add wrapper for MultiBlockChangeInfo 2015-05-10 14:04:08 -04:00
Dan Mulloy 1da65317c4 Add in basic metadata API
Fixes #80
2015-04-26 15:47:44 -04:00
Dan Mulloy e4d1f8d992 Fix typo in Readme.md 2015-04-19 20:18:43 -04:00
Dan Mulloy 166c615725 Fix getProtocolVersion()
Fixes #74
2015-04-16 21:13:58 -04:00
Dan Mulloy 0cc182f93d Reimplement plugin incompatibility check, tweak some commands 2015-04-11 16:47:07 -04:00
Dan Mulloy 0ed76d7228 Use our scheduler with metrics 2015-04-09 20:42:54 -04:00
Dan Mulloy ce3069d490 Update metrics to revision 7, don't include build number with metrics 2015-04-09 20:36:57 -04:00
Dan Mulloy e31599073f Reimplement the last possible tests, add a few more 2015-04-06 18:19:00 -04:00
Dan Mulloy a2c9240011 Reimplement a bunch more tests 2015-04-06 17:30:01 -04:00
Dan Mulloy 0958c042c9 Fix some more failing tests 2015-04-05 19:50:47 -04:00
Dan Mulloy 1c6641748b Don't run tests with the legacy profile 2015-04-05 19:40:02 -04:00
Dan Mulloy 889d1f6bc4 Reimplement some tests, fix reloading
Fixes #68
2015-04-05 19:23:06 -04:00
Dan Mulloy c981ba8d62 Fix a few copyright headers, update packages in Constants 2015-04-03 17:24:28 -04:00
Dan Mulloy 5d80173f44 Fix block data, don't shade netty 2015-04-03 14:00:56 -04:00
Dan Mulloy a5689a5550 Handle uncaught exceptions to avoid console spam 2015-04-02 14:28:29 -04:00
Dan Mulloy 16111449b4 Restore compatibility with 1.8 2015-03-31 19:31:11 -04:00
Dan Mulloy d96ed73e82 Add build number to the version 2015-03-31 15:45:19 -04:00
Dan Mulloy 992be51646 Rewrite BukkitCloner to be more dynamic, fix some NPEs
Fixes #66
2015-03-30 23:20:13 -04:00
Dan Mulloy 0abe72d72b Don't bother printing warnings for nonexistant CustomTypes 2015-03-30 10:03:28 -04:00
Dan Mulloy 24e543b33b The login start packet is a better source for GameProfiles 2015-03-29 23:02:59 -04:00
Dan Mulloy d44741dd17 Update the .gitignore 2015-03-29 22:58:50 -04:00
Dan Mulloy addfacb19c Add backwards compatibility for versions 1.0 thru 1.7.10 2015-03-29 22:56:11 -04:00
Dan Mulloy 2c743e1c89 Fix an error involving async packets and logged off players
Fixes #65
2015-03-22 21:23:59 -04:00
Dan Mulloy ae8ba16a7e PlayerDigType is the second enum in the packet
Fixes #62
2015-03-22 15:38:14 -04:00
Dan Mulloy 16c85ac8b4 Chunk position no longer exists, don't sweat if we can't find it
Fixes #64
2015-03-22 15:30:45 -04:00
Dan Mulloy 37123c0aa1 Make async packets less scary 2015-03-22 15:26:01 -04:00
Dan Mulloy 923f4f4c4a Merge pull request #61 from yawkat/8-patch-0
Implement AnnotatedElement contract in MethodInfo
2015-03-21 12:03:35 -04:00
Jonas Konrad 0b4ce155ac Implement AnnotatedElement contract in MethodInfo 2015-03-21 14:32:42 +01:00
Dan Mulloy cb5633aba8 Merge pull request #60 from Techcable/patch-1
Only compile version pattern once
2015-03-16 16:03:33 -04:00
Techcable a078ddb6e6 Only compile pattern once 2015-03-15 23:01:24 -07:00
Dan Mulloy c7b9600c21 Fix a ClassNotFoundException with PlayerInfoData
Fixes #59
2015-03-15 13:10:36 -04:00
Dan Mulloy ac14843d96 Update to 1.8.3 2015-03-14 14:51:40 -04:00
Dan Mulloy 9a0c421b52 Update maximum supported version 2015-03-13 16:52:01 -04:00
Dan Mulloy f72a6d8695 Fix a ClassNotFoundException with AttributeSnapshot
Fixes #56
2015-03-09 16:43:25 -04:00
Dan Mulloy 7291837b9d Fix a few errors with inner classes 2015-03-07 18:27:48 -05:00
Dan Mulloy b0662b05c5 Initial update to 1.8.3 2015-03-07 17:57:47 -05:00
Dan Mulloy 0d4071f11e Use my maven repo, should fix compilation errors 2015-02-27 12:37:49 -05:00
Dan Mulloy 115b5e8daa [TinyProtocol] Format TinyProtocol 2015-02-17 16:53:09 -05:00
Dan Mulloy 66be4900a3 Warn if exceptions are caused by broken plugins 2015-02-14 21:57:45 -05:00
Dan Mulloy a3784b3cf1 Improve Util.getOnlinePlayers() 2015-02-12 17:02:38 -05:00
Dan Mulloy ac54cef2fd Add methods to convert NativeGameMode to and from GameMode
Fixes #45
2015-02-05 16:20:02 -05:00
Dan Mulloy 391970b185 Fix nonexistent field messages 2015-01-31 00:54:55 -05:00
Dan Mulloy bfb0683b1f Don't take fieldIndex into account when checking for nonexistent fields 2015-01-28 21:30:17 -05:00
Dan Mulloy 704fe60bd1 Provide more descriptive error messages for nonexistent fields 2015-01-28 21:28:28 -05:00
Dan Mulloy 1d711315e4 Add wrapper for BlockData
Closes #34
2015-01-26 17:26:07 -05:00
Dan Mulloy 8846b28469 Add support for Particle modification 2015-01-25 12:42:30 -05:00
Dan Mulloy 3dda5c6a0a Remove unused code, revert some unnecessary changes 2015-01-17 19:23:51 -05:00
Dan Mulloy 5e5eff5e5f Merge pull request #32 from DarkSeraphim/patch-1
Fix NPE when writing PlayerInfoData to packet
2015-01-08 20:10:31 -05:00
Mark Hendriks dd5bfd5f16 Fix NPE when writing PlayerInfoData to packet
By default, the listName field in EntityPlayer is null. As the WrappedChatComponent ignores null values (which in itself is completely fine), the field will be null when you read one while the EntityPlayer has no listName. When you try to write one, however, the converter directly accesses the handle from the WrappedChatComponent. This means you will be trying to access the handle of null when you don't explicitly set the displayName in such a packet.
2015-01-09 01:45:17 +01:00
Dan Mulloy 266e9e47cc Move null assignments after the proper checks 2015-01-04 17:54:12 -05:00
Dan Mulloy 489c72418d Add initial support for wire format packets 2015-01-03 23:18:43 -05:00
Dan Mulloy 6ddbbfb428 Use correct methods for WrappedChatComponent 2015-01-02 17:07:15 -05:00
Dan Mulloy 09e2312d80 More practical fix for #28 2015-01-01 21:44:38 -05:00
Dan Mulloy a1b989cb3a Revert changes to channel injection 2015-01-01 21:21:42 -05:00
Dan Mulloy a748a95197 Fix a few errors with injection 2015-01-01 13:53:46 -05:00
Dan Mulloy 79da4f92a1 Don't attempt to process packets after disconnect
Addresses #28
2015-01-01 12:48:05 -05:00
Dan Mulloy 5605c3817e Fix issues with determining async packets
Fixes #27
2014-12-31 18:26:35 -05:00
Dan Mulloy 10f9c4c9f9 Partial fix for async packets 2014-12-28 13:34:40 -05:00
Dan Mulloy 7d5e1b9c34 Update StreamSerializer to 1.8 2014-12-28 13:09:29 -05:00
Dan Mulloy 687db088ec Update versions in WrappedServerPing 2014-12-23 14:09:21 -05:00
Dan Mulloy 6f3329cae6 Fix some tests 2014-12-23 00:25:16 -05:00
Dan Mulloy 2ed358405d Actually fix PlayerInfoData constructor 2014-12-20 22:18:05 -05:00
Dan Mulloy 0af57b853e Organize PlayerInfoData by constructor order 2014-12-20 19:22:42 -05:00
Flo // Sheigutn 776eeb898f Fix PlayerInfoData constructor 2014-12-20 19:17:07 -05:00
Dan Mulloy 5f4867eb1f Add wrapper for PlayerInfoData 2014-12-18 21:25:49 -05:00
Dan Mulloy f145d32016 TagAPI no longer works, update minimum version 2014-12-13 23:44:01 -05:00
Dan Mulloy 821c3a1d48 Update maven plugin versions 2014-12-13 17:02:54 -05:00
Dan Mulloy 2a51e16ef0 Update Readme to contain Maven info 2014-12-09 17:41:37 -05:00
Dan Mulloy 4c1fac9aa3 [ItemDisguise] Update ItemDisguise to 1.8 2014-12-08 16:36:20 -05:00
Dan Mulloy a60e2522c9 [TinyProtocol] Update to 1.8 2014-12-08 16:24:27 -05:00
Dan Mulloy 74297da901 Add Spigot requirement in the Readme 2014-12-06 09:40:30 -05:00
Dan Mulloy 0bc1b7ecaf Correct casing of Vec3D 2014-12-05 21:45:45 -05:00
Dan Mulloy f6e0bcf6f5 Add support for getting vectors 2014-12-05 21:41:55 -05:00
Dan Mulloy 2c017c6dac Merge branch 'master' of https://github.com/dmulloy2/ProtocolLib.git 2014-12-05 18:41:33 -05:00
Dan Mulloy 58302f2477 Use local repository instead 2014-12-05 18:41:07 -05:00
Dan Mulloy 37d4fadbf1 Merge pull request #17 from Zeruska/master
Fix typo in EnumWrappers (PlayerInfoAction)
2014-12-05 09:03:06 -05:00
Zeruska 701885e4eb Fix typo in EnumWrappers (PlayerInfoAction) 2014-12-04 11:40:22 +01:00
Dan Mulloy f14623897b Move libraries to the local machine 2014-12-03 16:38:03 -05:00
Dan Mulloy 9a9c5446cc Rename some enum wrappers to match their NMS counterparts 2014-12-03 16:24:53 -05:00
Dan Mulloy 1a368299b4 Merge pull request #15 from Zeruska/master
Add more EnumWrappers (PlayerDiggingAction, EntityAction, UpdateScoreAct...
2014-12-03 16:15:07 -05:00
Zeruska d6b94e658a Add more EnumWrappers (PlayerDiggingAction, EntityAction, UpdateScoreAction) 2014-12-03 21:56:23 +01:00
Dan Mulloy dabbe3fca9 Clarify the compatibility section 2014-12-02 16:20:03 -05:00
Dan Mulloy 5b9acb72fb Remove extra space 2014-12-02 16:12:03 -05:00
Dan Mulloy 30bff505c4 Fix some spacing 2014-12-02 16:11:13 -05:00
Dan Mulloy fa1d419b66 Merge pull request #13 from Sheigutn/master
Add PlayerInfoAction EnumWrapper
2014-12-02 16:08:51 -05:00
Flo // Sheigutn ea734965bc Add PlayerInfoAction EnumWrapper 2014-12-02 19:29:10 +01:00
Dan Mulloy 954a37a261 Fix a few javadoc issues 2014-12-01 16:31:11 -05:00
Dan Mulloy 98eb6958e0 Add more EnumWrappers
Thanks @Zeruska!
2014-12-01 16:25:27 -05:00
Dan Mulloy 18a45aace0 Fix an issue getting chat component arrays 2014-12-01 16:11:27 -05:00
Dan Mulloy 1c8e3b5ee3 Add support for ResourcePackStatus 2014-11-30 18:44:10 -05:00
Dan Mulloy d7087c2da5 Make write error messages more informational 2014-11-30 18:29:22 -05:00
Dan Mulloy 7b08bb9e1b Fix some javadoc typos 2014-11-30 12:24:47 -05:00
Dan Mulloy 6abd0cfdaa Add support for accessing ChatComponent arrays
Fixes #7
2014-11-30 12:23:59 -05:00
Dan Mulloy 3ac9793553 Update EnumWrappers with new constants 2014-11-29 21:24:27 -05:00
Dan Mulloy dfc1808aca Update protocol version 2014-11-29 21:13:49 -05:00
Dan Mulloy 30008ddd2c Merge branch 'master' of https://github.com/dmulloy2/ProtocolLib.git 2014-11-29 17:12:34 -05:00
Dan Mulloy 2074c2cab1 Add getters for block position
Fixes #6
2014-11-29 17:12:24 -05:00
Dan Mulloy 9cab57fa1c Merge pull request #5 from Minecrell/enum_wrappers
Fix EnumWrappers referencing a changed packet
Thanks @Minecrell!
2014-11-29 15:30:14 -05:00
Minecrell c2fdd15677 Fix EnumWrappers referencing a changed packet 2014-11-29 21:14:20 +01:00
Dan Mulloy a501e50237 Increment version to 3.6.3-SNAPSHOT 2014-11-29 13:51:23 -05:00
Dan Mulloy 38cf8f4888 Add wrapped block position, fix some errors 2014-11-29 13:35:34 -05:00
Dan Mulloy 1f6b873f84 ChunkPosition was replaced by BlockPosition 2014-11-29 13:12:35 -05:00
Dan Mulloy d5a63e8e38 Update scm information in the pom.xml 2014-11-29 12:17:08 -05:00
Dan Mulloy 670e8f034c Fix players being disconnected on login 2014-11-29 11:58:43 -05:00
Dan Mulloy b9818cace7 Update some version stuff 2014-11-28 22:36:47 -05:00
Dan Mulloy bd8f2dcc41 Skip tests for now 2014-11-28 22:24:00 -05:00
Dan Mulloy 9b88847c28 Actually update to 1.8 2014-11-28 22:08:46 -05:00
Dan Mulloy 075ef28b5e Add libraries, update support URL 2014-11-28 11:29:49 -05:00
Dan Mulloy 077ea6ea08 Initial update to 1.8 - "It compiles" 2014-11-28 11:22:10 -05:00
341 changed files with 11670 additions and 6921 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:
+21 -8
View File
@@ -2,21 +2,25 @@
## Eclipse
#################
*.pydevproject
# Generic project files
.project
.metadata
.classpath
.settings/
bin/
.idea/
.iml
.ipr
.iws
*.pydevproject
.metadata
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
target/
.gitignore
# External tool builders
.externalToolBuilders/
@@ -30,6 +34,12 @@ target/
# PDT-specific
.buildpath
#################
## Maven
#################
target/
dependency-reduced-pom.xml
#################
## Visual Studio
@@ -155,11 +165,14 @@ pip-log.txt
.coverage
.tox
#Translations
# Translations
*.mo
#Mr Developer
# Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
# Log4J files
logs/
+13
View File
@@ -0,0 +1,13 @@
language: java
jdk:
- oraclejdk8
- oraclejdk7
script: mvn clean test
#before_install: cd ProtocolLib
install: true
notifications:
email:
recipients:
- "dmulloy2@live.com"
on_success: change
on_failure: always
-165
View File
@@ -1,165 +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
-72
View File
@@ -1,72 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.comphenix.itemdisguise</groupId>
<artifactId>ItemDisguise</artifactId>
<version>1.0.0</version>
<name>Item Disguise</name>
<description>Change the appearance of inventory items.</description>
<properties>
<project.build.sourceEncoding>cp1252</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>bukkit-rep</id>
<url>http://repo.bukkit.org/content/groups/public</url>
</repository>
<repository>
<id>comphenix-rep</id>
<name>Comphenix Maven Releases</name>
<url>http://repo.comphenix.net/content/groups/public</url>
</repository>
</repositories>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<scm>
<connection>scm:git:git://github.com/aadnk/ProtocolLib.git</connection>
<developerConnection>scm:git:git@github.com:aadnk/ProtocolLib.git</developerConnection>
<url>https://github.com/aadnk/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>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.3.2-R1.0</version>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>
@@ -1,122 +0,0 @@
/*
* ItemDisguise - A simple Bukkit plugin that illustrates how to use ProtocolLib.
* 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.itemdisguise;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Server;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
public class HideEnchantmentsListener {
private final Server server;
private final Logger logger;
public HideEnchantmentsListener(Server server, Logger logger) {
this.server = server;
this.logger = logger;
}
public void addListener(ProtocolManager protocolManager, JavaPlugin plugin) {
// Hide all enchantments
protocolManager.addPacketListener(new PacketAdapter(plugin, ConnectionSide.SERVER_SIDE, 0x67, 0x68, 0x3E) {
@Override
public void onPacketSending(PacketEvent event) {
PacketContainer packet = event.getPacket();
try {
// Item packets
switch (event.getPacketID()) {
case 0x67: // Set slot
removeEnchantments(packet.getItemModifier().read(0));
break;
case 0x68: // Set Window Items
ItemStack[] elements = packet.getItemArrayModifier().read(0);
for (int i = 0; i < elements.length; i++) {
if (elements[i] != null) {
removeEnchantments(elements[i]);
}
}
break;
case 0x3E: // Sound effect
event.setCancelled(true);
break;
}
} catch (FieldAccessException e) {
logger.log(Level.SEVERE, "Couldn't access field.", e);
}
}
});
// Censor
protocolManager.addPacketListener(new PacketAdapter(plugin, ConnectionSide.CLIENT_SIDE, 0x3) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (event.getPacketID() == 0x3) {
try {
String message = event.getPacket().
getSpecificModifier(String.class).read(0);
if (message.contains("shit") || message.contains("fuck")) {
event.setCancelled(true);
event.getPlayer().sendMessage("Bad manners!");
}
} catch (FieldAccessException e) {
logger.log(Level.SEVERE, "Couldn't access field.", e);
}
}
}
});
}
public Server getServer() {
return server;
}
public void removeListener(ProtocolManager protocolManager, JavaPlugin plugin) {
// Just remove every adapter with this plugin
protocolManager.removePacketListeners(plugin);
}
private void removeEnchantments(ItemStack stack) {
if (stack == null)
return;
Object[] copy = stack.getEnchantments().keySet().toArray();
for (Object enchantment : copy) {
stack.removeEnchantment((Enchantment) enchantment);
}
}
}
@@ -1,99 +0,0 @@
/*
* ItemDisguise - A simple Bukkit plugin that illustrates how to use ProtocolLib.
* 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.itemdisguise;
import java.util.logging.Logger;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
public class ItemDisguiseMod extends JavaPlugin {
private ProtocolManager protocolManager;
private Logger logger;
private HideEnchantmentsListener enchantmentsListener;
@Override
public void onEnable() {
logger = getLoggerSafely();
protocolManager = ProtocolLibrary.getProtocolManager();
enchantmentsListener = new HideEnchantmentsListener(getServer(), logger);
enchantmentsListener.addListener(protocolManager, this);
}
@Override
public void onDisable() {
enchantmentsListener.removeListener(protocolManager, this);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
if (label.equalsIgnoreCase("explosion")) {
PacketContainer fakeExplosion = protocolManager.createPacket(0x3C);
// Set the coordinates
try {
fakeExplosion.getSpecificModifier(double.class).
write(0, player.getLocation().getX()).
write(1, player.getLocation().getY()).
write(2, player.getLocation().getZ());
fakeExplosion.getSpecificModifier(float.class).
write(0, 3.0F);
protocolManager.sendServerPacket(player, fakeExplosion);
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
return false;
}
// Get the Bukkit logger first, before we try to create our own
private Logger getLoggerSafely() {
Logger log = null;
try {
log = getLogger();
} catch (Throwable e) {
// We'll handle it
}
if (log == null)
log = Logger.getLogger("Minecraft");
return log;
}
}
@@ -1,14 +0,0 @@
name: ItemDisguiseMod
version: 1.0.0
description: Change the appearance of inventory items.
author: Comphenix
website: http://www.comphenix.net/ItemDisguise
main: com.comphenix.itemdisguise.ItemDisguiseMod
depends: [ProtocolLib]
database: false
commands:
explosion:
description: Creates a fake explosion around the caller.
usage: /<command>
-165
View File
@@ -1,165 +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
@@ -1,375 +0,0 @@
package com.comphenix.tinyprotocol;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
/**
* An utility class that simplifies reflection in Bukkit plugins.
* @author Kristian
*/
public final class Reflection {
/**
* An interface for invoking a specific constructor.
*/
public interface ConstructorInvoker {
/**
* Invoke a constructor for a specific class.
* @param arguments - the arguments to pass to the constructor.
* @return The constructed object.
*/
public Object invoke(Object... arguments);
}
/**
* An interface for invoking a specific method.
*/
public interface MethodInvoker {
/**
* Invoke a method on a specific target object.
* @param target - the target object, or NULL for a static method.
* @param arguments - the arguments to pass to the method.
* @return The return value, or NULL if is void.
*/
public Object invoke(Object target, Object... arguments);
}
/**
* An interface for retrieving the field content.
* @param <T> - field type.
*/
public interface FieldAccessor<T> {
/**
* Retrieve the content of a field.
* @param target - the target object, or NULL for a static field.
* @return The value of the field.
*/
public T get(Object target);
/**
* Set the content of a field.
* @param target - the target object, or NULL for a static field.
* @param value - the new value of the field.
*/
public void set(Object target, Object value);
/**
* Determine if the given object has this field.
* @param target - the object to test.
* @return TRUE if it does, FALSE otherwise.
*/
public boolean hasField(Object target);
}
// Deduce the net.minecraft.server.v* package
private static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName();
private static String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server");
private static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "").replace(".", "");
// Variable replacement
private static Pattern MATCH_VARIABLE = Pattern.compile("\\{([^\\}]+)\\}");
private Reflection() {
// Seal class
}
/**
* Retrieve a field accessor for a specific field type and name.
* @param target - the target type.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType) {
return getField(target, name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, String name, Class<T> fieldType) {
return getField(getClass(className), name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
* @param target - the target type.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index) {
return getField(target, null, fieldType, index);
}
/**
* Retrieve a field accessor for a specific field type and name.
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, Class<T> fieldType, int index) {
return getField(getClass(className), fieldType, index);
}
// Common method
private static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType, int index) {
for (final Field field : target.getDeclaredFields()) {
if ((name == null || field.getName().equals(name)) &&
fieldType.isAssignableFrom(field.getType()) && index-- <= 0) {
field.setAccessible(true);
// A function for retrieving a specific field value
return new FieldAccessor<T>() {
@SuppressWarnings("unchecked")
@Override
public T get(Object target) {
try {
return (T) field.get(target);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access reflection.", e);
}
}
@Override
public void set(Object target, Object value) {
try {
field.set(target, value);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access reflection.", e);
}
}
@Override
public boolean hasField(Object target) {
// target instanceof DeclaringClass
return field.getDeclaringClass().isAssignableFrom(target.getClass());
}
};
}
}
// Search in parent classes
if (target.getSuperclass() != null)
return getField(target.getSuperclass(), name, fieldType, index);
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
}
/**
* Search for the first publically and privately defined method of the given name and parameter count.
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(String className, String methodName, Class<?>... params) {
return getTypedMethod(getClass(className), methodName, null, params);
}
/**
* Search for the first publically and privately defined method of the given name and parameter count.
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(Class<?> clazz, String methodName, Class<?>... params) {
return getTypedMethod(clazz, methodName, null, params);
}
/**
* Search for the first publically and privately defined method of the given name and parameter count.
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param returnType - the expected return type, or NULL to ignore.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
for (final Method method : clazz.getDeclaredMethods()) {
if ((methodName == null || method.getName().equals(methodName)) &&
(returnType == null) || method.getReturnType().equals(returnType) &&
Arrays.equals(method.getParameterTypes(), params)) {
method.setAccessible(true);
return new MethodInvoker() {
@Override
public Object invoke(Object target, Object... arguments) {
try {
return method.invoke(target, arguments);
} catch (Exception e) {
throw new RuntimeException("Cannot invoke method " + method, e);
}
}
};
}
}
// Search in every superclass
if (clazz.getSuperclass() != null)
return getMethod(clazz.getSuperclass(), methodName, params);
throw new IllegalStateException(String.format(
"Unable to find method %s (%s).", methodName, Arrays.asList(params)));
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(String className, Class<?>... params) {
return getConstructor(getClass(className), params);
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
* @param clazz - a class to start with.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(Class<?> clazz, Class<?>... params) {
for (final Constructor<?> constructor : clazz.getDeclaredConstructors()) {
if (Arrays.equals(constructor.getParameterTypes(), params)) {
constructor.setAccessible(true);
return new ConstructorInvoker() {
@Override
public Object invoke(Object... arguments) {
try {
return constructor.newInstance(arguments);
} catch (Exception e) {
throw new RuntimeException("Cannot invoke constructor " + constructor, e);
}
}
};
}
}
throw new IllegalStateException(String.format(
"Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
}
/**
* Retrieve a class from its full name, without knowing its type on compile time.
* <p>
* This is useful when looking up fields by a NMS or OBC type.
* <p>
* @see {@link #getClass()} for more information.
* @param lookupName - the class name with variables.
* @return The class.
*/
public static Class<Object> getUntypedClass(String lookupName) {
@SuppressWarnings({"rawtypes", "unchecked"})
Class<Object> clazz = (Class<Object>)(Class)getClass(lookupName);
return clazz;
}
/**
* Retrieve a class from its full name.
* <p>
* Strings enclosed with curly brackets - such as {TEXT} - will be replaced according
* to the following table:
* <p>
* <table border="1">
* <tr>
* <th>Variable</th>
* <th>Content</th>
* </tr>
* <tr>
* <td>{nms}</td>
* <td>Actual package name of net.minecraft.server.VERSION</td>
* </tr>
* <tr>
* <td>{obc}</td>
* <td>Actual pacakge name of org.bukkit.craftbukkit.VERSION</td>
* </tr>
* <tr>
* <td>{version}</td>
* <td>The current Minecraft package VERSION, if any.</td>
* </tr>
* </table>
* @param lookupName - the class name with variables.
* @return The looked up class.
* @throws IllegalArgumentException If a variable or class could not be found.
*/
public static Class<?> getClass(String lookupName) {
return getCanonicalClass(expandVariables(lookupName));
}
/**
* Retrieve a class in the net.minecraft.server.VERSION.* package.
* @param name - the name of the class, excluding the package.
* @throws IllegalArgumentException If the class doesn't exist.
*/
public static Class<?> getMinecraftClass(String name) {
return getCanonicalClass(NMS_PREFIX + "." + name);
}
/**
* Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package.
* @param name - the name of the class, excluding the package.
* @throws IllegalArgumentException If the class doesn't exist.
*/
public static Class<?> getCraftBukkitClass(String name) {
return getCanonicalClass(OBC_PREFIX + "." + name);
}
/**
* Retrieve a class by its canonical name.
* @param canonicalName - the canonical name.
* @return The class.
*/
private static Class<?> getCanonicalClass(String canonicalName) {
try {
return Class.forName(canonicalName);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Cannot find " + canonicalName, e);
}
}
/**
* Expand variables such as "{nms}" and "{obc}" to their corresponding packages.
* @param name - the full name of the class.
* @return The expanded string.
*/
private static String expandVariables(String name) {
StringBuffer output = new StringBuffer();
Matcher matcher = MATCH_VARIABLE.matcher(name);
while (matcher.find()) {
String variable = matcher.group(1);
String replacement = "";
// Expand all detected variables
if ("nms".equalsIgnoreCase(variable))
replacement = NMS_PREFIX;
else if ("obc".equalsIgnoreCase(variable))
replacement = OBC_PREFIX;
else if ("version".equalsIgnoreCase(variable))
replacement = VERSION;
else
throw new IllegalArgumentException("Unknown variable: " + variable);
// Assume the expanded variables are all packages, and append a dot
if (replacement.length() > 0 && matcher.end() < name.length() && name.charAt(matcher.end()) != '.')
replacement += ".";
matcher.appendReplacement(output, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(output);
return output.toString();
}
}
-165
View File
@@ -1,165 +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
@@ -1,146 +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 java.io.File;
import java.io.IOException;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.timing.TimedListenerManager;
import com.comphenix.protocol.timing.TimingReportGenerator;
/**
* Handles the "protocol" administration command.
*
* @author Kristian
*/
class CommandProtocol extends CommandBase {
/**
* Name of this command.
*/
public static final String NAME = "protocol";
private Plugin plugin;
private ProtocolConfig config;
public CommandProtocol(ErrorReporter reporter, Plugin plugin, ProtocolConfig config) {
super(reporter, CommandBase.PERMISSION_ADMIN, NAME, 1);
this.plugin = plugin;
this.config = config;
}
@Override
protected boolean handleCommand(CommandSender sender, String[] args) {
String subCommand = args[0];
// Only return TRUE if we executed the correct command
if (subCommand.equalsIgnoreCase("config") || subCommand.equalsIgnoreCase("reload"))
reloadConfiguration(sender);
else if (subCommand.equalsIgnoreCase("timings"))
toggleTimings(sender, args);
else if (subCommand.equalsIgnoreCase("listeners"))
printListeners(sender, args);
else
return false;
return true;
}
// Display every listener on the server
private void printListeners(final CommandSender sender, String[] args) {
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
for (PacketListener listener : manager.getPacketListeners()) {
sender.sendMessage(ChatColor.GOLD + "Packet listeners:");
sender.sendMessage(ChatColor.GOLD + " " + listener);
}
// Along with every asynchronous listener
for (PacketListener listener : manager.getAsynchronousManager().getAsyncHandlers()) {
sender.sendMessage(ChatColor.GOLD + "Asynchronous listeners:");
sender.sendMessage(ChatColor.GOLD + " " + listener);
}
}
private void toggleTimings(CommandSender sender, String[] args) {
TimedListenerManager manager = TimedListenerManager.getInstance();
boolean state = !manager.isTiming(); // toggle
// Parse the boolean parameter
if (args.length == 2) {
Boolean parsed = parseBoolean(toQueue(args, 2), "start");
if (parsed != null) {
state = parsed;
} else {
sender.sendMessage(ChatColor.RED + "Specify a state: ON or OFF.");
return;
}
} else if (args.length > 2) {
sender.sendMessage(ChatColor.RED + "Too many parameters.");
return;
}
// Now change the state
if (state) {
if (manager.startTiming())
sender.sendMessage(ChatColor.GOLD + "Started timing packet listeners.");
else
sender.sendMessage(ChatColor.RED + "Packet timing already started.");
} else {
if (manager.stopTiming()) {
saveTimings(manager);
sender.sendMessage(ChatColor.GOLD + "Stopped and saved result in plugin folder.");
} else {
sender.sendMessage(ChatColor.RED + "Packet timing already stopped.");
}
}
}
private void saveTimings(TimedListenerManager manager) {
try {
File destination = new File(plugin.getDataFolder(), "Timings - " + System.currentTimeMillis() + ".txt");
TimingReportGenerator generator = new TimingReportGenerator();
// Print to a text file
generator.saveTo(destination, manager);
manager.clear();
} catch (IOException e) {
reporter.reportMinimal(plugin, "saveTimings()", e);
}
}
/**
* Prevent further automatic updates until the next delay.
*/
public void updateFinished() {
long currentTime = System.currentTimeMillis() / ProtocolLibrary.MILLI_PER_SECOND;
config.setAutoLastTime(currentTime);
config.saveAll();
}
public void reloadConfiguration(CommandSender sender) {
plugin.reloadConfig();
sender.sendMessage(ChatColor.YELLOW + "Reloaded configuration!");
}
}
@@ -1,27 +0,0 @@
package com.comphenix.protocol.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicate that this API and its descendants are only valid on Spigot.
* @author Kristian
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PACKAGE,
ElementType.PARAMETER, ElementType.TYPE, ElementType.FIELD})
public @interface Spigot {
/**
* The minimum build number of Spigot where this is valid.
* @return The minimum build.
*/
int minimumBuild();
/**
* The maximum build number of Spigot where this is valid, or Integer.MAX_VALUE if not set.
* @return The maximum build number.
*/
int maximumBuild() default Integer.MAX_VALUE;
}
@@ -1,400 +0,0 @@
package com.comphenix.protocol.injector.netty;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Set;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelFuture;
import net.minecraft.util.io.netty.channel.ChannelHandler;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelInboundHandler;
import net.minecraft.util.io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.util.io.netty.channel.ChannelInitializer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.concurrency.PacketTypeSet;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.ListenerOptions;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
import com.comphenix.protocol.injector.spigot.AbstractPacketInjector;
import com.comphenix.protocol.injector.spigot.AbstractPlayerHandler;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Lists;
public class NettyProtocolInjector implements ChannelListener {
public static final ReportType REPORT_CANNOT_INJECT_INCOMING_CHANNEL = new ReportType("Unable to inject incoming channel %s.");
private volatile boolean injected;
private volatile boolean closed;
// The temporary player factory
private TemporaryPlayerFactory playerFactory = new TemporaryPlayerFactory();
private List<VolatileField> bootstrapFields = Lists.newArrayList();
// The channel injector factory
private InjectionFactory injectionFactory;
// List of network managers
private volatile List<Object> networkManagers;
// Different sending filters
private PacketTypeSet sendingFilters = new PacketTypeSet();
private PacketTypeSet reveivedFilters = new PacketTypeSet();
// Packets that must be executed on the main thread
private PacketTypeSet mainThreadFilters = new PacketTypeSet();
// Which packets are buffered
private PacketTypeSet bufferedPackets = new PacketTypeSet();
private ListenerInvoker invoker;
// Handle errors
private ErrorReporter reporter;
private boolean debug;
public NettyProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter) {
this.injectionFactory = new InjectionFactory(plugin);
this.invoker = invoker;
this.reporter = reporter;
}
@Override
public boolean isDebug() {
return debug;
}
/**
* Set whether or not the debug mode is enabled.
* @param debug - TRUE if it is, FALSE otherwise.
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* Inject into the spigot connection class.
*/
@SuppressWarnings("unchecked")
public synchronized void inject() {
if (injected)
throw new IllegalStateException("Cannot inject twice.");
try {
FuzzyReflection fuzzyServer = FuzzyReflection.fromClass(MinecraftReflection.getMinecraftServerClass());
List<Method> serverConnectionMethods = fuzzyServer.getMethodListByParameters(MinecraftReflection.getServerConnectionClass(), new Class[] {});
// Get the server connection
Object server = fuzzyServer.getSingleton();
Object serverConnection = null;
for (Method method : serverConnectionMethods) {
try {
serverConnection = method.invoke(server);
// Continue until we get a server connection
if (serverConnection != null) {
break;
}
} catch (Exception e) {
// Try the next though
e.printStackTrace();
}
}
// Handle connected channels
final ChannelInboundHandler endInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
injectionFactory.fromChannel(channel, NettyProtocolInjector.this, playerFactory).inject();
}
} catch (Exception e) {
reporter.reportDetailed(NettyProtocolInjector.this, Report.newBuilder(REPORT_CANNOT_INJECT_INCOMING_CHANNEL).
messageParam(channel).error(e));
}
}
};
// This is executed before Minecraft's channel handler
final ChannelInboundHandler beginInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
// Our only job is to add init protocol
channel.pipeline().addLast(endInitProtocol);
}
};
// Add our handler to newly created channels
final ChannelHandler connectionHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg;
// Prepare to initialize ths channel
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
// Get the current NetworkMananger list
networkManagers = (List<Object>) FuzzyReflection.fromObject(serverConnection, true).
invokeMethod(null, "getNetworkManagers", List.class, serverConnection);
// Insert ProtocolLib's connection interceptor
bootstrapFields = getBootstrapFields(serverConnection);
for (VolatileField field : bootstrapFields) {
final List<Object> list = (List<Object>) field.getValue();
// We don't have to override this list
if (list == networkManagers) {
continue;
}
// Synchronize with each list before we attempt to replace them.
field.setValue(new BootstrapList(list, connectionHandler));
}
injected = true;
} catch (Exception e) {
throw new RuntimeException("Unable to inject channel futures.", e);
}
}
@Override
public boolean hasListener(Class<?> packetClass) {
return reveivedFilters.contains(packetClass) || sendingFilters.contains(packetClass);
}
@Override
public boolean hasMainThreadListener(Class<?> packetClass) {
return mainThreadFilters.contains(packetClass);
}
@Override
public ErrorReporter getReporter() {
return reporter;
}
/**
* Inject our packet handling into a specific player.
* @param player
*/
public void injectPlayer(Player player) {
injectionFactory.fromPlayer(player, this).inject();
}
private List<VolatileField> getBootstrapFields(Object serverConnection) {
List<VolatileField> result = Lists.newArrayList();
// Find and (possibly) proxy every list
for (Field field : FuzzyReflection.fromObject(serverConnection, true).getFieldListByType(List.class)) {
VolatileField volatileField = new VolatileField(field, serverConnection, true).toSynchronized();
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>) volatileField.getValue();
if (list.size() == 0 || list.get(0) instanceof ChannelFuture) {
result.add(volatileField);
}
}
return result;
}
/**
* Clean up any remaning injections.
*/
public synchronized void close() {
if (!closed) {
closed = true;
for (VolatileField field : bootstrapFields) {
Object value = field.getValue();
// Undo the processed channels, if any
if (value instanceof BootstrapList) {
((BootstrapList) value).close();
}
field.revertValue();
}
// Uninject all the players
injectionFactory.close();
}
}
@Override
public PacketEvent onPacketSending(Injector injector, Object packet, NetworkMarker marker) {
Class<?> clazz = packet.getClass();
if (sendingFilters.contains(clazz) || marker != null) {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetQueued(container, injector.getPlayer(), marker);
}
// Don't change anything
return null;
}
@Override
public PacketEvent onPacketReceiving(Injector injector, Object packet, NetworkMarker marker) {
Class<?> clazz = packet.getClass();
if (reveivedFilters.contains(clazz) || marker != null) {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetReceived(container, injector.getPlayer(), marker);
}
// Don't change anything
return null;
}
@Override
public boolean includeBuffer(Class<?> packetClass) {
return bufferedPackets.contains(packetClass);
}
/**
* Called to inform the event listeners of a queued packet.
* @param packet - the packet that is to be sent.
* @param receiver - the receiver of this packet.
* @return The packet event that was used.
*/
private PacketEvent packetQueued(PacketContainer packet, Player receiver, NetworkMarker marker) {
PacketEvent event = PacketEvent.fromServer(this, packet, marker, receiver);
invoker.invokePacketSending(event);
return event;
}
/**
* Called to inform the event listeners of a received packet.
* @param packet - the packet that has been receieved.
* @param sender - the client packet.
* @param marker - the network marker.
* @return The packet event that was used.
*/
private PacketEvent packetReceived(PacketContainer packet, Player sender, NetworkMarker marker) {
PacketEvent event = PacketEvent.fromClient(this, packet, marker, sender);
invoker.invokePacketRecieving(event);
return event;
}
// Server side
public PlayerInjectionHandler getPlayerInjector() {
return new AbstractPlayerHandler(sendingFilters) {
private ChannelListener listener = NettyProtocolInjector.this;
@Override
public int getProtocolVersion(Player player) {
return injectionFactory.fromPlayer(player, listener).getProtocolVersion();
}
@Override
public void updatePlayer(Player player) {
injectionFactory.fromPlayer(player, listener).inject();
}
@Override
public void injectPlayer(Player player, ConflictStrategy strategy) {
injectionFactory.fromPlayer(player, listener).inject();
}
@Override
public boolean uninjectPlayer(InetSocketAddress address) {
// Ignore this too
return true;
}
@Override
public void addPacketHandler(PacketType type, Set<ListenerOptions> options) {
if (options != null && !options.contains(ListenerOptions.ASYNC))
mainThreadFilters.addType(type);
super.addPacketHandler(type, options);
}
@Override
public void removePacketHandler(PacketType type) {
mainThreadFilters.removeType(type);
super.removePacketHandler(type);
}
@Override
public boolean uninjectPlayer(Player player) {
// Just let Netty clean this up
return true;
}
@Override
public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
injectionFactory.fromPlayer(receiver, listener).
sendServerPacket(packet.getHandle(), marker, filters);
}
@Override
public boolean hasMainThreadListener(PacketType type) {
return mainThreadFilters.contains(type);
}
@Override
public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
injectionFactory.fromPlayer(player, listener).
recieveClientPacket(mcPacket);
}
@Override
public PacketEvent handlePacketRecieved(PacketContainer packet, InputStream input, byte[] buffered) {
// Ignore this
return null;
}
@Override
public void handleDisconnect(Player player) {
injectionFactory.fromPlayer(player, listener).close();
}
};
}
/**
* Retrieve a view of this protocol injector as a packet injector.
* @return The packet injector.
*/
// Client side
public PacketInjector getPacketInjector() {
return new AbstractPacketInjector(reveivedFilters) {
@Override
public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) {
NetworkMarker marker = buffered != null ? new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, buffered) : null;
injectionFactory.fromPlayer(client, NettyProtocolInjector.this).
saveMarker(packet.getHandle(), marker);
return packetReceived(packet, client, marker);
}
@Override
public void inputBuffersChanged(Set<PacketType> set) {
bufferedPackets = new PacketTypeSet(set);
}
};
}
}
@@ -1,37 +0,0 @@
package com.comphenix.protocol.utility;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
* Utility methods relating to Bukkit.
* @author dmulloy2
*/
public class BukkitUtil {
private static Method getOnlinePlayers;
/**
* Gets a list of online {@link Player}s. This also provides backwards
* compatibility as Bukkit changed <code>getOnlinePlayers</code>.
*
* @return A list of online Players
*/
@SuppressWarnings("unchecked")
public static List<Player> getOnlinePlayers() {
try {
if (getOnlinePlayers == null)
getOnlinePlayers = Bukkit.class.getMethod("getOnlinePlayers");
if (getOnlinePlayers.getReturnType() != Collection.class)
return Arrays.asList((Player[]) getOnlinePlayers.invoke(null));
} catch (Throwable ex) {
}
return (List<Player>) Bukkit.getOnlinePlayers();
}
}
@@ -1,182 +0,0 @@
package com.comphenix.protocol.wrappers;
import java.util.Map;
import org.bukkit.GameMode;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Maps;
/**
* Represents a generic enum converter.
* @author Kristian
*/
public abstract class EnumWrappers {
public enum ClientCommand {
PERFORM_RESPAWN,
REQUEST_STATS,
OPEN_INVENTORY_ACHIEVEMENT;
}
public enum ChatVisibility {
FULL,
SYSTEM,
HIDDEN;
}
public enum Difficulty {
PEACEFUL,
EASY,
NORMAL,
HARD;
}
public enum EntityUseAction {
INTERACT,
ATTACK;
}
/**
* Represents a native game mode in Minecraft.
* <p>
* Not to be confused with {@link GameMode} in Bukkit.
* @author Kristian
*/
public enum NativeGameMode {
NONE,
SURVIVAL,
CREATIVE,
ADVENTURE;
}
private static Class<?> PROTOCOL_CLASS = null;
private static Class<?> CLIENT_COMMAND_CLASS = null;
private static Class<?> CHAT_VISIBILITY_CLASS = null;
private static Class<?> DIFFICULTY_CLASS = null;
private static Class<?> ENTITY_USE_ACTION_CLASS = null;
private static Class<?> GAMEMODE_CLASS = null;
private static Map<Class<?>, EquivalentConverter<?>> FROM_NATIVE = Maps.newHashMap();
private static Map<Class<?>, EquivalentConverter<?>> FROM_WRAPPER = Maps.newHashMap();
/**
* Initialize the wrappers, if we haven't already.
*/
private static void initialize() {
if (!MinecraftReflection.isUsingNetty())
throw new IllegalArgumentException("Not supported on 1.6.4 and earlier.");
PROTOCOL_CLASS = getEnum(PacketType.Handshake.Client.SET_PROTOCOL.getPacketClass(), 0);
CLIENT_COMMAND_CLASS = getEnum(PacketType.Play.Client.CLIENT_COMMAND.getPacketClass(), 0);
CHAT_VISIBILITY_CLASS = getEnum(PacketType.Play.Client.SETTINGS.getPacketClass(), 0);
DIFFICULTY_CLASS = getEnum(PacketType.Play.Client.SETTINGS.getPacketClass(), 1);
ENTITY_USE_ACTION_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 0);
GAMEMODE_CLASS = getEnum(PacketType.Play.Server.LOGIN.getPacketClass(), 0);
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
associate(CHAT_VISIBILITY_CLASS, ChatVisibility.class, getChatVisibilityConverter());
associate(DIFFICULTY_CLASS, Difficulty.class, getDifficultyConverter());
associate(ENTITY_USE_ACTION_CLASS, EntityUseAction.class, getEntityUseActionConverter());
associate(GAMEMODE_CLASS, NativeGameMode.class, getGameModeConverter());
}
private static void associate(Class<?> nativeClass, Class<?> wrapperClass, EquivalentConverter<?> converter) {
FROM_NATIVE.put(nativeClass, converter);
FROM_WRAPPER.put(wrapperClass, converter);
}
/**
* Retrieve the enum field with the given declaration index (in relation to the other enums).
* @param clazz - the declaration class.
* @param index - the enum index.
* @return The type of the enum field.
*/
private static Class<?> getEnum(Class<?> clazz, int index) {
return FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class).get(index).getType();
}
public static Map<Class<?>, EquivalentConverter<?>> getFromNativeMap() {
return FROM_NATIVE;
}
public static Map<Class<?>, EquivalentConverter<?>> getFromWrapperMap() {
return FROM_WRAPPER;
}
// Get the native enum classes
public static Class<?> getProtocolClass() {
initialize();
return PROTOCOL_CLASS;
}
public static Class<?> getClientCommandClass() {
initialize();
return CLIENT_COMMAND_CLASS;
}
public static Class<?> getChatVisibilityClass() {
initialize();
return CHAT_VISIBILITY_CLASS;
}
public static Class<?> getDifficultyClass() {
initialize();
return DIFFICULTY_CLASS;
}
public static Class<?> getEntityUseActionClass() {
initialize();
return ENTITY_USE_ACTION_CLASS;
}
public static Class<?> getGameModeClass() {
initialize();
return GAMEMODE_CLASS;
}
// Get the converters
public static EquivalentConverter<Protocol> getProtocolConverter() {
return new EnumConverter<Protocol>(Protocol.class);
}
public static EquivalentConverter<ClientCommand> getClientCommandConverter() {
return new EnumConverter<ClientCommand>(ClientCommand.class);
}
public static EquivalentConverter<ChatVisibility> getChatVisibilityConverter() {
return new EnumConverter<ChatVisibility>(ChatVisibility.class);
}
public static EquivalentConverter<Difficulty> getDifficultyConverter() {
return new EnumConverter<Difficulty>(Difficulty.class);
}
public static EquivalentConverter<EntityUseAction> getEntityUseActionConverter() {
return new EnumConverter<EntityUseAction>(EntityUseAction.class);
}
public static EquivalentConverter<NativeGameMode> getGameModeConverter() {
return new EnumConverter<NativeGameMode>(NativeGameMode.class);
}
// The common enum converter
@SuppressWarnings({"rawtypes", "unchecked"})
private static class EnumConverter<T extends Enum<T>> implements EquivalentConverter<T> {
private Class<T> specificType;
public EnumConverter(Class<T> specificType) {
this.specificType = specificType;
}
@Override
public T getSpecific(Object generic) {
// We know its an enum already!
return Enum.valueOf(specificType, ((Enum) generic).name());
}
@Override
public Object getGeneric(Class<?> genericType, T specific) {
return Enum.valueOf((Class) genericType, specific.name());
}
@Override
public Class<T> getSpecificType() {
return specificType;
}
}
}
@@ -1,939 +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.annotations.Spigot;
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 Spigot #1628 and above.
* @author Kristian
*/
@Spigot(minimumBuild = 1628)
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) {
// System.out.println("[ProtocolLib] 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.
*/
@Spigot(minimumBuild = 1628)
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.
* @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.
* @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 {
// The get method will take care of concurrency
WrappedWatchableObject object = getWrappedObject(index);
return object != null ? object.getValue() : null;
}
/**
* Retrieve the wrapped object by index.
* @param index - the index.
* @return The corresponding wrapper, or NULL.
*/
@Spigot(minimumBuild = 1628)
public WrappedWatchableObject getWrappedObject(int index) {
// The get method will take care of concurrency
Object watchable = getWatchedObject(index);
if (watchable != null) {
return new WrappedWatchableObject(watchable);
} 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.
* @throws FieldAccessException Cannot read underlying field.
*/
@Spigot(minimumBuild = 1628)
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,466 +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.annotations.Spigot;
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.comphenix.protocol.wrappers.WrappedDataWatcher.CustomType;
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.
*/
@Spigot(minimumBuild = 1628)
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.
*/
@Spigot(minimumBuild = 1628)
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.
* <p>
* <table border=1>
* <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.
* @see {@link #getTypeID()} for more information.
* @param id - the new ID.
* @throws FieldAccessException Reflection failed.
*/
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.
*/
@Spigot(minimumBuild = 1628)
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.
*/
@Spigot(minimumBuild = 1628)
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.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 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(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.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,73 +0,0 @@
package com.comphenix.protocol;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import net.minecraft.server.v1_7_R4.Block;
import net.minecraft.server.v1_7_R4.Item;
import net.minecraft.server.v1_7_R4.StatisticList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemFactory;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.meta.ItemMeta;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.utility.MinecraftReflection;
// Will have to be updated for every version though
/**
* Used to ensure that ProtocolLib and Bukkit is prepared to be tested.
*
* @author Kristian
*/
public class BukkitInitialization {
private static boolean initialized;
/**
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing.
* @throws IllegalAccessException If we are unable to initialize Bukkit.
*/
public static void initializeItemMeta() throws IllegalAccessException {
if (!initialized) {
// Denote that we're done
initialized = true;
initializePackage();
try {
Block.p();
Item.l();
StatisticList.a();
} catch (Exception e) {
// Swallow
e.printStackTrace();
}
// Mock the server object
Server mockedServer = mock(Server.class);
ItemFactory mockedFactory = mock(CraftItemFactory.class);
ItemMeta mockedMeta = mock(ItemMeta.class);
when(mockedServer.getItemFactory()).thenReturn(mockedFactory);
when(mockedServer.isPrimaryThread()).thenReturn(true);
when(mockedFactory.getItemMeta(any(Material.class))).thenReturn(mockedMeta);
// Inject this fake server
FieldUtils.writeStaticField(Bukkit.class, "server", mockedServer, true);
// And the fake item factory
FieldUtils.writeStaticField(CraftItemFactory.class, "instance", mockedFactory, true);
}
}
/**
* Ensure that package names are correctly set up.
*/
public static void initializePackage() {
// Initialize reflection
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_7_R4", "org.bukkit.craftbukkit.v1_7_R4");
}
}
@@ -1,21 +0,0 @@
package com.comphenix.protocol;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
public class PacketTypeTest {
@BeforeClass
public static void initializeReflection() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
@Test
public void testFindCurrent() {
assertEquals(PacketType.Play.Client.STEER_VEHICLE, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, 12));
}
}
@@ -1,111 +0,0 @@
package com.comphenix.protocol.utility;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import net.minecraft.server.v1_7_R4.ChatComponentText;
import net.minecraft.server.v1_7_R4.ChatSerializer;
import net.minecraft.server.v1_7_R4.IChatBaseComponent;
import net.minecraft.server.v1_7_R4.ServerPing;
import net.minecraft.server.v1_7_R4.ServerPingPlayerSample;
import net.minecraft.server.v1_7_R4.ServerPingServerData;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
import com.google.common.collect.Maps;
public class MinecraftReflectionTest {
// Mocking objects
private interface FakeEntity {
public Entity getBukkitEntity();
}
private interface FakeBlock {
public Block getBukkitEntity();
}
@BeforeClass
public static void initializeReflection() throws IllegalAccessException {
BukkitInitialization.initializePackage();
// Set up a package with no class loader knowledge
MinecraftReflection.minecraftPackage = new CachedPackage(
MinecraftReflection.getMinecraftPackage(),
ClassSource.fromMap(Maps.<String, Class<?>>newHashMap())
);
}
@AfterClass
public static void undoMocking() {
// NOP
MinecraftReflection.minecraftPackage = null;
}
@Test
public void testBukkitMethod() {
FakeEntity entity = mock(FakeEntity.class);
FakeBlock block = mock(FakeBlock.class);
MinecraftReflection.getBukkitEntity(entity);
MinecraftReflection.getBukkitEntity(block);
verify(entity, times(1)).getBukkitEntity();
verify(block, times(1)).getBukkitEntity();
}
@Test(expected = IllegalArgumentException.class)
public void testIllegalClass() {
MinecraftReflection.getBukkitEntity("Hello");
}
// @Test
// public void testNbtStreamTools() {
// assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
// }
@Test
public void testChatComponent() {
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass());
}
@Test
public void testChatComponentText() {
assertEquals(ChatComponentText.class, MinecraftReflection.getChatComponentTextClass());
}
@Test
public void testChatSerializer() {
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
}
@Test
public void testServerPing() {
assertEquals(ServerPing.class, MinecraftReflection.getServerPingClass());
}
@Test
public void testServerPingPlayerSample() {
assertEquals(ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
}
@Test
public void testServerPingServerData() {
assertEquals(ServerPingServerData.class, MinecraftReflection.getServerPingServerDataClass());
}
// @Test
// public void testChunkCoordIntPair() {
// assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair());
// }
// @Test
// public void testWatchableObject() {
// assertEquals(WatchableObject.class, MinecraftReflection.getWatchableObjectClass());
// }
}
@@ -1,24 +0,0 @@
package com.comphenix.protocol.wrappers;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
public class WrappedChunkCoordinateTest {
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
@Test
public void test() {
WrappedChunkCoordinate coordinate = new WrappedChunkCoordinate(1, 2, 3);
assertEquals(1, coordinate.getX());
assertEquals(2, coordinate.getY());
assertEquals(3, coordinate.getZ());
}
}
@@ -1,33 +0,0 @@
package com.comphenix.protocol.wrappers;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
import com.google.common.base.Charsets;
public class WrappedGameProfileTest {
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
@SuppressWarnings("deprecation")
@Test
public void testSkinUpdate() {
final UUID uuid = UUID.nameUUIDFromBytes("123".getBytes(Charsets.UTF_8));
assertEquals(null, new WrappedGameProfile((String)null, "Test").getId());
assertEquals(uuid, new WrappedGameProfile("123", "Test").getUUID());
}
@SuppressWarnings("deprecation")
@Test(expected = IllegalArgumentException.class)
public void testNullFailure() {
new WrappedGameProfile((String)null, null);
}
}
@@ -1,37 +0,0 @@
package com.comphenix.protocol.wrappers;
import org.junit.BeforeClass;
import com.comphenix.protocol.BukkitInitialization;
public class WrappedServerPingTest {
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
// @Test
// public void test() throws IOException {
// CompressedImage tux = CompressedImage.fromPng(Resources.getResource("tux.png").openStream());
// byte[] original = tux.getDataCopy();
//
// WrappedServerPing serverPing = new WrappedServerPing();
// serverPing.setMotD("Hello, this is a test.");
// serverPing.setPlayersOnline(5);
// serverPing.setPlayersMaximum(10);
// serverPing.setVersionName("Minecraft 123");
// serverPing.setVersionProtocol(4);
// serverPing.setFavicon(tux);
//
// assertEquals(5, serverPing.getPlayersOnline());
// assertEquals(10, serverPing.getPlayersMaximum());
// assertEquals("Minecraft 123", serverPing.getVersionName());
// assertEquals(4, serverPing.getVersionProtocol());
//
// assertArrayEquals(original, serverPing.getFavicon().getData());
//
// CompressedImage copy = CompressedImage.fromBase64Png(Base64Coder.encodeLines(tux.getData()));
// assertArrayEquals(copy.getData(), serverPing.getFavicon().getData());
// }
}
+38 -26
View File
@@ -1,5 +1,4 @@
ProtocolLib
===========
# ProtocolLib [![Travis Status](https://travis-ci.org/dmulloy2/ProtocolLib.svg?branch=master)](https://travis-ci.org/dmulloy2/ProtocolLib)
Certain tasks are impossible to perform with the standard Bukkit API, and may require
working with and even modify Minecraft directly. A common technique is to modify incoming
@@ -11,42 +10,55 @@ Critically, different plugins that use this approach may _hook_ into the same cl
with unpredictable outcomes. More than often this causes plugins to crash, but it may also
lead to more subtle bugs.
Currently maintained by dmulloy2 on behalf of [SpigotMC](http://www.spigotmc.org/)
Currently maintained by dmulloy2 on behalf of [Spigot](http://www.spigotmc.org/).
### Resources
* [Downloads](http://ci.shadowvolt.com/job/ProtocolLib)
* [JavaDoc](http://ci.shadowvolt.com/job/ProtocolLib/javadoc)
* [Resource Page](http://www.spigotmc.org/resources/protocollib.1997/)
* [Dev Builds](http://ci.dmulloy2.net/job/ProtocolLib)
* [JavaDoc](http://ci.dmulloy2.net/job/ProtocolLib/javadoc)
### Compilation
Building
--------
You can compile this project yourself by using the latest version of Maven.
ProtocolLib is built with Maven and requires Spigot and SpigotAPI, which can be found [here](http://www.spigotmc.org/wiki/buildtools/).
A new API
---------
### A new API
__ProtocolLib__ attempts to solve this problem by providing a event API, much like Bukkit,
that allow plugins to monitor, modify or cancel packets sent and received. But more importantly,
that allows plugins to monitor, modify, or cancel packets sent and received. But, more importantly,
the API also hides all the gritty, obfuscated classes with a simple index based read/write system.
You no longer have to reference CraftBukkit!
### Using ProtocolLib
To use the library, first add ProtocolLib.jar to your Java build path. Then, add ProtocolLib
as a dependency (or soft-dependency, if you can live without it) to your plugin.yml file:
To use this library, first add ProtocolLib.jar to your Java build path. Then, add ProtocolLib
as a dependency or soft dependency to your plugin.yml file like any other plugin:
````yml
depends: [ProtocolLib]
depend: [ProtocolLib]
````
Future versions will be available in a public Maven repository, possibly on Maven central. But it
will always be possible to reference ProtocolLib manually.
You can also add ProtocolLib as a Maven dependency:
Then get a reference to ProtocolManager in onLoad() and you're good to go.
````xml
<repositories>
<repository>
<id>dmulloy2-repo</id>
<url>http://repo.dmulloy2.net/content/groups/public/</url>
</repository>
...
</repository>
<dependencies>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>
````
Then get a reference to ProtocolManager in onLoad() or onEnable() and you're good to go.
````java
private ProtocolManager protocolManager;
@@ -119,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()).
@@ -133,19 +146,18 @@ try {
}
````
Compatiblity
------------
### Compatibility
One of the main goals of this project was to achieve maximum compatibility with CraftBukkit. And the end
result is quite flexible - in tests I successfully ran an unmodified ProtocolLib on CraftBukkit 1.8.0, and
it should be resiliant against future changes. It's likely that I won't have to update ProtocolLib for
anything but bug and performance fixes.
result is quite flexible. Aside from netty package changes, it should be resilient against future changes.
It's likely that I won't have to update ProtocolLib for anything but bug fixes and new features.
How is this possible? It all comes down to reflection in the end. Essentially, no name is hard coded -
every field, method and class is deduced by looking at field types, package names or parameter
types. It's remarkably consistent across different versions.
### Incompatiblity
### Incompatibility
The following plugins (to be expanded) are not compatible with ProtocolLib:
* TagAPI
+245
View File
@@ -0,0 +1,245 @@
<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>4.0</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>
</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.7</source>
<target>1.7</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.version}${project.build.number}</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>
</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>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>
<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>
<dependencies>
<!-- Included with Minecraft
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.23.Final</version>
</dependency>
-->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.9.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.9.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -52,7 +52,7 @@ public interface AsynchronousManager {
/**
* Unregisters and closes the first asynchronous handler associated with the given listener.
* @param handler - asynchronous handler.
* @param listener - asynchronous listener
*/
public abstract void unregisterAsyncHandler(PacketListener listener);
@@ -63,7 +63,7 @@ public interface AsynchronousManager {
public void unregisterAsyncHandlers(Plugin plugin);
/**
* Retrieves a immutable set containing the ID of the sent server packets that will be
* Retrieves a immutable set containing the ID of the sent server packets that will be
* observed by the asynchronous listeners.
* <p>
* Deprecated: Use {@link #getSendingTypes()} instead.
@@ -73,7 +73,7 @@ public interface AsynchronousManager {
public abstract Set<Integer> getSendingFilters();
/**
* Retrieves a immutable set containing the types of the sent server packets that will be
* Retrieves a immutable set containing the types of the sent server packets that will be
* observed by the asynchronous listeners.
* @return Every filtered server packet.
*/
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -24,6 +24,7 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.injector.netty.WirePacket;
/**
* Represents a object capable of sending or receiving packets.
@@ -37,7 +38,7 @@ public interface PacketStream {
* @param packet - packet to send.
* @throws InvocationTargetException - if an error occured when sending the packet.
*/
public void sendServerPacket(Player receiver, PacketContainer packet)
public void sendServerPacket(Player receiver, PacketContainer packet)
throws InvocationTargetException;
/**
@@ -61,6 +62,22 @@ public interface PacketStream {
public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters)
throws InvocationTargetException;
/**
* Send a wire packet to the given player.
* @param receiver - the receiver.
* @param id - packet id.
* @param bytes - packet bytes.
* @throws InvocationTargetException if an error occured when sending the packet.
*/
public void sendWirePacket(Player receiver, int id, byte[] bytes) throws InvocationTargetException;
/**
* Send a wire packet to the given player.
* @param receiver - the receiver.
* @param packet - packet to send.
* @throws InvocationTargetException if an error occured when sending the packet.
*/
public void sendWirePacket(Player receiver, WirePacket packet) throws InvocationTargetException;
/**
* Simulate recieving a certain packet from a given player.
@@ -69,7 +86,7 @@ public interface PacketStream {
* @throws InvocationTargetException If the reflection machinery failed.
* @throws IllegalAccessException If the underlying method caused an error.
*/
public void recieveClientPacket(Player sender, PacketContainer packet)
public void recieveClientPacket(Player sender, PacketContainer packet)
throws IllegalAccessException, InvocationTargetException;
/**
@@ -4,13 +4,15 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Bukkit;
import com.comphenix.protocol.annotations.Spigot;
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;
@@ -26,14 +28,13 @@ import com.google.common.util.concurrent.Futures;
/**
* Represents the type of a packet in a specific protocol.
* <p>
* Note that vanilla Minecraft reuses packet IDs per protocol (ping, game, login), so you cannot
* rely on IDs alone.
* 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> {
// Increment whenever the type changes
private static final long serialVersionUID = 1L;
/**
* Represents an unknown legacy packet ID.
*/
@@ -52,10 +53,8 @@ public class PacketType implements Serializable, Comparable<PacketType> {
*/
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
/**
* Legacy name: HANDSHAKE.
*/
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 2);
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "SetProtocol");
private final static Client INSTANCE = new Client();
@@ -106,86 +105,106 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Server extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0);
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x01, 1);
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x02, 3);
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x03, 4);
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x04, 5);
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x05, 6);
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x06, 8);
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x07, 9);
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x08, 13);
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16);
/**
* Note that this was Packets.Server.ENTITY_LOCATION_ACTION.
*/
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x0A, 17);
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0B, 18);
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x0C, 20);
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x0D, 22);
public static final PacketType SPAWN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0E, 23);
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x0F, 24);
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x10, 25);
public static final PacketType SPAWN_ENTITY_EXPERIENCE_ORB =
new PacketType(PROTOCOL, SENDER, 0x11, 26);
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x12, 28);
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x13, 29);
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x14, 30);
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x15, 31);
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x16, 32);
public static final PacketType ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x17, 33);
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x18, 34);
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x19, 35);
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1A, 38);
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x1B, 39);
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x1C, 40);
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1D, 41);
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1E, 42);
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x1F, 43);
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x20, 44);
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x21, 51);
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x22, 52);
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x23, 53);
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x24, 54);
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x25, 55);
public static final PacketType MAP_CHUNK_BULK = new PacketType(PROTOCOL, SENDER, 0x26, 56);
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x27, 60);
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x28, 61);
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x29, 62);
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x2A, 63);
/**
* Note that this was Packets.Server.BED.
*/
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x2B, 70);
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x2C, 71);
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2D, 100);
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2E, 101);
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x2F, 103);
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x30, 104);
public static final PacketType CRAFT_PROGRESS_BAR = new PacketType(PROTOCOL, SENDER, 0x31, 105);
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x32, 106);
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x33, 130);
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x34, 131);
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x35, 132);
public static final PacketType OPEN_SIGN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x36, 133);
public static final PacketType STATISTICS = new PacketType(PROTOCOL, SENDER, 0x37, 200);
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x38, 201);
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x39, 202);
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x3A, 203);
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x3B, 206);
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x3C, 207);
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE =
new PacketType(PROTOCOL, SENDER, 0x3D, 208);
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x3E, 209);
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x3F, 250);
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x40, 255);
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 REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x25, 0x15, "RelEntityMove");
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x26, 0x17, "RelEntityMoveLook");
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x27, 0x16, "EntityLook");
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x28, 0x14, "Entity");
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 ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x30, 0x13, "EntityDestroy");
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x31, 0x1E, "RemoveEntityEffect");
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x32, 0x48, "ResourcePackSend");
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x33, 0x07, "Respawn");
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x34, 0x19, "EntityHeadRotation");
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 0x35, 0x44, "WorldBorder");
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x36, 0x43, "Camera");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x37, 0x09, "HeldItemSlot");
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x38, 0x3D, "ScoreboardDisplayObjective");
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x39, 0x1C, "EntityMetadata");
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x3A, 0x1B, "AttachEntity");
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x3B, 0x12, "EntityVelocity");
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x3C, 0x04, "EntityEquipment");
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x3D, 0x1F, "Experience");
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x3E, 0x06, "UpdateHealth");
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x3F, 0x3B, "ScoreboardObjective");
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x40, 0xFB, "Mount");
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x41, 0x3E, "ScoreboardTeam");
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x42, 0x3C, "ScoreboardScore");
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x43, 0x05, "SpawnPosition");
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x44, 0x03, "UpdateTime");
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x45, 0x45, "Title");
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x47, 0x29, "NamedSoundEffect");
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x48, 0x47, "PlayerListHeaderFooter");
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x49, 0x0D, "Collect");
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x4A, 0x18, "EntityTeleport");
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x4B, 0x20, "UpdateAttributes");
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x4C, 0x1D, "EntityEffect");
@Spigot(minimumBuild = 1628)
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x45, -1);
@Spigot(minimumBuild = 1628)
public static final PacketType TAB_HEADER = new PacketType(PROTOCOL, SENDER, 0x47, -1);
@Spigot(minimumBuild = 1628)
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x48, -1);
/**
* @deprecated Replaced by {@link WINDOW_DATA}
*/
@Deprecated
public static final PacketType CRAFT_PROGRESS_BAR = WINDOW_DATA;
/**
* @deprecated Replaced by {@link REL_ENTITY_MOVE_LOOK}
*/
@Deprecated
public static final PacketType ENTITY_MOVE_LOOK = REL_ENTITY_MOVE_LOOK;
/**
* @deprecated Replaced by {@link STATISTIC}
*/
@Deprecated
public static final PacketType STATISTICS = STATISTIC;
/**
* @deprecated Replaced by {@link TILE_ENTITY_DATA}
*/
@Deprecated
public static final PacketType UPDATE_SIGN = TILE_ENTITY_DATA;
// The instance must
private final static Server INSTANCE = new Server();
@@ -208,33 +227,36 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0);
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x01, 3);
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x02, 7);
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x03, 10);
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x04, 11);
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x05, 12);
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x06, 13);
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x07, 14);
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x08, 15);
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16);
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0A, 18);
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x0B, 19);
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x0C, 27);
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x0D, 101);
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x0E, 102);
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x0F, 106);
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x10, 107);
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x11, 108);
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x12, 130);
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x13, 202);
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x14, 203);
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x15, 204);
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x16, 205);
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x17, 250);
@Spigot(minimumBuild = 1628)
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x19, -1);
public static final PacketType TELEPORT_ACCEPT = new PacketType(PROTOCOL, SENDER, 0x00, 0xF9, "TeleportAccept");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x01, 0x14, "TabComplete");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x02, 0x01, "Chat");
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x03, 0x16, "ClientCommand");
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x04, 0x15, "Settings");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x05, 0x0F, "Transaction");
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x06, 0x11, "EnchantItem");
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x07, 0x0E, "WindowClick");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x08, 0x0D, "CloseWindow");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x09, 0x17, "CustomPayload");
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0A, 0x02, "UseEntity");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x0B, 0x00, "KeepAlive");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x0C, 0x04, "Position");
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x0D, 0x06, "PositionLook");
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x0E, 0x05, "Look");
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x0F, 0x03, "Flying");
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x10, 0xF8, "VehicleMove");
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x11, 0xF7, "BoatMove");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x12, 0x13, "Abilities");
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x13, 0x07, "BlockDig");
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x14, 0x0B, "EntityAction");
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x15, 0x0C, "SteerVehicle");
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x16, 0x19, "ResourcePackStatus");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x17, 0x09, "HeldItemSlot");
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x18, 0x10, "SetCreativeSlot");
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x19, 0x12, "UpdateSign");
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x1A, 0x0A, "ArmAnimation");
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x1B, 0x18, "Spectate");
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x1C, 0xF6, "UseItem");
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x1D, 0x08, "BlockPlace");
private final static Client INSTANCE = new Client();
@@ -268,9 +290,14 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Server extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType OUT_SERVER_INFO = new PacketType(PROTOCOL, SENDER, 0x00, 255);
@SuppressWarnings("deprecation")
public static final PacketType OUT_PING = new PacketType(PROTOCOL, SENDER, 0x01, Packets.Server.PING_TIME);
public static final PacketType SERVER_INFO = new PacketType(PROTOCOL, SENDER, 0x00, 0x00, "ServerInfo").forceAsync(true);
public static final PacketType PONG = new PacketType(PROTOCOL, SENDER, 0x01, 0x01, "Pong");
/**
* @deprecated Replaced by {@link SERVER_INFO}
*/
@Deprecated
public static final PacketType OUT_SERVER_INFO = SERVER_INFO;
private final static Server INSTANCE = new Server();
@@ -292,9 +319,8 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType IN_START = new PacketType(PROTOCOL, SENDER, 0x00, 254);
@SuppressWarnings("deprecation")
public static final PacketType IN_PING = new PacketType(PROTOCOL, SENDER, 0x01, Packets.Client.PING_TIME);
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();
@@ -328,13 +354,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Server extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x00, 255);
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 253);
@SuppressWarnings("deprecation")
public static final PacketType SUCCESS = new PacketType(PROTOCOL, SENDER, 0x02, Packets.Server.LOGIN_SUCCESS);
@Spigot(minimumBuild = 1628)
public static final PacketType LOGIN_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x03, -1);
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();
@@ -356,9 +379,8 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
@SuppressWarnings("deprecation")
public static final PacketType START = new PacketType(PROTOCOL, SENDER, 0x00, Packets.Client.LOGIN_START);
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 252);
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();
@@ -479,7 +501,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
String name = vanilla.name();
if ("HANDSHAKING".equals(name))
return HANDSHAKING;
return HANDSHAKING;
if ("PLAY".equals(name))
return PLAY;
if ("STATUS".equals(name))
@@ -488,6 +510,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
return LOGIN;
throw new IllegalArgumentException("Unrecognized vanilla enum " + vanilla);
}
public String getPacketName() {
return WordUtils.capitalize(name().toLowerCase());
}
}
/**
@@ -513,6 +539,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public ConnectionSide toSide() {
return this == CLIENT ? ConnectionSide.CLIENT_SIDE : ConnectionSide.SERVER_SIDE;
}
public String getPacketName() {
return this == CLIENT ? "In" : "Out";
}
}
// Lookup of packet types
@@ -521,13 +551,17 @@ public class PacketType implements Serializable, Comparable<PacketType> {
/**
* Protocol version of all the current IDs.
*/
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.WORLD_UPDATE;
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.BOUNTIFUL_UPDATE;
private final Protocol protocol;
private final Sender sender;
private final int currentId;
private final int legacyId;
private final MinecraftVersion version;
private final String[] classNames;
private boolean forceAsync;
private boolean dynamic;
/**
* Retrieve the current packet/legacy lookup.
@@ -607,7 +641,6 @@ public class PacketType implements Serializable, Comparable<PacketType> {
/**
* Determine if the given legacy packet exists.
* @param packetId - the legacy packet ID.
* @param preference - the sender preference.
* @return TRUE if it does, FALSE otherwise.
*/
public static boolean hasLegacy(int packetId) {
@@ -626,7 +659,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @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);
@@ -636,13 +671,34 @@ public class PacketType implements Serializable, Comparable<PacketType> {
"(Protocol: " + protocol + ", Sender: " + sender + ")");
}
public static PacketType findCurrent(Protocol protocol, Sender sender, String name) {
name = format(protocol, sender, name);
PacketType type = getLookup().getFromCurrent(protocol, sender, name);
if (type != null) {
return type;
} else {
throw new IllegalArgumentException("Cannot find packet " + name +
"(Protocol: " + protocol + ", Sender: " + sender + ")");
}
}
private static String format(Protocol protocol, Sender sender, String name) {
if (name.contains("Packet"))
return name;
return String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), name);
}
/**
* Determine if the given packet exists.
* @param protocol - the protocol.
* @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;
}
@@ -671,24 +727,68 @@ public class PacketType implements Serializable, Comparable<PacketType> {
}
/**
* Retrieve a packet type from a protocol, sender and packet ID.
* Retrieve a packet type from a protocol, sender and packet ID, for pre-1.8.
* <p>
* The packet will automatically be registered if its missing.
* @param protocol - the current protocol.
* @param sender - the sender.
* @param packetId - the packet ID. Can be UNKNOWN_PACKET.
* @param legacyId - the legacy packet ID. Can be UNKNOWN_PACKET.
* @param packetClass - the packet class
* @return The corresponding packet type.
*/
public static PacketType fromCurrent(Protocol protocol, Sender sender, int packetId, int legacyId) {
public static PacketType fromID(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
if (type == null) {
type = new PacketType(protocol, sender, packetId, legacyId);
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, packetClass.getName());
type.dynamic = true;
// Many may be scheduled, but only the first will be executed
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
}
return type;
}
/**
* Retrieve a packet type from a protocol, sender, ID, and class for 1.8+
* <p>
* The packet will automatically be registered if its missing.
* @param protocol - the current protocol.
* @param sender - the sender.
* @param packetId - the packet ID. Can be UNKNOWN_PACKET.
* @param packetClass - the packet class.
* @return The corresponding packet type.
*/
public static PacketType fromCurrent(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
ClassLookup lookup = getLookup().getClassLookup();
Map<String, PacketType> map = lookup.getMap(protocol, sender);
// Check the map first
String className = packetClass.getSimpleName();
PacketType type = map.get(className);
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.dynamic = true;
// Many may be scheduled, but only the first will be executed
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
}
return type;
}
@@ -751,7 +851,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) {
@@ -790,8 +890,8 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param currentId - the current packet ID, or
* @param legacyId - the legacy packet ID.
*/
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId) {
this(protocol, sender, currentId, legacyId, PROTOCOL_VERSION);
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId, String... names) {
this(protocol, sender, currentId, legacyId, PROTOCOL_VERSION, names);
}
/**
@@ -802,18 +902,25 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param legacyId - the legacy packet ID.
* @param version - the version of the current ID.
*/
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId, MinecraftVersion version) {
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId, MinecraftVersion version, String... names) {
this.protocol = Preconditions.checkNotNull(protocol, "protocol cannot be NULL");
this.sender = Preconditions.checkNotNull(sender, "sender cannot be NULL");
this.currentId = currentId;
this.legacyId = legacyId;
this.version = version;
this.classNames = new String[names.length];
for (int i = 0; i < classNames.length; i++) {
classNames[i] = format(protocol, sender, names[i]);
}
//System.out.println(Arrays.toString(classNames));
}
/**
* Construct a legacy packet type.
* @param sender - client or server.
* @param legacyId - the legacy packet ID.
* @return Legacy packet type
*/
public static PacketType newLegacy(Sender sender, int legacyId) {
return new PacketType(Protocol.LEGACY, sender, PacketType.UNKNOWN_PACKET, legacyId, MinecraftVersion.WORLD_UPDATE);
@@ -866,11 +973,17 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* <p>
* It is only unknown if the packet was removed in Minecraft 1.7.2.
* @return The current ID, or {@link #UNKNOWN_PACKET} if unknown.
* @deprecated IDs are subject to change
*/
@Deprecated
public int getCurrentId() {
return currentId;
}
public String[] getClassNames() {
return classNames;
}
/**
* Retrieve the equivalent packet class.
* @return The packet class, or NULL if not found.
@@ -909,6 +1022,27 @@ public class PacketType implements Serializable, Comparable<PacketType> {
return legacyId;
}
/**
* Whether or not this packet was dynamically created (i.e. we don't have it registered)
* @return True if dnyamic, false if not.
*/
public boolean isDynamic() {
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);
@@ -941,10 +1075,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
@Override
public String toString() {
Class<?> clazz = getPacketClass();;
Class<?> clazz = getPacketClass();
if (clazz == null)
return "UNREGISTERED [" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + "]";
return "UNREGISTERED[" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + ", classNames: " + Arrays.toString(classNames) + "]";
else
return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]";
}
@@ -2,6 +2,8 @@ package com.comphenix.protocol;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
@@ -15,7 +17,7 @@ import com.google.common.collect.Multimap;
* @author Kristian
*/
class PacketTypeLookup {
private static class ProtocolSenderLookup {
public static class ProtocolSenderLookup {
// Unroll lookup for performance reasons
public final IntegerMap<PacketType> HANDSHAKE_CLIENT = IntegerMap.newMap();
public final IntegerMap<PacketType> HANDSHAKE_SERVER = IntegerMap.newMap();
@@ -47,6 +49,39 @@ class PacketTypeLookup {
}
}
}
public static class ClassLookup {
// Unroll lookup for performance reasons
public final Map<String, PacketType> HANDSHAKE_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> HANDSHAKE_SERVER = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> GAME_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> GAME_SERVER = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> STATUS_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> STATUS_SERVER = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> LOGIN_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> LOGIN_SERVER = new ConcurrentHashMap<String, PacketType>();
/**
* Retrieve the correct integer map for a specific protocol and sender.
* @param protocol - the protocol.
* @param sender - the sender.
* @return The integer map of packets.
*/
public Map<String, PacketType> getMap(Protocol protocol, Sender sender) {
switch (protocol) {
case HANDSHAKING:
return sender == Sender.CLIENT ? HANDSHAKE_CLIENT : HANDSHAKE_SERVER;
case PLAY:
return sender == Sender.CLIENT ? GAME_CLIENT : GAME_SERVER;
case STATUS:
return sender == Sender.CLIENT ? STATUS_CLIENT : STATUS_SERVER;
case LOGIN:
return sender == Sender.CLIENT ? LOGIN_CLIENT : LOGIN_SERVER;
default:
throw new IllegalArgumentException("Unable to find protocol " + protocol);
}
}
}
// Packet IDs from 1.6.4 and below
private final IntegerMap<PacketType> legacyLookup = new IntegerMap<PacketType>();
@@ -54,11 +89,14 @@ class PacketTypeLookup {
private final IntegerMap<PacketType> clientLookup = new IntegerMap<PacketType>();
// Packets for 1.7.2
private final ProtocolSenderLookup currentLookup = new ProtocolSenderLookup();
private final ProtocolSenderLookup idLookup = new ProtocolSenderLookup();
// Packets for 1.8+
private final ClassLookup classLookup = new ClassLookup();
// Packets based on name
private final Multimap<String, PacketType> nameLookup = HashMultimap.create();
/**
* Add a collection of packet types to the lookup.
* @param types - the types to add.
@@ -79,9 +117,9 @@ class PacketTypeLookup {
}
// Skip unknown current packets
if (type.getCurrentId() != PacketType.UNKNOWN_PACKET) {
currentLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
idLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames()[0], type);
}
// Save name
nameLookup.put(type.name(), type);
}
return this;
@@ -132,8 +170,18 @@ class PacketTypeLookup {
* @param sender - the sender.
* @param packetId - the packet ID.
* @return The corresponding packet type, or NULL if not found.
* @deprecated IDs are no longer reliable
*/
@Deprecated
public PacketType getFromCurrent(Protocol protocol, Sender sender, int packetId) {
return currentLookup.getMap(protocol, sender).get(packetId);
return idLookup.getMap(protocol, sender).get(packetId);
}
public PacketType getFromCurrent(Protocol protocol, Sender sender, String name) {
return classLookup.getMap(protocol, sender).get(name);
}
public ClassLookup getClassLookup() {
return classLookup;
}
}
@@ -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();
@@ -1,4 +1,4 @@
/*
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
@@ -14,18 +14,18 @@
* 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.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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;
@@ -38,53 +38,49 @@ import com.google.common.io.Files;
*/
public class ProtocolConfig {
private static final String LAST_UPDATE_FILE = "lastupdate";
private static final String SECTION_GLOBAL = "global";
private static final String SECTION_AUTOUPDATER = "auto updater";
private static final String METRICS_ENABLED = "metrics";
private static final String IGNORE_VERSION_CHECK = "ignore version check";
private static final String IGNORE_VERSION_CHECK = "ignore version check";
private static final String BACKGROUND_COMPILER_ENABLED = "background compiler";
private static final String DEBUG_MODE_ENABLED = "debug";
private static final String DETAILED_ERROR = "detailed error";
private static final String INJECTION_METHOD = "injection method";
private static final String SCRIPT_ENGINE_NAME = "script engine";
private static final String SUPPRESSED_REPORTS = "suppressed reports";
private static final String UPDATER_NOTIFY = "notify";
private static final String UPDATER_DOWNLAD = "download";
private static final String UPDATER_DELAY = "delay";
// Defaults
private static final long DEFAULT_UPDATER_DELAY = 43200;
private Plugin plugin;
private Configuration config;
private boolean loadingSections;
private ConfigurationSection global;
private ConfigurationSection updater;
// Last update time
private long lastUpdateTime;
private boolean configChanged;
private boolean valuesChanged;
// Modifications
private int modCount;
public ProtocolConfig(Plugin plugin) {
this(plugin, plugin.getConfig());
}
public ProtocolConfig(Plugin plugin, Configuration config) {
this.plugin = plugin;
reloadConfig();
}
/**
* Reload configuration file.
*/
@@ -93,19 +89,20 @@ public class ProtocolConfig {
configChanged = false;
valuesChanged = false;
modCount++;
this.config = plugin.getConfig();
this.lastUpdateTime = loadLastUpdate();
loadSections(!loadingSections);
}
/**
* Load the last update time stamp from the file system.
*
* @return Last update time stamp.
*/
private long loadLastUpdate() {
File dataFile = getLastUpdateFile();
if (dataFile.exists()) {
try {
return Long.parseLong(Files.toString(dataFile, Charsets.UTF_8));
@@ -118,37 +115,40 @@ public class ProtocolConfig {
// Default last update
return 0;
}
/**
* Store the given time stamp.
*
* @param value - time stamp to store.
*/
private void saveLastUpdate(long value) {
File dataFile = getLastUpdateFile();
// The data folder must exist
dataFile.getParentFile().mkdirs();
if (dataFile.exists())
dataFile.delete();
try {
Files.write(Long.toString(value), dataFile, Charsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("Cannot write " + dataFile, e);
}
}
/**
* Retrieve the file that is used to store the update time stamp.
*
* @return File storing the update time stamp.
*/
private File getLastUpdateFile() {
return new File(plugin.getDataFolder(), LAST_UPDATE_FILE);
}
/**
* Load data sections.
*
* @param copyDefaults - whether or not to copy configuration defaults.
*/
private void loadSections(boolean copyDefaults) {
@@ -162,20 +162,21 @@ public class ProtocolConfig {
// Automatically copy defaults
if (copyDefaults && (!getFile().exists() || global == null || updater == null)) {
loadingSections = true;
if (config != null)
config.options().copyDefaults(true);
plugin.saveDefaultConfig();
plugin.reloadConfig();
loadingSections = false;
loadingSections = false;
// Inform the user
System.out.println("[ProtocolLib] Created default configuration.");
plugin.getLogger().info("Created default configuration.");
}
}
/**
* Set a particular configuration key value pair.
*
* @param section - the configuration root.
* @param path - the path to the key.
* @param value - the value to set.
@@ -185,93 +186,122 @@ public class ProtocolConfig {
section.set(path, value);
}
@SuppressWarnings("unchecked")
private <T> T getGlobalValue(String path, T def) {
try {
return (T) global.get(path, def);
} catch (Throwable ex) {
return def;
}
}
@SuppressWarnings("unchecked")
private <T> T getUpdaterValue(String path, T def) {
try {
return (T) updater.get(path, def);
} catch (Throwable ex) {
return def;
}
}
/**
* Retrieve a reference to the configuration file.
*
* @return Configuration file on disk.
*/
public File getFile() {
return new File(plugin.getDataFolder(), "config.yml");
}
/**
* Determine if detailed error reporting is enabled. Default FALSE.
*
* @return TRUE if it is enabled, FALSE otherwise.
*/
public boolean isDetailedErrorReporting() {
return global.getBoolean(DETAILED_ERROR, false);
return getGlobalValue(DETAILED_ERROR, false);
}
/**
* Set whether or not detailed error reporting is enabled.
*
* @param value - TRUE if it is enabled, FALSE otherwise.
*/
public void setDetailedErrorReporting(boolean value) {
global.set(DETAILED_ERROR, value);
}
/**
* Retrieve whether or not ProtocolLib should determine if a new version has been released.
*
* @return TRUE if it should do this automatically, FALSE otherwise.
*/
public boolean isAutoNotify() {
return updater.getBoolean(UPDATER_NOTIFY, true);
return getUpdaterValue(UPDATER_NOTIFY, true);
}
/**
* Set whether or not ProtocolLib should determine if a new version has been released.
*
* @param value - TRUE to do this automatically, FALSE otherwise.
*/
public void setAutoNotify(boolean value) {
setConfig(updater, UPDATER_NOTIFY, value);
modCount++;
}
/**
* Retrieve whether or not ProtocolLib should automatically download the new version.
*
* @return TRUE if it should, FALSE otherwise.
*/
public boolean isAutoDownload() {
return updater != null && updater.getBoolean(UPDATER_DOWNLAD, true);
return updater != null && getUpdaterValue(UPDATER_DOWNLAD, true);
}
/**
* Set whether or not ProtocolLib should automatically download the new version.
*
* @param value - TRUE if it should. FALSE otherwise.
*/
public void setAutoDownload(boolean value) {
setConfig(updater, UPDATER_DOWNLAD, value);
modCount++;
}
/**
* Determine whether or not debug mode is enabled.
* <p>
* This grants access to the filter command.
*
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isDebug() {
return global.getBoolean(DEBUG_MODE_ENABLED, false);
return getGlobalValue(DEBUG_MODE_ENABLED, false);
}
/**
* Set whether or not debug mode is enabled.
*
* @param value - TRUE if it is enabled, FALSE otherwise.
*/
public void setDebug(boolean value) {
setConfig(global, DEBUG_MODE_ENABLED, value);
modCount++;
}
/**
* Retrieve an immutable list of every suppressed report type.
*
* @return Every suppressed report type.
*/
public ImmutableList<String> getSuppressedReports() {
return ImmutableList.copyOf(global.getStringList(SUPPRESSED_REPORTS));
return ImmutableList.copyOf(getGlobalValue(SUPPRESSED_REPORTS, new ArrayList<String>()));
}
/**
* Set the list of suppressed report types,
*
* @param reports - suppressed report types.
*/
public void setSuppressedReports(List<String> reports) {
@@ -281,17 +311,19 @@ public class ProtocolConfig {
/**
* Retrieve the amount of time to wait until checking for a new update.
*
* @return The amount of time to wait.
*/
public long getAutoDelay() {
// Note that the delay must be greater than 59 seconds
return Math.max(updater.getInt(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY);
return Math.max(getUpdaterValue(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY);
}
/**
* Set the amount of time to wait until checking for a new update.
* <p>
* This time must be greater than 59 seconds.
*
* @param delaySeconds - the amount of time to wait.
*/
public void setAutoDelay(long delaySeconds) {
@@ -301,20 +333,20 @@ public class ProtocolConfig {
setConfig(updater, UPDATER_DELAY, delaySeconds);
modCount++;
}
/**
* The version of Minecraft to ignore the built-in safety feature.
*
* @return The version to ignore ProtocolLib's satefy.
*/
public String getIgnoreVersionCheck() {
return global.getString(IGNORE_VERSION_CHECK, "");
return getGlobalValue(IGNORE_VERSION_CHECK, "");
}
/**
* Sets under which version of Minecraft the version safety feature will be ignored.
* <p>
* This is useful if a server operator has tested and verified that a version of ProtocolLib works,
* but doesn't want or can't upgrade to a newer version.
* This is useful if a server operator has tested and verified that a version of ProtocolLib works, but doesn't want or can't upgrade to a newer version.
*
* @param ignoreVersion - the version of Minecraft where the satefy will be disabled.
*/
@@ -322,15 +354,16 @@ public class ProtocolConfig {
setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion);
modCount++;
}
/**
* Retrieve whether or not metrics is enabled.
*
* @return TRUE if metrics is enabled, FALSE otherwise.
*/
public boolean isMetricsEnabled() {
return global.getBoolean(METRICS_ENABLED, true);
return getGlobalValue(METRICS_ENABLED, true);
}
/**
* Set whether or not metrics is enabled.
* <p>
@@ -342,28 +375,31 @@ public class ProtocolConfig {
setConfig(global, METRICS_ENABLED, enabled);
modCount++;
}
/**
* Retrieve whether or not the background compiler for structure modifiers is enabled or not.
*
* @return TRUE if it is enabled, FALSE otherwise.
*/
public boolean isBackgroundCompilerEnabled() {
return global.getBoolean(BACKGROUND_COMPILER_ENABLED, true);
return getGlobalValue(BACKGROUND_COMPILER_ENABLED, true);
}
/**
* Set whether or not the background compiler for structure modifiers is enabled or not.
* <p>
* This setting will take effect next time ProtocolLib is started.
*
* @param enabled - TRUE if is enabled/running, FALSE otherwise.
*/
public void setBackgroundCompilerEnabled(boolean enabled) {
setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled);
modCount++;
}
/**
* Retrieve the last time we updated, in seconds since 1970.01.01 00:00.
*
* @return Last update time.
*/
public long getAutoLastTime() {
@@ -373,75 +409,81 @@ public class ProtocolConfig {
/**
* Set the last time we updated, in seconds since 1970.01.01 00:00.
* <p>
* Note that this is not considered to modify the configuration, so the modification count
* will not be incremented.
* Note that this is not considered to modify the configuration, so the modification count will not be incremented.
*
* @param lastTimeSeconds - new last update time.
*/
public void setAutoLastTime(long lastTimeSeconds) {
public void setAutoLastTime(long lastTimeSeconds) {
this.valuesChanged = true;
this.lastUpdateTime = lastTimeSeconds;
}
/**
* Retrieve the unique name of the script engine to use for filtering.
*
* @return Script engine to use.
*/
public String getScriptEngineName() {
return global.getString(SCRIPT_ENGINE_NAME, "JavaScript");
return getGlobalValue(SCRIPT_ENGINE_NAME, "JavaScript");
}
/**
* Set the unique name of the script engine to use for filtering.
* <p>
* This setting will take effect next time ProtocolLib is started.
*
* @param name - name of the script engine to use.
*/
public void setScriptEngineName(String name) {
setConfig(global, SCRIPT_ENGINE_NAME, name);
modCount++;
}
/**
* Retrieve the default injection method.
*
* @return Default method.
*/
public PlayerInjectHooks getDefaultMethod() {
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
}
/**
* Retrieve the injection method that has been set in the configuration, or use a default value.
*
* @return Injection method to use.
* @throws IllegalArgumentException If the configuration option is malformed.
*/
public PlayerInjectHooks getInjectionMethod() throws IllegalArgumentException {
String text = global.getString(INJECTION_METHOD);
// Default hook if nothing has been set
PlayerInjectHooks hook = getDefaultMethod();
if (text != null)
if (text != null)
hook = PlayerInjectHooks.valueOf(text.toUpperCase().replace(" ", "_"));
return hook;
}
/**
* Set the starting injection method to use.
*
* @return Injection method.
*/
public void setInjectionMethod(PlayerInjectHooks hook) {
setConfig(global, INJECTION_METHOD, hook.name());
modCount++;
}
/**
* Retrieve the number of modifications made to this configuration.
*
* @return The number of modifications.
*/
public int getModificationCount() {
return modCount;
}
/**
* Save the current configuration file.
*/
@@ -450,9 +492,9 @@ public class ProtocolConfig {
saveLastUpdate(lastUpdateTime);
if (configChanged)
plugin.saveConfig();
// And we're done
valuesChanged = false;
configChanged = false;
}
}
}
@@ -0,0 +1,144 @@
/**
* 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.9";
/**
* The maximum version ProtocolLib has been tested with.
*/
public static final String MAXIMUM_MINECRAFT_VERSION = "1.9.4";
/**
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.9.4) was released.
*/
public static final String MINECRAFT_LAST_RELEASE_DATE = "2016-05-10";
/**
* 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;
ProtocolLogger.init(plugin);
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,63 @@
/**
* 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 java.util.logging.Logger;
import org.bukkit.plugin.Plugin;
/**
* @author dmulloy2
*/
public class ProtocolLogger {
private static Logger logger;
protected static void init(Plugin plugin) {
ProtocolLogger.logger = plugin.getLogger();
}
/**
* 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) {
logger.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) {
logger.log(level, message, ex);
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -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;
@@ -53,7 +54,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Send a packet to the given player.
* <p>
* Re-sending a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* Re-sending a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* to delay a packet until a certain condition has been met.
*
* @param receiver - the receiver.
@@ -62,13 +63,13 @@ public interface ProtocolManager extends PacketStream {
* @throws InvocationTargetException - if an error occurred when sending the packet.
*/
@Override
public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters)
public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters)
throws InvocationTargetException;
/**
* Simulate receiving a certain packet from a given player.
* <p>
* Receiving a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* Receiving a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* to delay a packet until a certain condition has been met.
*
* @param sender - the sender.
@@ -78,7 +79,7 @@ public interface ProtocolManager extends PacketStream {
* @throws IllegalAccessException If the underlying method caused an error.
*/
@Override
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
throws IllegalAccessException, InvocationTargetException;
/**
@@ -89,9 +90,9 @@ public interface ProtocolManager extends PacketStream {
public void broadcastServerPacket(PacketContainer packet);
/**
* Broadcast a packet to every player that is receiving information about a given entity.
* Broadcast a packet to every player that is receiving information about a given entity.
* <p>
* This is usually every player in the same world within an observable distance. If the entity is a
* This is usually every player in the same world within an observable distance. If the entity is a
* player, it will only be included if <i>includeTracker</i> is TRUE.
* @param packet - the packet to broadcast.
* @param entity - the entity whose trackers we will inform.
@@ -115,17 +116,17 @@ public interface ProtocolManager extends PacketStream {
public ImmutableSet<PacketListener> getPacketListeners();
/**
* Adds a packet listener.
* Adds a packet listener.
* <p>
* Adding an already registered listener has no effect. If you need to change the packets
* the current listener is observing, you must first remove the packet listener before you
* Adding an already registered listener has no effect. If you need to change the packets
* the current listener is observing, you must first remove the packet listener before you
* can register it again.
* @param listener - new packet listener.
*/
public void addPacketListener(PacketListener listener);
/**
* Removes a given packet listener.
* Removes a given packet listener.
* <p>
* Attempting to remove a listener that doesn't exist has no effect.
* @param listener - the packet listener to remove.
@@ -158,7 +159,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Constructs a new encapsulated Minecraft packet with the given ID.
* <p>
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* give non-primitive fields in the packet sensible default values. For instance, certain
* packets - like Packet60Explosion - require a List or Set to be non-null. If the
* forceDefaults option is true, the List or Set will be automatically created.
@@ -175,7 +176,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Constructs a new encapsulated Minecraft packet with the given ID.
* <p>
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* give non-primitive fields in the packet sensible default values. For instance, certain
* packets - like Packet60Explosion - require a List or Set to be non-null. If the
* forceDefaults option is true, the List or Set will be automatically created.
@@ -199,7 +200,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Construct a packet using the special builtin Minecraft constructors.
* @param id - the packet type.
* @param type - the packet type.
* @param arguments - arguments that will be passed to the constructor.
* @return The packet constructor.
*/
@@ -208,7 +209,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Completely resend an entity to a list of clients.
* <p>
* Note that this method is NOT thread safe. If you call this method from anything
* Note that this method is NOT thread safe. If you call this method from anything
* but the main thread, it will throw an exception.
* @param entity - entity to refresh.
* @param observers - the clients to update.
@@ -269,7 +270,7 @@ public interface ProtocolManager extends PacketStream {
public MinecraftVersion getMinecraftVersion();
/**
* Determines whether or not this protocol manager has been disabled.
* Determines whether or not this protocol manager has been disabled.
* @return TRUE if it has, FALSE otherwise.
*/
public boolean isClosed();
@@ -279,4 +280,6 @@ public interface ProtocolManager extends PacketStream {
* @return Asynchronous packet manager.
*/
public AsynchronousManager getAsynchronousManager();
public void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist);
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -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;
@@ -81,7 +80,7 @@ public class AsyncFilterManager implements AsynchronousManager {
/**
* Initialize a asynchronous filter manager.
* <p>
* <b>Internal method</b>. Retrieve the global asynchronous manager from the protocol manager instead.
* <b>Internal method</b>. Retrieve the global asynchronous manager from the protocol manager instead.
* @param reporter - desired error reporter.
* @param scheduler - task scheduler.
*/
@@ -148,7 +147,7 @@ public class AsyncFilterManager implements AsynchronousManager {
ImmutableSet.Builder<PacketListener> builder = ImmutableSet.builder();
// Add every asynchronous packet listener
for (PrioritizedListener<AsyncListenerHandler> handler :
for (PrioritizedListener<AsyncListenerHandler> handler :
Iterables.concat(serverProcessingQueue.values(), clientProcessingQueue.values())) {
builder.add(handler.getListener().getAsyncListener());
}
@@ -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);
}
@@ -221,7 +220,7 @@ public class AsyncFilterManager implements AsynchronousManager {
if (listener == null)
throw new IllegalArgumentException("listener cannot be NULL.");
AsyncListenerHandler handler =
AsyncListenerHandler handler =
findHandler(serverProcessingQueue, listener.getSendingWhitelist(), listener);
if (handler == null) {
@@ -232,7 +231,7 @@ public class AsyncFilterManager implements AsynchronousManager {
// Search for the first correct handler
private AsyncListenerHandler findHandler(PacketProcessingQueue queue, ListeningWhitelist search, PacketListener target) {
if (ListeningWhitelist.isEmpty(search))
if (ListeningWhitelist.isEmpty(search))
return null;
for (PacketType type : search.getTypes()) {
@@ -250,7 +249,7 @@ public class AsyncFilterManager implements AsynchronousManager {
if (handler == null)
throw new IllegalArgumentException("listenerToken cannot be NULL");
handler.cancel();
handler.cancel();
}
// Called by AsyncListenerHandler
@@ -295,7 +294,7 @@ public class AsyncFilterManager implements AsynchronousManager {
private void unregisterAsyncHandlers(PacketProcessingQueue processingQueue, Plugin plugin) {
// Iterate through every packet listener
for (PrioritizedListener<AsyncListenerHandler> listener : processingQueue.values()) {
for (PrioritizedListener<AsyncListenerHandler> listener : processingQueue.values()) {
// Remove the listener
if (Objects.equal(listener.getListener().getPlugin(), plugin)) {
unregisterAsyncHandler(listener.getListener());
@@ -305,22 +304,28 @@ public class AsyncFilterManager implements AsynchronousManager {
/**
* Enqueue a packet for asynchronous processing.
*
* @param syncPacket - synchronous packet event.
* @param asyncMarker - the asynchronous marker to use.
*/
public synchronized void enqueueSyncPacket(PacketEvent syncPacket, AsyncMarker asyncMarker) {
PacketEvent newEvent = PacketEvent.fromSynchronous(syncPacket, asyncMarker);
if (asyncMarker.isQueued() || asyncMarker.isTransmitted())
throw new IllegalArgumentException("Cannot queue a packet that has already been queued.");
asyncMarker.setQueuedSendingIndex(asyncMarker.getNewSendingIndex());
// Start the process
getSendingQueue(syncPacket).enqueue(newEvent);
// We know this is occuring on the main thread, so pass TRUE
getProcessingQueue(syncPacket).enqueue(newEvent, true);
// The player is only be null when they're logged out,
// so this should be a pretty safe check
Player player = newEvent.getPlayer();
if (player != null) {
// Start the process
getSendingQueue(syncPacket).enqueue(newEvent);
// We know this is occuring on the main thread, so pass TRUE
getProcessingQueue(syncPacket).enqueue(newEvent, true);
}
}
@Override
@@ -362,23 +367,21 @@ public class AsyncFilterManager implements AsynchronousManager {
* @return Asynchronous marker.
*/
public AsyncMarker createAsyncMarker() {
return createAsyncMarker(AsyncMarker.DEFAULT_SENDING_DELTA, AsyncMarker.DEFAULT_TIMEOUT_DELTA);
return createAsyncMarker(AsyncMarker.DEFAULT_TIMEOUT_DELTA);
}
/**
* Construct an async marker with the given sending priority delta and timeout delta.
* @param sendingDelta - how many packets we're willing to wait.
* @param timeoutDelta - how long (in ms) until the packet expire.
* @return An async marker.
*/
public AsyncMarker createAsyncMarker(long sendingDelta, long timeoutDelta) {
return createAsyncMarker(sendingDelta, timeoutDelta,
currentSendingIndex.incrementAndGet(), System.currentTimeMillis());
public AsyncMarker createAsyncMarker(long timeoutDelta) {
return createAsyncMarker(timeoutDelta, currentSendingIndex.incrementAndGet());
}
// Helper method
private AsyncMarker createAsyncMarker(long sendingDelta, long timeoutDelta, long sendingIndex, long currentTime) {
return new AsyncMarker(manager, sendingIndex, sendingDelta, System.currentTimeMillis(), timeoutDelta);
private AsyncMarker createAsyncMarker(long timeoutDelta, long sendingIndex) {
return new AsyncMarker(manager, sendingIndex, System.currentTimeMillis(), timeoutDelta);
}
@Override
@@ -468,6 +471,8 @@ public class AsyncFilterManager implements AsynchronousManager {
/**
* Send any due packets, or clean up packets that have expired.
* @param tickCounter Tick counter
* @param onMainThread Whether or not to execute on the main thread
*/
public void sendProcessedPackets(int tickCounter, boolean onMainThread) {
// The server queue is unlikely to need checking that often
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -48,7 +48,7 @@ import com.google.common.base.Joiner;
*/
public class AsyncListenerHandler {
public static final ReportType REPORT_HANDLER_NOT_STARTED = new ReportType(
"Plugin %s did not start the asynchronous handler %s by calling start() or syncStart().");
"Plugin %s did not start the asynchronous handler %s by calling start() or syncStart().");
/**
* Signal an end to packet processing.
@@ -209,6 +209,7 @@ public class AsyncListenerHandler {
* close a specific worker is less efficient than stopping an arbitrary worker.
* <p>
* <b>Warning</b>: Never call the run() method in the main thread.
* @return The listener loop
*/
public AsyncRunnable getListenerLoop() {
return new AsyncRunnable() {
@@ -315,7 +316,7 @@ public class AsyncListenerHandler {
* public Void apply(&#64;Nullable AsyncRunnable workerLoop) {
* Thread thread = Thread.currentThread();
* int prevPriority = thread.getPriority();
*
*
* thread.setPriority(Thread.MIN_PRIORITY);
* workerLoop.run();
* thread.setPriority(prevPriority);
@@ -357,9 +358,9 @@ public class AsyncListenerHandler {
* @return A friendly thread name.
*/
public String getFriendlyWorkerName(int id) {
return String.format("Protocol Worker #%s - %s - [recv: %s, send: %s]",
id,
PacketAdapter.getPluginName(listener),
return String.format("Protocol Worker #%s - %s - [recv: %s, send: %s]",
id,
PacketAdapter.getPluginName(listener),
fromWhitelist(listener.getReceivingWhitelist()),
fromWhitelist(listener.getSendingWhitelist())
);
@@ -383,8 +384,8 @@ public class AsyncListenerHandler {
* This is useful if you need to synchronize with the main thread in your packet listener, but
* you're not performing any expensive processing.
* <p>
* <b>Note</b>: Use a asynchronous worker if the packet listener may use more than 0.5 ms
* of processing time on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* <b>Note</b>: Use a asynchronous worker if the packet listener may use more than 0.5 ms
* of processing time on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* to use the Bukkit API instead.
* @return TRUE if the synchronized processing was successfully started, FALSE if it's already running.
* @throws IllegalStateException If we couldn't start the underlying task.
@@ -399,12 +400,12 @@ public class AsyncListenerHandler {
* This is useful if you need to synchronize with the main thread in your packet listener, but
* you're not performing any expensive processing.
* <p>
* The processing time parameter gives the upper bound for the amount of time spent processing pending packets.
* It should be set to a fairly low number, such as 0.5 ms or 1% of a game tick - to reduce the impact
* The processing time parameter gives the upper bound for the amount of time spent processing pending packets.
* It should be set to a fairly low number, such as 0.5 ms or 1% of a game tick - to reduce the impact
* on the main thread. Never go beyond 50 milliseconds.
* <p>
* <b>Note</b>: Use a asynchronous worker if the packet listener may exceed the ideal processing time
* on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* <b>Note</b>: Use a asynchronous worker if the packet listener may exceed the ideal processing time
* on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* to use the Bukkit API instead.
*
* @param time - the amount of processing time alloted per game tick (20 ticks per second).
@@ -503,7 +504,7 @@ public class AsyncListenerHandler {
}
/**
* Set the current number of workers.
* Set the current number of workers.
* <p>
* This method can only be called with a count of zero when the listener is closing.
* @param count - new number of workers.
@@ -563,7 +564,7 @@ public class AsyncListenerHandler {
*/
private void listenerLoop(int workerID) {
// Danger, danger!
if (Thread.currentThread().getId() == mainThread.getId())
if (Thread.currentThread().getId() == mainThread.getId())
throw new IllegalStateException("Do not call this method from the main thread.");
if (cancelled)
throw new IllegalStateException("Listener has been cancelled. Create a new listener instead.");
@@ -584,7 +585,7 @@ public class AsyncListenerHandler {
// This is a bit slow, but it should be safe
synchronized (stopLock) {
// Are we the one who is supposed to stop?
if (stoppedTasks.contains(workerID))
if (stoppedTasks.contains(workerID))
return;
if (waitForStops())
return;
@@ -616,7 +617,7 @@ public class AsyncListenerHandler {
AsyncMarker marker = packet.getAsyncMarker();
// Here's the core of the asynchronous processing
try {
try {
synchronized (marker.getProcessingLock()) {
marker.setListenerHandler(this);
marker.setWorkerID(workerID);
@@ -624,7 +625,7 @@ public class AsyncListenerHandler {
// We're not THAT worried about performance here
if (timedManager.isTiming()) {
// Retrieve the tracker to use
TimedTracker tracker = timedManager.getTracker(listener,
TimedTracker tracker = timedManager.getTracker(listener,
packet.isServerPacket() ? ListenerType.ASYNC_SERVER_SIDE : ListenerType.ASYNC_CLIENT_SIDE);
long token = tracker.beginTracking();
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -24,14 +24,18 @@ import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import com.comphenix.protocol.PacketStream;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PrioritizedListener;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.primitives.Longs;
/**
@@ -106,7 +110,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
* Create a container for asyncronous packets.
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
*/
AsyncMarker(PacketStream packetStream, long sendingIndex, long sendingDelta, long initialTime, long timeoutDelta) {
AsyncMarker(PacketStream packetStream, long sendingIndex, long initialTime, long timeoutDelta) {
if (packetStream == null)
throw new IllegalArgumentException("packetStream cannot be NULL");
@@ -123,11 +127,11 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
/**
* Retrieve the time the packet was initially queued for asynchronous processing.
* @return The initial time in number of milliseconds since 01.01.1970 00:00.
* @return The initial time in number of milliseconds since 01.01.1970 00:00.
*/
public long getInitialTime() {
return initialTime;
}
}
/**
* Retrieve the time the packet will be forcefully rejected.
@@ -209,11 +213,11 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
* Increment the number of times the current packet must be signalled as done before its transmitted.
* <p>
* This is useful if an asynchronous listener is waiting for further information before the
* packet can be sent to the user. A packet listener <b>MUST</b> eventually call
* packet can be sent to the user. A packet listener <b>MUST</b> eventually call
* {@link AsyncFilterManager#signalPacketTransmission(PacketEvent)},
* even if the packet is cancelled, after this method is called.
* even if the packet is cancelled, after this method is called.
* <p>
* It is recommended that processing outside a packet listener is wrapped in a synchronized block
* It is recommended that processing outside a packet listener is wrapped in a synchronized block
* using the {@link #getProcessingLock()} method.
*
* @return The new processing delay.
@@ -331,7 +335,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
}
/**
* Set the current asynchronous listener handler.
* Set the current asynchronous listener handler.
* <p>
* Used by the worker to update the value.
* @param listenerHandler - new listener handler.
@@ -397,10 +401,11 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
/**
* Determine if Minecraft allows asynchronous processing of this packet.
* @param event - packet event
* @return TRUE if it does, FALSE otherwise.
* @throws FieldAccessException If determining fails for some reasaon
*/
public boolean isMinecraftAsync(PacketEvent event) throws FieldAccessException {
if (isMinecraftAsync == null && !alwaysSync) {
try {
isMinecraftAsync = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethodByName("a_.*");
@@ -415,18 +420,36 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
} else if (methods.size() == 1) {
// We're in 1.2.5
alwaysSync = true;
} else if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
// The centralized async marker was removed in 1.8
// Incoming chat packets can be async
if (event.getPacketType() == PacketType.Play.Client.CHAT) {
String content = event.getPacket().getStrings().readSafely(0);
if (content != null) {
// Incoming chat packets are async only if they aren't commands
return ! content.startsWith("/");
} else {
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 {
System.err.println("[ProtocolLib] Cannot determine asynchronous state of packets!");
ProtocolLogger.log(Level.INFO, "Could not determine asynchronous state of packets (this can probably be ignored)");
alwaysSync = true;
}
}
}
if (alwaysSync) {
return false;
} else {
try {
// Wrap exceptions
// Wrap exceptions
return (Boolean) isMinecraftAsync.invoke(event.getPacket().getHandle());
} catch (IllegalArgumentException e) {
throw new FieldAccessException("Illegal argument", e);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -35,6 +35,7 @@ public interface AsyncRunnable extends Runnable {
* <p>
* This may not occur right away.
* @return TRUE if the thread was stopped, FALSE if it was already stopped.
* @throws InterruptedException if it is interrupted
*/
public boolean stop() throws InterruptedException;
@@ -18,6 +18,7 @@ public class IntegerMap<T> {
/**
* Construct a new integer map.
* @param <T> Parameter type
* @return A new integer map.
*/
public static <T> IntegerMap<T> newMap() {
@@ -51,7 +52,7 @@ public class IntegerMap<T> {
public T put(int key, T value) {
ensureCapacity(key);
T old = array[key];
T old = array[key];
array[key] = Preconditions.checkNotNull(value, "value cannot be NULL");
if (old == null)
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -25,7 +25,6 @@ import java.util.TreeMap;
import com.google.common.base.Objects;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
/**
* Represents a generic store of intervals and associated values. No two intervals
@@ -68,7 +67,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
@Override
public Range<TKey> getKey() {
return Ranges.closed(left.key, right.key);
return Range.closed(left.key, right.key);
}
@Override
@@ -130,7 +129,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
this.state = state;
this.key = key;
this.value = value;
}
}
}
// To quickly look up ranges we'll index them by endpoints
@@ -140,6 +139,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
* Removes every interval that intersects with the given range.
* @param lowerBound - lowest value to remove.
* @param upperBound - highest value to remove.
* @return Intervals that were removed
*/
public Set<Entry> remove(TKey lowerBound, TKey upperBound) {
return remove(lowerBound, upperBound, false);
@@ -150,12 +150,13 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
* @param lowerBound - lowest value to remove.
* @param upperBound - highest value to remove.
* @param preserveDifference - whether or not to preserve the intervals that are partially outside.
* @return Intervals that were removed
*/
public Set<Entry> remove(TKey lowerBound, TKey upperBound, boolean preserveDifference) {
checkBounds(lowerBound, upperBound);
NavigableMap<TKey, EndPoint> range = bounds.subMap(lowerBound, true, upperBound, true);
EndPoint first = getNextEndPoint(lowerBound, true);
EndPoint first = getNextEndPoint(lowerBound, true);
EndPoint last = getPreviousEndPoint(upperBound, true);
// Used while resizing intervals
@@ -181,7 +182,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
if (next != null) {
removed.add(getEntry(last, next));
}
}
}
// Now remove both ranges
@@ -253,7 +254,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
/**
* Associates a given interval of keys with a certain value. Any previous
* association will be overwritten in the given interval.
* association will be overwritten in the given interval.
* <p>
* Overlapping intervals are not permitted. A key can only be associated with a single value.
*
@@ -262,7 +263,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
* @param value - the value, or NULL to reset this range.
*/
public void put(TKey lowerBound, TKey upperBound, TValue value) {
// While we don't permit overlapping intervals, we'll still allow overwriting existing intervals.
// While we don't permit overlapping intervals, we'll still allow overwriting existing intervals.
remove(lowerBound, upperBound, true);
invokeEntryAdded(putUnsafe(lowerBound, upperBound, value));
}
@@ -423,7 +424,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
if (point != null) {
Map.Entry<TKey, EndPoint> previous = bounds.floorEntry(inclusive ? point : decrementKey(point));
if (previous != null)
if (previous != null)
return previous.getValue();
}
return null;
@@ -439,7 +440,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
if (point != null) {
Map.Entry<TKey, EndPoint> next = bounds.ceilingEntry(inclusive ? point : incrementKey(point));
if (next != null)
if (next != null)
return next.getValue();
}
return null;
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -48,6 +48,8 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Retrieve a cache loader that will always throw an exception.
* @param <TKey> Type of the key
* @param <TValue> Type of the value
* @return An invalid cache loader.
*/
public static <TKey, TValue> CacheLoader<TKey, TValue> newInvalidCacheLoader() {
@@ -83,6 +85,8 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Initialize a new map.
* @param <TKey> Type of the key
* @param <TValue> Type of the value
* @return The created map.
*/
public static <TKey, TValue> BlockingHashMap<TKey, TValue> create() {
@@ -91,7 +95,7 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Waits until a value has been associated with the given key, and then retrieves that value.
* @param key - the key whose associated value is to be returned
* @param key - the key whose associated value is to be returned
* @return The value to which the specified key is mapped.
* @throws InterruptedException If the current thread got interrupted while waiting.
*/
@@ -118,7 +122,7 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Waits until a value has been associated with the given key, and then retrieves that value.
* @param key - the key whose associated value is to be returned
* @param key - the key whose associated value is to be returned
* @param timeout - the amount of time to wait until an association has been made.
* @param unit - unit of timeout.
* @return The value to which the specified key is mapped, or NULL if the timeout elapsed.
@@ -133,7 +137,7 @@ public class BlockingHashMap<TKey, TValue> {
* <p>
* If timeout is zero, this method will return immediately if it can't find an socket injector.
*
* @param key - the key whose associated value is to be returned
* @param key - the key whose associated value is to be returned
* @param timeout - the amount of time to wait until an association has been made.
* @param unit - unit of timeout.
* @param ignoreInterrupted - TRUE if we should ignore the thread being interrupted, FALSE otherwise.
@@ -6,12 +6,11 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.comphenix.protocol.utility.SafeCacheBuilder;
import com.comphenix.protocol.utility.Util;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.RemovalListener;
@@ -70,6 +69,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
/**
* Construct a new concurrent player map that uses each player's address as key.
* @param <T> Parameter type
* @return Concurrent player map.
*/
public static <T> ConcurrentPlayerMap<T> usingAddress() {
@@ -78,6 +78,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
/**
* Construct a new concurrent player map that uses each player's name as key.
* @param <T> Parameter type
* @return Concurrent player map.
*/
public static <T> ConcurrentPlayerMap<T> usingName() {
@@ -165,7 +166,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
* @return The player with the given key, or NULL if not found.
*/
protected Player findOnlinePlayer(Object key) {
for (Player player : Bukkit.getOnlinePlayers()) {
for (Player player : Util.getOnlinePlayers()) {
if (key.equals(keyMethod.apply(player))) {
return player;
}
@@ -177,7 +178,6 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
* Lookup a player by key in the cache, optionally searching every online player.
* @param key - the key of the player we are locating.
* @return The player, or NULL if not found.
* @throws ExecutionException
*/
protected Player lookupPlayer(Object key) {
try {
@@ -293,7 +293,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
private Iterator<Entry<Player, TValue>> entryIterator() {
// Skip entries with stale data
final Iterator<Entry<Object, TValue>> source = valueLookup.entrySet().iterator();
final AbstractIterator<Entry<Player,TValue>> filtered =
final AbstractIterator<Entry<Player,TValue>> filtered =
new AbstractIterator<Entry<Player,TValue>>() {
@Override
protected Entry<Player, TValue> computeNext() {
@@ -315,12 +315,15 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
// We can't return AbstractIterator directly, as it doesn't permitt the remove() method
return new Iterator<Entry<Player, TValue>>() {
@Override
public boolean hasNext() {
return filtered.hasNext();
}
@Override
public Entry<Player, TValue> next() {
return filtered.next();
}
@Override
public void remove() {
source.remove();
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -25,7 +25,7 @@ import java.util.Set;
/**
* Represents a very quick integer set that uses a lookup table to store membership.
* <p>
* This class is intentionally missing a size method.
* This class is intentionally missing a size method.
* @author Kristian
*/
public class IntegerSet {
@@ -67,7 +67,7 @@ public class IntegerSet {
/**
* Add the given element to the set, or do nothing if it already exists.
* @param element - element to add.
* @throws OutOfBoundsException If the given element is not in the range [0, count).
* @throws ArrayIndexOutOfBoundsException If the given element is not in the range [0, count).
*/
public void add(int element) {
array[element] = true;
@@ -65,7 +65,7 @@ public class PacketTypeSet {
/**
* Remove the given types from the set.
* @param type - the types to remove.
* @param types Types to remove
*/
public synchronized void removeAll(Iterable<? extends PacketType> types) {
for (PacketType type : types) {
@@ -101,7 +101,7 @@ public class PacketTypeSet {
}
/**
* Determine if the type of a packet is in the current set.
* Determine if the type of a packet is in the current set.
* @param packet - the packet.
* @return TRUE if it is, FALSE otherwise.
*/
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -35,6 +35,7 @@ import org.apache.commons.lang.builder.ToStringStyle;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLogger;
import com.comphenix.protocol.collections.ExpireHashMap;
import com.comphenix.protocol.error.Report.ReportBuilder;
import com.comphenix.protocol.events.PacketAdapter;
@@ -49,13 +50,13 @@ import com.google.common.primitives.Primitives;
*/
public class DetailedErrorReporter implements ErrorReporter {
/**
* Report format for printing the current exception count.
* Report format for printing the current exception count.
*/
public static final ReportType REPORT_EXCEPTION_COUNT = new ReportType("Internal exception count: %s!");
public static final String SECOND_LEVEL_PREFIX = " ";
public static final String DEFAULT_PREFIX = " ";
public static final String DEFAULT_SUPPORT_URL = "http://dev.bukkit.org/server-mods/protocollib/";
public static final String DEFAULT_SUPPORT_URL = "https://github.com/dmulloy2/ProtocolLib/issues";
// Users that are informed about errors in the chat
public static final String ERROR_PERMISSION = "protocol.info";
@@ -78,7 +79,7 @@ public class DetailedErrorReporter implements ErrorReporter {
protected String pluginName;
// Whether or not Apache Commons is not present
protected boolean apacheCommonsMissing;
protected static boolean apacheCommonsMissing;
// Whether or not detailed errror reporting is enabled
protected boolean detailedReporting;
@@ -92,6 +93,7 @@ public class DetailedErrorReporter implements ErrorReporter {
/**
* Create a default error reporting system.
* @param plugin - the plugin owner.
*/
public DetailedErrorReporter(Plugin plugin) {
this(plugin, DEFAULT_PREFIX, DEFAULT_SUPPORT_URL);
@@ -120,13 +122,21 @@ public class DetailedErrorReporter implements ErrorReporter {
throw new IllegalArgumentException("Plugin cannot be NULL.");
this.pluginReference = new WeakReference<Plugin>(plugin);
this.pluginName = plugin.getName();
this.pluginName = getNameSafely(plugin);
this.prefix = prefix;
this.supportURL = supportURL;
this.maxErrorCount = maxErrorCount;
this.logger = logger;
}
private String getNameSafely(Plugin plugin) {
try {
return plugin.getName();
} catch (LinkageError e) {
return "ProtocolLib";
}
}
// Attempt to get the logger.
private static Logger getBukkitLogger() {
try {
@@ -272,7 +282,7 @@ public class DetailedErrorReporter implements ErrorReporter {
// Print the main warning
if (report.getException() != null) {
logger.log(level, message, report.getException());
} else {
} else {
logger.log(level, message);
// Remember the call stack
@@ -336,7 +346,7 @@ public class DetailedErrorReporter implements ErrorReporter {
writer.println("at " + supportURL + " with the following data:");
// Now, let us print important exception information
writer.println(" ===== STACK TRACE =====");
writer.println("Stack Trace:");
if (report.getException() != null) {
report.getException().printStackTrace(writer);
@@ -346,7 +356,7 @@ public class DetailedErrorReporter implements ErrorReporter {
}
// Data dump!
writer.println(" ===== DUMP =====");
writer.println("Dump:");
// Relevant parameters
if (report.hasCallerParameters()) {
@@ -356,7 +366,7 @@ public class DetailedErrorReporter implements ErrorReporter {
// Global parameters
for (String param : globalParameters()) {
writer.println(SECOND_LEVEL_PREFIX + param + ":");
writer.println(addPrefix(getStringDescription(getGlobalParameter(param)),
writer.println(addPrefix(getStringDescription(getGlobalParameter(param)),
SECOND_LEVEL_PREFIX + SECOND_LEVEL_PREFIX));
}
@@ -369,14 +379,18 @@ public class DetailedErrorReporter implements ErrorReporter {
writer.println("Version:");
writer.println(addPrefix(plugin.toString(), SECOND_LEVEL_PREFIX));
}
// And java version
writer.println("Java Version:");
writer.println(addPrefix(System.getProperty("java.version"), SECOND_LEVEL_PREFIX));
// Add the server version too
if (Bukkit.getServer() != null) {
writer.println("Server:");
writer.println(addPrefix(Bukkit.getServer().getVersion(), SECOND_LEVEL_PREFIX));
// Inform of this occurrence
if (ERROR_PERMISSION != null) {
if (ERROR_PERMISSION != null) {
Bukkit.getServer().broadcast(
String.format("Error %s (%s) occured in %s.", report.getReportMessage(), report.getException(), sender),
ERROR_PERMISSION
@@ -441,7 +455,7 @@ public class DetailedErrorReporter implements ErrorReporter {
* @param value - object to convert.
* @return String representation.
*/
protected String getStringDescription(Object value) {
public static String getStringDescription(Object value) {
// We can't only rely on toString.
if (value == null) {
return "[NULL]";
@@ -450,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)
System.err.print("[ProtocolLib] 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
@@ -473,7 +489,7 @@ public class DetailedErrorReporter implements ErrorReporter {
* @param test - the object to test.
* @return TRUE if this object is simple enough to simply be printed, FALSE othewise.
*/
protected boolean isSimpleType(Object test) {
protected static boolean isSimpleType(Object test) {
return test instanceof String || Primitives.isWrapperType(test.getClass());
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -56,20 +56,20 @@ public interface ErrorReporter {
/**
* Prints a debug message from the current sender.
* @param sender - the sender.
* @param report - the report builder.
* @param builder - the report builder.
*/
public abstract void reportDebug(Object sender, ReportBuilder builder);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param sender - the object containing the caller method.
* @param report - an error report to include.
*/
public abstract void reportWarning(Object sender, Report report);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param sender - the object containing the caller method.
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportWarning(Object sender, ReportBuilder reportBuilder);
@@ -1,7 +1,6 @@
package com.comphenix.protocol.error;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.CodeSource;
@@ -29,11 +28,11 @@ public final class PluginContext {
for (int i = 1; i < elements.length; i++) {
String caller = getPluginName(elements[i]);
if (caller != null && !caller.equals(current)) {
return caller;
}
}
return null;
}
@@ -41,30 +40,28 @@ public final class PluginContext {
* Lookup the plugin that this method invocation belongs to, and return its file name.
* @param element - the method invocation.
* @return Plugin name, or NULL if not found.
*
*/
public static String getPluginName(StackTraceElement element) {
try {
if (Bukkit.getServer() == null)
if (Bukkit.getServer() == null) {
return null;
}
CodeSource codeSource = Class.forName(element.getClassName()).getProtectionDomain().getCodeSource();
if (codeSource != null) {
String encoding = codeSource.getLocation().getPath();
File path = new File(URLDecoder.decode(encoding, "UTF-8"));
File plugins = getPluginFolder();
if (plugins != null && folderContains(plugins, path)) {
return path.getName();
return path.getName().replaceAll(".jar", "");
}
}
return null; // Cannot find it
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Cannot lookup plugin name.", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot lookup plugin name.", e);
} catch (Throwable ex) {
// throw new RuntimeException("Cannot lookup plugin name.", ex);
}
return null; // Cannot find it
}
/**
@@ -86,6 +83,7 @@ public final class PluginContext {
return true;
file = file.getParentFile();
}
return false;
}
@@ -96,7 +94,7 @@ public final class PluginContext {
private static File getPluginFolder() {
File folder = pluginFolder;
if (folder == null && Bukkit.getServer() != null) {
if (folder == null && Bukkit.getServer() != null) {
Plugin[] plugins = Bukkit.getPluginManager().getPlugins();
if (plugins.length > 0) {
@@ -104,6 +102,7 @@ public final class PluginContext {
pluginFolder = folder;
}
}
return folder;
}
}
@@ -10,7 +10,7 @@ import javax.annotation.Nullable;
*
* @author Kristian
*/
public class Report {
public class Report {
private final ReportType type;
private final Throwable exception;
private final Object[] messageParameters;
@@ -76,7 +76,7 @@ public class Report {
}
/**
* Set the minimum number of nanoseconds to wait until a report of equal type and parameters
* Set the minimum number of nanoseconds to wait until a report of equal type and parameters
* is allowed to be printed again.
* @param rateLimit - number of nanoseconds, or 0 to disable. Cannot be negative.
* @return This builder, for chaining.
@@ -122,8 +122,8 @@ public class Report {
* @param type - the report type that will be used to construct the message.
* @param messageParameters - parameters used to construct the report message.
* @param callerParameters - parameters from the caller method.
*/
protected Report(ReportType type, @Nullable Throwable exception,
*/
protected Report(ReportType type, @Nullable Throwable exception,
@Nullable Object[] messageParameters, @Nullable Object[] callerParameters) {
this(type, exception, messageParameters, callerParameters, 0);
}
@@ -135,8 +135,8 @@ public class Report {
* @param messageParameters - parameters used to construct the report message.
* @param callerParameters - parameters from the caller method.
* @param rateLimit - minimum number of nanoseconds to wait until a report of equal type and parameters is allowed to be printed again.
*/
protected Report(ReportType type, @Nullable Throwable exception,
*/
protected Report(ReportType type, @Nullable Throwable exception,
@Nullable Object[] messageParameters, @Nullable Object[] callerParameters, long rateLimit) {
if (type == null)
throw new IllegalArgumentException("type cannot be NULL.");
@@ -157,7 +157,7 @@ public class Report {
/**
* Retrieve the message parameters that will be used to construc the report message.
* <p<
* <p>
* This should not be confused with the method parameters of the caller method.
* @return Message parameters.
*/
@@ -231,8 +231,8 @@ public class Report {
return true;
if (obj instanceof Report) {
Report other = (Report) obj;
return type == other.type &&
Arrays.equals(callerParameters, other.callerParameters) &&
return type == other.type &&
Arrays.equals(callerParameters, other.callerParameters) &&
Arrays.equals(messageParameters, other.messageParameters);
}
return false;
@@ -2,6 +2,7 @@ package com.comphenix.protocol.events;
import com.comphenix.protocol.injector.GamePhase;
/**
* Represents additional options a listener may require.
*
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -47,7 +47,7 @@ public enum ListenerPriority {
HIGHEST(4),
/**
* Event is listened to purely for monitoring the outcome of an event.
* <p/>
* <p>
* No modifications to the event should be made under this priority.
*/
MONITOR(5);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -32,7 +32,7 @@ import com.google.common.collect.Sets;
/**
* Determines which packets will be observed by a listener, and with what priority.
* @author Kristian
* @author Kristian
*/
public class ListeningWhitelist {
/**
@@ -60,7 +60,7 @@ public class ListeningWhitelist {
* <p>
* Deprecated: Use {@link #newBuilder()} instead.
* @param priority - the listener priority.
* @param whitelist - set of IDs to observe/enable.
* @param whitelist - set of IDs to observe/enable.
*/
@Deprecated
public ListeningWhitelist(ListenerPriority priority, Set<Integer> whitelist) {
@@ -192,7 +192,7 @@ public class ListeningWhitelist {
/**
* Determine if any of the given IDs can be found in the whitelist.
* @param whitelist - whitelist to test.
* @param idList - list of packet IDs to find.
* @param idList - list of packet IDs to find.
* @return TRUE if any of the packets in the list can be found in the whitelist, FALSE otherwise.
*/
public static boolean containsAny(ListeningWhitelist whitelist, int... idList) {
@@ -442,7 +442,7 @@ public class ListeningWhitelist {
/**
* Set the options to copy when constructing new whitelists.
* @param options - the options array.
* @param serverOptions - the options array.
* @return This builder, for chaining.
*/
public Builder options(ListenerOptions[] serverOptions) {
@@ -452,7 +452,7 @@ public class ListeningWhitelist {
/**
* Options to merge into the current set of options.
* @param options - the options array.
* @param serverOptions - the options array.
* @return This builder, for chaining.
*/
public Builder mergeOptions(ListenerOptions... serverOptions) {
@@ -461,7 +461,7 @@ public class ListeningWhitelist {
/**
* Options to merge into the current set of options.
* @param options - the options array.
* @param serverOptions - the options array.
* @return This builder, for chaining.
*/
public Builder mergeOptions(Collection<ListenerOptions> serverOptions) {
@@ -24,12 +24,12 @@ import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
/**
* Marker containing the serialized packet data seen from the network,
* Marker containing the serialized packet data seen from the network,
* or output handlers that will serialize the current packet.
*
* @author Kristian
*/
public abstract class NetworkMarker {
public abstract class NetworkMarker {
public static class EmptyBufferMarker extends NetworkMarker {
public EmptyBufferMarker(@Nonnull ConnectionSide side) {
super(side, (byte[]) null, null);
@@ -48,7 +48,7 @@ public abstract class NetworkMarker {
@Override
protected DataInputStream addHeader(DataInputStream input, PacketType type) {
throw new IllegalStateException("Buffer is empty.");
}
}
}
// Custom network handler
@@ -68,8 +68,9 @@ public abstract class NetworkMarker {
/**
* Construct a new network marker.
* @param side - whether or not this marker belongs to a client or server packet.
* @param side - which side this marker belongs to.
* @param inputBuffer - the read serialized packet data.
* @param type - packet type
*/
public NetworkMarker(@Nonnull ConnectionSide side, ByteBuffer inputBuffer, PacketType type) {
this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
@@ -81,9 +82,9 @@ public abstract class NetworkMarker {
* Construct a new network marker.
* <p>
* The input buffer is only non-null for client-side packets.
* @param side - whether or not this marker belongs to a client or server packet.
* @param side - which side this marker belongs to.
* @param inputBuffer - the read serialized packet data.
* @param handler - handle skipping headers.
* @param type - packet type
*/
public NetworkMarker(@Nonnull ConnectionSide side, byte[] inputBuffer, PacketType type) {
this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
@@ -115,7 +116,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data (excluding the header by default) from the network input stream.
* <p>
* The returned buffer is read-only. If the parent event is a server side packet this
* The returned buffer is read-only. If the parent event is a server side packet this
* method throws {@link IllegalStateException}.
* <p>
* It returns NULL if the packet was transmitted by a plugin locally.
@@ -128,7 +129,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data from the network input stream.
* <p>
* The returned buffer is read-only. If the parent event is a server side packet this
* The returned buffer is read-only. If the parent event is a server side packet this
* method throws {@link IllegalStateException}.
* <p>
* It returns NULL if the packet was transmitted by a plugin locally.
@@ -143,7 +144,7 @@ public abstract class NetworkMarker {
ByteBuffer result = inputBuffer.asReadOnlyBuffer();
try {
if (excludeHeader)
if (excludeHeader)
result = skipHeader(result);
else
result = addHeader(result, type);
@@ -158,7 +159,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data (excluding the header by default) as an input stream.
* <p>
* The data is exactly the same as in {@link #getInputBuffer()}.
* The data is exactly the same as in {@link #getInputBuffer()}.
* @see #getInputBuffer()
* @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
*/
@@ -169,7 +170,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data as an input stream.
* <p>
* The data is exactly the same as in {@link #getInputBuffer()}.
* The data is exactly the same as in {@link #getInputBuffer()}.
* @see #getInputBuffer()
* @param excludeHeader - whether or not to exclude the packet ID header.
* @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
@@ -186,7 +187,7 @@ public abstract class NetworkMarker {
);
try {
if (excludeHeader)
if (excludeHeader)
input = skipHeader(input);
else
input = addHeader(input, type);
@@ -207,7 +208,7 @@ public abstract class NetworkMarker {
/**
* Enqueue the given output handler for managing how the current packet will be written to the network stream.
* <p>
* Note that output handlers are not serialized, as most consumers will probably implement them using anonymous classes.
* Note that output handlers are not serialized, as most consumers will probably implement them using anonymous classes.
* It is not safe to serialize anonymous classes, as their name depend on the order in which they are declared in the parent class.
* <p>
* This can only be invoked on server side packet events.
@@ -261,10 +262,10 @@ public abstract class NetworkMarker {
}
/**
* Add a listener that is invoked after a packet has been successfully sent to the client, or received
* by the server.
* Add a listener that is invoked after a packet has been successfully sent to the client, or received
* by the server.
* <p>
* Received packets are not guarenteed to have been fully processed, but packets passed
* Received packets are not guarenteed to have been fully processed, but packets passed
* to {@link ProtocolManager#recieveClientPacket(Player, PacketContainer)} will be processed after the
* current packet event.
* <p>
@@ -324,7 +325,9 @@ public abstract class NetworkMarker {
* Return a byte buffer without the header in the current packet.
* <p>
* It's safe to modify the position of the buffer.
* @param buffer - a read-only byte source.
* @param buffer - a read-only byte source.
* @return A byte buffer without the header in the current packet.
* @throws IOException If integer reading fails
*/
protected ByteBuffer skipHeader(ByteBuffer buffer) throws IOException {
skipHeader(new DataInputStream(new ByteBufferInputStream(buffer)));
@@ -335,13 +338,16 @@ public abstract class NetworkMarker {
* Return an input stream without the header in the current packet.
* <p>
* It's safe to modify the input stream.
* @param input - input stream
* @return An input stream without the header
* @throws IOException If integer reading fails
*/
protected abstract DataInputStream skipHeader(DataInputStream input) throws IOException;
/**
* Return the byte buffer prepended with the packet header.
* @param buffer - the read-only byte buffer.
* @param type - the current packet.
* @param buffer - the read-only byte buffer.
* @param type - the current packet.
* @return The byte buffer.
*/
protected abstract ByteBuffer addHeader(ByteBuffer buffer, PacketType type);
@@ -349,7 +355,7 @@ public abstract class NetworkMarker {
/**
* Return the input stream prepended with the packet header.
* @param input - the input stream.
* @param type - the current packet.
* @param type - the current packet.
* @return The byte buffer.
*/
protected abstract DataInputStream addHeader(DataInputStream input, PacketType type);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -50,7 +50,7 @@ public abstract class PacketAdapter implements PacketListener {
*/
public PacketAdapter(@Nonnull AdapterParameteters params) {
this(
checkValidity(params).plugin, params.connectionSide, params.listenerPriority,
checkValidity(params).plugin, params.connectionSide, params.listenerPriority,
params.gamePhase, params.options, params.packets
);
}
@@ -58,7 +58,6 @@ public abstract class PacketAdapter implements PacketListener {
/**
* Initialize a packet listener with the given parameters.
* @param plugin - the plugin.
* @param listenerPriority - the priority.
* @param types - the packet types.
*/
public PacketAdapter(Plugin plugin, PacketType... types) {
@@ -241,7 +240,7 @@ public abstract class PacketAdapter implements PacketListener {
*/
@Deprecated
public PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, Integer... packets) {
this(plugin, connectionSide, listenerPriority, gamePhase, options,
@@ -251,7 +250,7 @@ public abstract class PacketAdapter implements PacketListener {
// For internal use only
private PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, PacketType... packets) {
if (plugin == null)
@@ -272,7 +271,7 @@ public abstract class PacketAdapter implements PacketListener {
// Special case that allows us to specify optionIntercept().
if (connectionSide == ConnectionSide.BOTH) {
serverOptions = except(serverOptions, new ListenerOptions[0],
serverOptions = except(serverOptions, new ListenerOptions[0],
ListenerOptions.INTERCEPT_INPUT_BUFFER);
}
@@ -347,23 +346,21 @@ public abstract class PacketAdapter implements PacketListener {
* @return Name of the given plugin.
*/
public static String getPluginName(Plugin plugin) {
// Try to get the plugin name
if (plugin == null)
return "UNKNOWN";
try {
if (plugin == null)
return "UNKNOWN";
else
return plugin.getName();
return plugin.getName();
} catch (NoSuchMethodError e) {
return plugin.toString();
}
}
@Override
public String toString() {
// This is used by the error reporter
return String.format("PacketAdapter[plugin=%s, sending=%s, receiving=%s]",
getPluginName(this),
public String toString() {
// This is used by the error reporter
return String.format("PacketAdapter[plugin=%s, sending=%s, receiving=%s]",
getPluginName(this),
sendingWhitelist,
receivingWhitelist);
}
@@ -441,7 +438,7 @@ public abstract class PacketAdapter implements PacketListener {
}
/**
* Set this adapter to also look for client-side packets.
* Set this adapter to also look for client-side packets.
* @return This builder, for chaining.
*/
public AdapterParameteters clientSide() {
@@ -449,7 +446,7 @@ public abstract class PacketAdapter implements PacketListener {
}
/**
* Set this adapter to also look for server-side packets.
* Set this adapter to also look for server-side packets.
* @return This builder, for chaining.
*/
public AdapterParameteters serverSide() {
@@ -457,7 +454,7 @@ public abstract class PacketAdapter implements PacketListener {
}
/**
* Set the the event priority, where the execution is in ascending order from lowest to highest.
* Set the the event priority, where the execution is in ascending order from lowest to highest.
* <p>
* Default is {@link ListenerPriority#NORMAL}.
* @param listenerPriority - the new event priority.
@@ -2,21 +2,24 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.events;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
@@ -29,6 +32,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -37,15 +41,14 @@ import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.buffer.UnpooledByteBufAllocator;
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;
@@ -61,22 +64,40 @@ 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;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.StreamSerializer;
import com.comphenix.protocol.wrappers.BlockPosition;
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.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.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;
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;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import com.comphenix.protocol.wrappers.WrappedAttribute;
import com.comphenix.protocol.wrappers.WrappedBlockData;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
@@ -112,6 +133,7 @@ public class PacketContainer implements Serializable {
instanceProvider(DefaultInstances.DEFAULT).
andThen(BukkitCloner.class).
andThen(ImmutableDetector.class).
andThen(OptionalCloner.class).
andThen(CollectionCloner.class).
andThen(getSpecializedDeepClonerFactory()).
build();
@@ -134,8 +156,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>
@@ -149,10 +171,9 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* <p>
* Deprecated: Use {@link #PacketContainer(PacketType, Object))} instead.
* @param id - ID of the given packet.
* @param handle - contained packet.
* @deprecated Use {@link #PacketContainer(PacketType, Object)} instead
*/
@Deprecated
public PacketContainer(int id, Object handle) {
@@ -161,11 +182,10 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* <p>
* Deprecated: Use {@link #PacketContainer(PacketType, Object, StructureModifier))} instead.
* @param id - ID of the given packet.
* @param handle - contained packet.
* @param structure - structure modifier.
* @deprecated Use {@link #PacketContainer(PacketType, Object, StructureModifier)} instead
*/
@Deprecated
public PacketContainer(int id, Object handle, StructureModifier<Object> structure) {
@@ -182,7 +202,7 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* @param id - ID of the given packet.
* @param type - Type of the given packet.
* @param handle - contained packet.
*/
public PacketContainer(PacketType type, Object handle) {
@@ -191,7 +211,7 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* @param id - ID of the given packet.
* @param type - Type of the given packet.
* @param handle - contained packet.
* @param structure - structure modifier.
*/
@@ -223,7 +243,7 @@ public class PacketContainer implements Serializable {
}
/**
* Retrieves the underlying Minecraft packet.
* Retrieves the underlying Minecraft packet.
* @return Underlying Minecraft packet.
*/
public Object getHandle() {
@@ -240,6 +260,7 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for every field with the given type.
* @param <T> Type
* @param primitiveType - the type to find.
* @return A modifier for this specific type.
*/
@@ -362,10 +383,10 @@ public class PacketContainer implements Serializable {
* internal Minecraft ItemStack.
* @return A modifier for ItemStack array fields.
*/
public StructureModifier<ItemStack[]> getItemArrayModifier() {
public StructureModifier<ItemStack[]> getItemArrayModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<ItemStack[]>withType(
MinecraftReflection.getItemStackArrayClass(),
MinecraftReflection.getItemStackArrayClass(),
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
}
@@ -376,9 +397,9 @@ public class PacketContainer implements Serializable {
* @return A modifier for maps of statistics.
*/
public StructureModifier<Map<WrappedStatistic, Integer>> getStatisticMaps() {
return structureModifier.withType(Map.class,
return structureModifier.withType(Map.class,
BukkitConverters.<WrappedStatistic, Integer>getMapConverter(
MinecraftReflection.getStatisticClass(),
MinecraftReflection.getStatisticClass(),
BukkitConverters.getWrappedStatisticConverter()
)
);
@@ -394,7 +415,7 @@ public class PacketContainer implements Serializable {
public StructureModifier<WorldType> getWorldTypeModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WorldType>withType(
MinecraftReflection.getWorldTypeClass(),
MinecraftReflection.getWorldTypeClass(),
BukkitConverters.getWorldTypeConverter());
}
@@ -405,7 +426,7 @@ public class PacketContainer implements Serializable {
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedDataWatcher>withType(
MinecraftReflection.getDataWatcherClass(),
MinecraftReflection.getDataWatcherClass(),
BukkitConverters.getDataWatcherConverter());
}
@@ -414,7 +435,7 @@ public class PacketContainer implements Serializable {
* <p>
* Note that entities are transmitted by integer ID, and the type may not be enough
* to distinguish between entities and other values. Thus, this structure modifier
* MAY return null or invalid entities for certain fields. Using the correct index
* MAY return null or invalid entities for certain fields. Using the correct index
* is essential.
*
* @param world - the world each entity is currently occupying.
@@ -432,7 +453,7 @@ public class PacketContainer implements Serializable {
* <p>
* Note that entities are transmitted by integer ID, and the type may not be enough
* to distinguish between entities and other values. Thus, this structure modifier
* MAY return null or invalid entities for certain fields. Using the correct index
* MAY return null or invalid entities for certain fields. Using the correct index
* is essential.
*
* @param event - the original packet event.
@@ -453,7 +474,18 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getChunkPositionClass(),
ChunkPosition.getConverter());
}
/**
* Retrieves a read/write structure for block positions.
* @return A modifier for a BlockPosition.
*/
public StructureModifier<BlockPosition> getBlockPositionModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.withType(
MinecraftReflection.getBlockPositionClass(),
BlockPosition.getConverter());
}
/**
* Retrieves a read/write structure for wrapped ChunkCoordIntPairs.
* @return A modifier for ChunkCoordIntPair.
@@ -475,7 +507,18 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getNBTBaseClass(),
BukkitConverters.getNbtConverter());
}
/**
* Retrieves a read/write structure for Vectors.
* @return A modifier for Vectors.
*/
public StructureModifier<Vector> getVectors() {
// Automatically marshal between Vec3d and the Bukkit wrapper
return structureModifier.withType(
MinecraftReflection.getVec3DClass(),
BukkitConverters.getVectorConverter());
}
/**
* Retrieves a read/write structure for collections of attribute snapshots.
* <p>
@@ -488,7 +531,7 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getAttributeSnapshotClass(),
MinecraftReflection.getAttributeSnapshotClass(),
BukkitConverters.getWrappedAttributeConverter())
);
}
@@ -498,6 +541,7 @@ public class PacketContainer implements Serializable {
* <p>
* This modifier will automatically marshall between the visible ProtocolLib ChunkPosition and the
* internal Minecraft ChunkPosition.
*
* @return A modifier for ChunkPosition list fields.
*/
public StructureModifier<List<ChunkPosition>> getPositionCollectionModifier() {
@@ -505,11 +549,29 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getChunkPositionClass(),
MinecraftReflection.getChunkPositionClass(),
ChunkPosition.getConverter())
);
}
/**
* Retrieves a read/write structure for collections of chunk positions.
* <p>
* This modifier will automatically marshall between the visible ProtocolLib BlockPosition and the
* internal Minecraft BlockPosition.
*
* @return A modifier for ChunkPosition list fields.
*/
public StructureModifier<List<BlockPosition>> getBlockPositionCollectionModifier() {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getBlockPositionClass(),
BlockPosition.getConverter())
);
}
/**
* Retrieves a read/write structure for collections of watchable objects.
* <p>
@@ -522,12 +584,11 @@ 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>
@@ -551,14 +612,42 @@ public class PacketContainer implements Serializable {
public StructureModifier<WrappedGameProfile> getGameProfiles() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedGameProfile>withType(
GameProfile.class, BukkitConverters.getWrappedGameProfileConverter());
MinecraftReflection.getGameProfileClass(), BukkitConverters.getWrappedGameProfileConverter());
}
/**
* Retrieves a read/write structure for BlockData in Minecraft 1.8.
* <p>
* This modifier will automatically marshall between WrappedBlockData and the
* internal Minecraft IBlockData.
* @return A modifier for BlockData fields.
*/
public StructureModifier<WrappedBlockData> getBlockData() {
// Convert to and from our wrapper
return structureModifier.<WrappedBlockData>withType(
MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter());
}
/**
* Retrieves a read/write structure for MultiBlockChangeInfo arrays in Minecraft 1.8.
* <p>
* This modifier will automatically marshall between MultiBlockChangeInfo and the
* internal Minecraft MultiBlockChangeInfo.
* @return A modifier for BlockData fields.
*/
public StructureModifier<MultiBlockChangeInfo[]> getMultiBlockChangeInfoArrays() {
ChunkCoordIntPair chunk = getChunkCoordIntPairs().read(0);
// Convert to and from our wrapper
return structureModifier.<MultiBlockChangeInfo[]>withType(
MinecraftReflection.getMultiBlockChangeInfoArrayClass(), MultiBlockChangeInfo.getArrayConverter(chunk));
}
/**
* Retrieves a read/write structure for chat components in Minecraft 1.7.2.
* <p>
* This modifier will automatically marshall between WrappedChatComponent and the
* internal Minecraft GameProfile.
* internal Minecraft IChatBaseComponent.
* @return A modifier for ChatComponent fields.
*/
public StructureModifier<WrappedChatComponent> getChatComponents() {
@@ -566,6 +655,20 @@ public class PacketContainer implements Serializable {
return structureModifier.<WrappedChatComponent>withType(
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
}
/**
* Retrieves a read/write structure for arrays of chat components.
* <p>
* This modifier will automatically marshall between WrappedChatComponent and the
* internal Minecraft IChatBaseComponent.
* @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()));
}
/**
* Retrieve a read/write structure for the ServerPing fields in the following packet: <br>
@@ -580,6 +683,23 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getServerPingClass(), BukkitConverters.getWrappedServerPingConverter());
}
/**
* Retrieve a read/write structure for the PlayerInfoData list fields in the following packet: <br>
* <ul>
* <li>{@link PacketType.Play.Server#PLAYER_INFO}
* </ul>
* @return A modifier for PlayerInfoData list fields.
*/
public StructureModifier<List<PlayerInfoData>> getPlayerInfoDataLists() {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getPlayerInfoDataClass(),
PlayerInfoData.getConverter())
);
}
/**
* Retrieve a read/write structure for the Protocol enum in 1.7.2.
* @return A modifier for Protocol enum fields.
@@ -629,7 +749,7 @@ public class PacketContainer implements Serializable {
return structureModifier.<EntityUseAction>withType(
EnumWrappers.getEntityUseActionClass(), EnumWrappers.getEntityUseActionConverter());
}
/**
* Retrieve a read/write structure for the NativeGameMode enum in 1.7.2.
* @return A modifier for NativeGameMode enum fields.
@@ -639,7 +759,172 @@ public class PacketContainer implements Serializable {
return structureModifier.<NativeGameMode>withType(
EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter());
}
/**
* Retrieve a read/write structure for the ResourcePackStatus enum in 1.8.
* @return A modifier for ResourcePackStatus enum fields.
*/
public StructureModifier<ResourcePackStatus> getResourcePackStatus() {
// Convert to and from the wrapper
return structureModifier.<ResourcePackStatus>withType(
EnumWrappers.getResourcePackStatusClass(), EnumWrappers.getResourcePackStatusConverter());
}
/**
* Retrieve a read/write structure for the PlayerInfo enum in 1.8.
* @return A modifier for PlayerInfoAction enum fields.
*/
public StructureModifier<PlayerInfoAction> getPlayerInfoAction() {
// Convert to and from the wrapper
return structureModifier.<PlayerInfoAction>withType(
EnumWrappers.getPlayerInfoActionClass(), EnumWrappers.getPlayerInfoActionConverter());
}
/**
* Retrieve a read/write structure for the TitleAction enum in 1.8.
* @return A modifier for TitleAction enum fields.
*/
public StructureModifier<TitleAction> getTitleActions() {
// Convert to and from the wrapper
return structureModifier.<TitleAction>withType(
EnumWrappers.getTitleActionClass(), EnumWrappers.getTitleActionConverter());
}
/**
* Retrieve a read/write structure for the WorldBorderAction enum in 1.8.
* @return A modifier for WorldBorderAction enum fields.
*/
public StructureModifier<WorldBorderAction> getWorldBorderActions() {
// Convert to and from the wrapper
return structureModifier.<WorldBorderAction>withType(
EnumWrappers.getWorldBorderActionClass(), EnumWrappers.getWorldBorderActionConverter());
}
/**
* Retrieve a read/write structure for the CombatEventType enum in 1.8.
* @return A modifier for CombatEventType enum fields.
*/
public StructureModifier<CombatEventType> getCombatEvents() {
// Convert to and from the wrapper
return structureModifier.<CombatEventType>withType(
EnumWrappers.getCombatEventTypeClass(), EnumWrappers.getCombatEventTypeConverter());
}
/**
* Retrieve a read/write structure for the PlayerDigType enum in 1.8.
* @return A modifier for PlayerDigType enum fields.
*/
public StructureModifier<PlayerDigType> getPlayerDigTypes() {
// Convert to and from the wrapper
return structureModifier.<PlayerDigType>withType(
EnumWrappers.getPlayerDigTypeClass(), EnumWrappers.getPlayerDiggingActionConverter());
}
/**
* Retrieve a read/write structure for the PlayerAction enum in 1.8.
* @return A modifier for PlayerAction enum fields.
*/
public StructureModifier<PlayerAction> getPlayerActions() {
// Convert to and from the wrapper
return structureModifier.<PlayerAction>withType(
EnumWrappers.getPlayerActionClass(), EnumWrappers.getEntityActionConverter());
}
/**
* Retrieve a read/write structure for the ScoreboardAction enum in 1.8.
* @return A modifier for ScoreboardAction enum fields.
*/
public StructureModifier<ScoreboardAction> getScoreboardActions() {
// Convert to and from the wrapper
return structureModifier.<ScoreboardAction>withType(
EnumWrappers.getScoreboardActionClass(), EnumWrappers.getUpdateScoreActionConverter());
}
/**
* Retrieve a read/write structure for the Particle enum in 1.8.
* @return A modifier for Particle enum fields.
*/
public StructureModifier<Particle> getParticles() {
// Convert to and from the wrapper
return structureModifier.<Particle>withType(
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());
}
/**
* Retrive 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());
}
/**
* Retrive 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 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>
@@ -663,7 +948,7 @@ public class PacketContainer implements Serializable {
* Create a shallow copy of the current packet.
* <p>
* This merely writes the content of each field to the new class directly,
* without performing any expensive copies.
* without performing any expensive copies.
*
* @return A shallow copy of the current packet.
*/
@@ -683,7 +968,7 @@ public class PacketContainer implements Serializable {
* @return A deep copy of the current packet.
*/
public PacketContainer deepClone() {
Object clonedPacket = null;
Object clonedPacket = null;
// Fall back on the alternative (but slower) method of reading and writing back the packet
if (CLONING_UNSUPPORTED.contains(type)) {
@@ -696,13 +981,14 @@ public class PacketContainer implements Serializable {
// To save space, we'll skip copying the inflated buffers in packet 51 and 56
private static Function<BuilderParameters, Cloner> getSpecializedDeepClonerFactory() {
// Look at what you've made me do Java, look at it!!
// Look at what you've made me do Java, look at it!!
return new Function<BuilderParameters, Cloner>() {
@Override
public Cloner apply(@Nullable BuilderParameters param) {
return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
this.writer = new ObjectWriter() {
protected void transformField(StructureModifier<Object> modifierSource,
@Override
protected void transformField(StructureModifier<Object> modifierSource,
StructureModifier<Object> modifierDest, int fieldIndex) {
// No need to clone inflated buffers
if (modifierSource.getField(fieldIndex).getName().startsWith("inflatedBuffer"))
@@ -717,7 +1003,7 @@ public class PacketContainer implements Serializable {
}
private void writeObject(ObjectOutputStream output) throws IOException {
// Default serialization
// Default serialization
output.defaultWriteObject();
// We'll take care of NULL packets as well
@@ -727,15 +1013,14 @@ public class PacketContainer implements Serializable {
if (MinecraftReflection.isUsingNetty()) {
ByteBuf buffer = createPacketBuffer();
MinecraftMethods.getPacketWriteByteBufMethod().invoke(handle, buffer);
output.writeInt(buffer.readableBytes());
buffer.readBytes(output, buffer.readableBytes());
} else {
// Call the write-method
output.writeInt(-1);
getMethodLazily(writeMethods, handle.getClass(), "write", DataOutput.class).
invoke(handle, new DataOutputStream(output));
invoke(handle, new DataOutputStream(output));
}
} catch (IllegalArgumentException e) {
@@ -792,9 +1077,81 @@ public class PacketContainer implements Serializable {
* @return The packet data serializer.
*/
private ByteBuf createPacketBuffer() {
return MinecraftReflection.getPacketDataSerializer(UnpooledByteBufAllocator.DEFAULT.buffer());
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
// This map will only be initialized if it is actually used
private Map<String, Object> metadata;
/**
* Gets the metadata value for a given key.
*
* @param key Metadata key
* @return Metadata value, or null if nonexistent.
*/
public Object getMetadata(String key) {
if (metadata != null) {
return metadata.get(key);
}
return null;
}
/**
* Adds metadata to this packet.
* <p>
* Note: Since metadata is lazily initialized, this may result in the creation of the metadata map.
*
* @param key Metadata key
* @param value Metadata value
*/
public void addMetadata(String key, Object value) {
if (metadata == null) {
metadata = new HashMap<String, Object>();
}
metadata.put(key, value);
}
/**
* Removes metadata from this packet.
* <p>
* Note: If this operation leaves the metadata map empty, the map will be set to null.
*
* @param key Metadata key
* @return The previous value, or null if nonexistant.
*/
public Object removeMetadata(String key) {
if (metadata != null) {
Object value = metadata.remove(key);
if (metadata.isEmpty()) {
metadata = null;
}
return value;
}
return null;
}
/**
* Whether or not this packet has metadata for a given key.
*
* @param key Metadata key
* @return True if this packet has metadata for the key, false if not.
*/
public boolean hasMetadata(String key) {
return metadata != null && metadata.containsKey(key);
}
/**
* Retrieve the cached method concurrently.
* @param lookup - a lazy lookup cache.
@@ -803,7 +1160,7 @@ public class PacketContainer implements Serializable {
* @param parameterClass - the one parameter type in the method.
* @return Reflected method.
*/
private Method getMethodLazily(ConcurrentMap<Class<?>, Method> lookup,
private Method getMethodLazily(ConcurrentMap<Class<?>, Method> lookup,
Class<?> handleClass, String methodName, Class<?> parameterClass) {
Method method = lookup.get(handleClass);
@@ -833,13 +1190,14 @@ public class PacketContainer implements Serializable {
private static class ItemStackArrayConverter implements EquivalentConverter<ItemStack[]> {
final EquivalentConverter<ItemStack> stackConverter = BukkitConverters.getItemStackConverter();
@Override
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
Class<?> nmsStack = MinecraftReflection.getItemStackClass();
Object[] result = (Object[]) Array.newInstance(nmsStack, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
}
return result;
}
@@ -861,4 +1219,46 @@ public class PacketContainer implements Serializable {
return ItemStack[].class;
}
}
}
/**
* Represents an equivalent converter for ChatComponent arrays.
* @author dmulloy2
*/
private static class WrappedChatComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
@Override
public Object getGeneric(Class<?>genericType, WrappedChatComponent[] specific) {
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
result[i] = componentConverter.getGeneric(nmsComponent, specific[i]);
}
return result;
}
@Override
public WrappedChatComponent[] getSpecific(Object generic) {
Object[] input = (Object[]) generic;
WrappedChatComponent[] result = new WrappedChatComponent[input.length];
// Add the wrapper
for (int i = 0; i < result.length; i++) {
result[i] = componentConverter.getSpecific(input[i]);
}
return result;
}
@Override
public Class<WrappedChatComponent[]> getSpecificType() {
return WrappedChatComponent[].class;
}
}
@Override
public String toString() {
return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]";
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -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;
@@ -39,7 +40,7 @@ import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
/**
* Represents a packet sending or receiving event. Changes to the packet will be
* Represents a packet sending or receiving event. Changes to the packet will be
* reflected in the final version to be sent or received. It is also possible to cancel an event.
* @author Kristian
*/
@@ -47,7 +48,7 @@ public class PacketEvent extends EventObject implements Cancellable {
public static final ReportType REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING = new ReportType(
"Plugin %s changed packet type from %s to %s in packet listener. This is confusing for other plugins! (Not an error, though!)");
private static final SetMultimap<PacketType, PacketType> CHANGE_WARNINGS =
private static final SetMultimap<PacketType, PacketType> CHANGE_WARNINGS =
Multimaps.synchronizedSetMultimap(HashMultimap.<PacketType, PacketType>create());
/**
@@ -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();
}
/**
@@ -229,9 +230,9 @@ public class PacketEvent extends EventObject implements Cancellable {
if (this.packet != null && !Objects.equal(oldType, newType)) {
// Only report this once
if (CHANGE_WARNINGS.put(oldType, newType)) {
ProtocolLibrary.getErrorReporter().reportWarning(this,
ProtocolLibrary.getErrorReporter().reportWarning(this,
Report.newBuilder(REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING).
messageParam(oldType, newType).
messageParam(PluginContext.getPluginCaller(new Exception()), oldType, newType).
build());
}
}
@@ -261,6 +262,7 @@ public class PacketEvent extends EventObject implements Cancellable {
* Retrieves whether or not the packet should be cancelled.
* @return TRUE if it should be cancelled, FALSE otherwise.
*/
@Override
public boolean isCancelled() {
return cancel;
}
@@ -307,6 +309,7 @@ public class PacketEvent extends EventObject implements Cancellable {
*
* @param cancel - TRUE if it should be cancelled, FALSE otherwise.
*/
@Override
public void setCancelled(boolean cancel) {
if (readOnly)
throw new IllegalStateException("The packet event is read-only.");
@@ -354,12 +357,12 @@ public class PacketEvent extends EventObject implements Cancellable {
return asyncMarker;
}
/**
* Set the asynchronous marker.
* Set the asynchronous marker.
* <p>
* If the marker is non-null at the end of an synchronous event processing, the packet will be scheduled
* to be processed asynchronously with the given settings.
* <p>
* Note that if there are no asynchronous events that can receive this packet, the marker should be NULL.
* Note that if there are no asynchronous events that can receive this packet, the marker should be NULL.
* @param asyncMarker - the new asynchronous marker, or NULL.
* @throws IllegalStateException If the current event is asynchronous.
*/
@@ -425,7 +428,7 @@ public class PacketEvent extends EventObject implements Cancellable {
}
private void writeObject(ObjectOutputStream output) throws IOException {
// Default serialization
// Default serialization
output.defaultWriteObject();
// Write the name of the player (or NULL if it's not set)
@@ -439,10 +442,15 @@ public class PacketEvent extends EventObject implements Cancellable {
final SerializedOfflinePlayer serialized = (SerializedOfflinePlayer) input.readObject();
// Better than nothing
if (serialized != null) {
if (serialized != null) {
// Store it, to prevent weak reference from cleaning up the reference
offlinePlayer = serialized.getPlayer();
playerReference = new WeakReference<Player>(offlinePlayer);
}
}
}
@Override
public String toString() {
return "PacketEvent[player=" + getPlayer() + ", packet=" + packet + "]";
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -34,7 +34,7 @@ public interface PacketListener {
* <p>
* This method is executed on the main thread in 1.6.4 and earlier, and thus the Bukkit API is safe to use.
* <p>
* In Minecraft 1.7.2 and later, this method MAY be executed asynchronously, but only if {@link ListenerOptions#ASYNC}
* In Minecraft 1.7.2 and later, this method MAY be executed asynchronously, but only if {@link ListenerOptions#ASYNC}
* have been specified in the listener. This is off by default.
* @param event - the packet that should be sent.
*/
@@ -43,9 +43,9 @@ public interface PacketListener {
/**
* Invoked right before a received packet from a client is being processed.
* <p>
* <b>WARNING</b>: </br>
* This method will be called <i>asynchronously</i>! You should synchronize with the main
* thread using {@link org.bukkit.scheduler.BukkitScheduler#scheduleSyncDelayedTask(Plugin, Runnable, long) scheduleSyncDelayedTask}
* <b>WARNING</b>: <br>
* This method will be called <i>asynchronously</i>! You should synchronize with the main
* thread using {@link org.bukkit.scheduler.BukkitScheduler#scheduleSyncDelayedTask(Plugin, Runnable, long) scheduleSyncDelayedTask}
* if you need to call the Bukkit API.
* @param event - the packet that has been received.
*/
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -38,8 +38,8 @@ import com.google.common.primitives.Primitives;
* <p>
* Typical conversions include:
* <ul>
* <li>org.bukkit.entity.Player -> net.minecraft.server.EntityPlayer</li>
* <li>org.bukkit.World -> net.minecraft.server.WorldServer</li>
* <li>org.bukkit.entity.Player to net.minecraft.server.EntityPlayer</li>
* <li>org.bukkit.World to net.minecraft.server.WorldServer</li>
* </ul>
*
* @author Kristian
@@ -91,7 +91,7 @@ public class BukkitUnwrapper implements Unwrapper {
@Override
public Object unwrapItem(Object wrappedObject) {
// Special case
if (wrappedObject == null)
if (wrappedObject == null)
return null;
Class<?> currentClass = PacketConstructor.getClass(wrappedObject);
@@ -149,7 +149,7 @@ public class BukkitUnwrapper implements Unwrapper {
try {
final Method find = type.getMethod("getHandle");
// It's thread safe, as getMethod should return the same handle
// It's thread safe, as getMethod should return the same handle
Unwrapper methodUnwrapper = new Unwrapper() {
@Override
public Object unwrapItem(Object wrappedObject) {
@@ -159,7 +159,7 @@ public class BukkitUnwrapper implements Unwrapper {
return find.invoke(wrappedObject);
} catch (IllegalArgumentException e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_ILLEGAL_ARGUMENT).error(e).callerParam(wrappedObject, find)
);
} catch (IllegalAccessException e) {
@@ -178,7 +178,7 @@ public class BukkitUnwrapper implements Unwrapper {
return methodUnwrapper;
} catch (SecurityException e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_SECURITY_LIMITATION).error(e).callerParam(type)
);
} catch (NoSuchMethodException e) {
@@ -188,7 +188,7 @@ public class BukkitUnwrapper implements Unwrapper {
if (fieldUnwrapper != null)
return fieldUnwrapper;
else
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
}
@@ -214,7 +214,7 @@ public class BukkitUnwrapper implements Unwrapper {
return checkClass((Class<?>) wrappedObject, type, find.getType());
return FieldUtils.readField(find, wrappedObject, true);
} catch (IllegalAccessException e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_READ_FIELD_HANDLE).error(e).callerParam(wrappedObject, find)
);
return null;
@@ -227,7 +227,7 @@ public class BukkitUnwrapper implements Unwrapper {
} else {
// Inform about this too
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_READ_FIELD_HANDLE).callerParam(find)
);
return null;
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -38,7 +38,7 @@ import com.google.common.primitives.Primitives;
*/
public class PacketConstructor {
/**
* A packet constructor that automatically converts Bukkit types to their NMS conterpart.
* A packet constructor that automatically converts Bukkit types to their NMS conterpart.
* <p>
* Remember to call withPacket().
*/
@@ -59,7 +59,7 @@ public class PacketConstructor {
private PacketConstructor(Constructor<?> constructorMethod) {
this.constructorMethod = constructorMethod;
this.unwrappers = Lists.newArrayList((Unwrapper) new BukkitUnwrapper(new RethrowErrorReporter() ));
this.unwrappers.addAll(BukkitConverters.getUnwrappers());
this.unwrappers.addAll(BukkitConverters.getUnwrappers());
}
private PacketConstructor(PacketType type, Constructor<?> constructorMethod, List<Unwrapper> unwrappers, Unwrapper[] paramUnwrapper) {
@@ -104,7 +104,7 @@ public class PacketConstructor {
/**
* Create a packet constructor that creates packets using the given ID.
* <p>
* Note that if you pass a Class<?> as a value, it will use its type directly.
* Note that if you pass a Class as a value, it will use its type directly.
* <p>
* Deprecated: Use {@link #withPacket(PacketType, Object[])} instead.
* @param id - legacy (1.6.4) packet ID.
@@ -120,7 +120,7 @@ public class PacketConstructor {
/**
* Create a packet constructor that creates packets using the given types.
* <p>
* Note that if you pass a Class<?> as a value, it will use its type directly.
* Note that if you pass a Class as a value, it will use its type directly.
* @param type - the type of the packet to create.
* @param values - the values that will match each parameter in the desired constructor.
* @return A packet constructor with these types.
@@ -129,7 +129,7 @@ public class PacketConstructor {
public PacketConstructor withPacket(PacketType type, Object[] values) {
Class<?>[] types = new Class<?>[values.length];
Throwable lastException = null;
Unwrapper[] paramUnwrapper = new Unwrapper[values.length];
Unwrapper[] paramUnwrapper = new Unwrapper[values.length];
for (int i = 0; i < types.length; i++) {
// Default type
@@ -258,7 +258,7 @@ public class PacketConstructor {
/**
* Convert the given wrapped object to the equivalent net.minecraft.server object.
* <p>
* Note that we may pass in a class instead of object - in that case, the unwrapper should
* Note that we may pass in a class instead of object - in that case, the unwrapper should
* return the equivalent NMS class.
* @param wrappedObject - wrapped object or class.
* @return The equivalent net.minecraft.server object or class.
@@ -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;
}
@@ -1,4 +1,24 @@
package com.comphenix.protocol.utility;
/**
* 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 io.netty.buffer.AbstractByteBuf;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -12,23 +32,19 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.channels.WritableByteChannel;
import net.minecraft.util.io.netty.buffer.AbstractByteBuf;
import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.buffer.ByteBufAllocator;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.io.ByteStreams;
import com.google.common.io.LimitInputStream;
/**
* Construct a ByteBuf around an input stream and an output stream.
* <p>
* Note that as streams usually don't support seeking, this implementation will ignore
* Note that as streams usually don't support seeking, this implementation will ignore
* all indexing in the byte buffer.
* @author Kristian
*/
class ByteBufAdapter extends AbstractByteBuf {
public class NettyByteBufAdapter extends AbstractByteBuf {
private DataInputStream input;
private DataOutputStream output;
@@ -38,7 +54,7 @@ class ByteBufAdapter extends AbstractByteBuf {
private static final int CAPACITY = Short.MAX_VALUE;
private ByteBufAdapter(DataInputStream input, DataOutputStream output) {
private NettyByteBufAdapter(DataInputStream input, DataOutputStream output) {
// Just pick a figure
super(CAPACITY);
this.input = input;
@@ -69,7 +85,7 @@ class ByteBufAdapter extends AbstractByteBuf {
* @return A packet serializer with a wrapped byte buf adapter.
*/
public static ByteBuf packetReader(DataInputStream input) {
return MinecraftReflection.getPacketDataSerializer(new ByteBufAdapter(input, null));
return (ByteBuf) MinecraftReflection.getPacketDataSerializer(new NettyByteBufAdapter(input, null));
}
/**
@@ -78,7 +94,7 @@ class ByteBufAdapter extends AbstractByteBuf {
* @return A packet serializer with a wrapped byte buf adapter.
*/
public static ByteBuf packetWriter(DataOutputStream output) {
return MinecraftReflection.getPacketDataSerializer(new ByteBufAdapter(null, output));
return (ByteBuf) MinecraftReflection.getPacketDataSerializer(new NettyByteBufAdapter(null, output));
}
@Override
@@ -250,13 +266,13 @@ class ByteBufAdapter extends AbstractByteBuf {
@Override
public ByteBuf getBytes(int index, OutputStream dst, int length) throws IOException {
ByteStreams.copy(new LimitInputStream(input, length), dst);
ByteStreams.copy(ByteStreams.limit(input, length), dst);
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
byte[] data = ByteStreams.toByteArray(new LimitInputStream(input, length));
byte[] data = ByteStreams.toByteArray(ByteStreams.limit(input, length));
out.write(ByteBuffer.wrap(data));
return data.length;
@@ -299,7 +315,7 @@ class ByteBufAdapter extends AbstractByteBuf {
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
LimitInputStream limit = new LimitInputStream(in, length);
InputStream limit = ByteStreams.limit(in, length);
ByteStreams.copy(limit, output);
return length - limit.available();
}
@@ -373,4 +389,4 @@ class ByteBufAdapter extends AbstractByteBuf {
public ByteBuf retain() {
return this;
}
}
}
@@ -0,0 +1,104 @@
/**
* 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.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
}
}
}
}
@@ -3,18 +3,15 @@ package com.comphenix.protocol.injector.netty;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -23,18 +20,21 @@ import com.google.common.collect.Sets;
* @author Kristian
*/
// TODO: Handle modifications to the BiMap
public class NettyProtocolRegistry {
public abstract class ProtocolRegistry {
/**
* Represents a register we are currently building.
* @author Kristian
*/
private static class Register {
protected static class Register {
// The main lookup table
public BiMap<PacketType, Class<?>> typeToClass = HashBiMap.create();
public volatile Set<PacketType> serverPackets = Sets.newHashSet();
public volatile Set<PacketType> clientPackets = Sets.newHashSet();
public List<MapContainer> containers = Lists.newArrayList();
public Register() {
}
/**
* Determine if the current register is outdated.
* @return TRUE if it is, FALSE otherwise.
@@ -49,12 +49,12 @@ public class NettyProtocolRegistry {
}
}
private Class<?> enumProtocol;
protected Class<?> enumProtocol;
// Current register
private volatile Register register;
protected volatile Register register;
public NettyProtocolRegistry() {
public ProtocolRegistry() {
enumProtocol = MinecraftReflection.getEnumProtocolClass();
initialize();
}
@@ -106,70 +106,20 @@ public class NettyProtocolRegistry {
/**
* Load the packet lookup tables in each protocol.
*/
private synchronized 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;
}
private 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(), PacketType.UNKNOWN_PACKET);
register.typeToClass.put(type, entry.getValue());
if (sender == Sender.SERVER)
register.serverPackets.add(type);
if (sender == Sender.CLIENT)
register.clientPackets.add(type);
}
}
protected abstract void initialize();
protected abstract void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender);
/**
* Retrieve the number of mapping in all the maps.
* @param maps - iterable of maps.
* @return The sum of all the entries.
*/
private int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
protected final int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
int count = 0;
for (Map<Integer, Class<?>> map : maps)
for (Map<Integer, Class<?>> map : maps)
count += map.size();
return count;
}
}
}
@@ -0,0 +1,55 @@
/**
* 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 io.netty.buffer.ByteBuf;
/**
* @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(ByteBuf output) {
int i = id;
while ((i & -128) != 0) {
output.writeByte(i & 127 | 128);
i >>>= 7;
}
output.writeByte(i);
}
public void writeBytes(ByteBuf output) {
output.writeBytes(bytes);
}
}
@@ -1,7 +1,5 @@
package com.comphenix.protocol.injector.packet;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Field;
import com.comphenix.protocol.reflect.FieldUtils;
@@ -12,20 +10,17 @@ import com.comphenix.protocol.reflect.FieldUtils;
*/
public class MapContainer {
// For detecting changes
private final Field modCountField;
private Field modCountField;
private int lastModCount;
// The object along with whether or not this is the initial run
private final Object source;
private Object source;
private boolean changed;
public MapContainer(Object source) {
this.source = source;
this.changed = false;
Field modCountField = FieldUtils.getField(source.getClass(), "modCount", true);
this.modCountField = checkNotNull(modCountField, "Failed to obtain modCount field");
this.lastModCount = getModificationCount();
this.changed = true;
this.modCountField = FieldUtils.getField(source.getClass(), "modCount", true);
}
/**
@@ -60,13 +55,13 @@ public class MapContainer {
/**
* Retrieve the current modification count.
* @return The current count
* @return The current count, or something different than lastModCount if not accessible.
*/
private int getModificationCount() {
try {
return modCountField.getInt(source);
} catch (Exception ex) {
throw new RuntimeException("Unable to retrieve modCount.", ex);
return modCountField != null ? modCountField.getInt(source) : lastModCount + 1;
} catch (Exception e) {
throw new RuntimeException("Unable to retrieve modCount.", e);
}
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -24,14 +24,10 @@ import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.InsufficientPacketsException;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftReflection;
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;
@@ -48,13 +44,8 @@ public class PacketRegistry {
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;
private static volatile NettyProtocolRegistry NETTY;
// Cached for legacy
private static volatile Set<PacketType> NETTY_SERVER_PACKETS;
private static volatile Set<PacketType> NETTY_CLIENT_PACKETS;
private static volatile ProtocolRegistry NETTY;
// Cached for Netty
private static volatile Set<Integer> LEGACY_SERVER_PACKETS;
private static volatile Set<Integer> LEGACY_CLIENT_PACKETS;
@@ -69,21 +60,15 @@ public class PacketRegistry {
private static void initialize() {
if (INITIALIZED) {
// Make sure they were initialized
if (NETTY == null && LEGACY == null)
if (NETTY == null)
throw new IllegalStateException("No initialized registry.");
return;
}
// Check for netty
if (MinecraftReflection.isUsingNetty()) {
if (NETTY == null) {
NETTY = new NettyProtocolRegistry();
}
} else {
initializeLegacy();
}
NETTY = new NettyProtocolRegistry();
}
/**
* Determine if the given packet type is supported on the current server.
* @param type - the type to check.
@@ -91,41 +76,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>
@@ -135,36 +88,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>() {
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>() {
public PacketType apply(Integer packetId) {
return PacketType.findLegacy(packetId);
};
});
@SuppressWarnings("unchecked")
Map<Class, PacketType> result = (Map) NETTY.getPacketClassLookup();
return result;
}
/**
@@ -176,12 +122,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.
@@ -189,22 +132,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>
@@ -215,14 +155,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(NETTY.getServerPackets());
}
return LEGACY.getServerPackets();
return LEGACY_SERVER_PACKETS;
}
/**
@@ -231,17 +168,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();
}
/**
@@ -254,14 +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(NETTY.getClientPackets());
}
return LEGACY.getClientPackets();
return LEGACY_CLIENT_PACKETS;
}
/**
@@ -270,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();
}
/**
@@ -288,7 +206,7 @@ public class PacketRegistry {
* @param types - packet type.
* @return Set of integers.
*/
public static Set<Integer> toLegacy(Set<PacketType> types) {
public static Set<Integer> toLegacy(Set<PacketType> types) {
Set<Integer> result = Sets.newHashSet();
for (PacketType type : types)
@@ -298,20 +216,20 @@ public class PacketRegistry {
/**
* Convert a set of legacy packet IDs to packet types.
* @param types - legacy packet IDs.
* @param ids - legacy packet IDs.
* @return Set of packet types.
*/
public static Set<PacketType> toPacketTypes(Set<Integer> ids) {
public static Set<PacketType> toPacketTypes(Set<Integer> ids) {
return toPacketTypes(ids, null);
}
/**
* Convert a set of legacy packet IDs to packet types.
* @param types - legacy packet IDs.
* @param ids - legacy packet IDs.
* @param preference - the sender preference, if any.
* @return Set of packet types.
*/
public static Set<PacketType> toPacketTypes(Set<Integer> ids, Sender preference) {
public static Set<PacketType> toPacketTypes(Set<Integer> ids, Sender preference) {
Set<PacketType> result = Sets.newHashSet();
for (int id : ids)
@@ -329,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));
}
/**
@@ -354,12 +269,9 @@ 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);
return NETTY.getPacketTypeLookup().get(type);
}
/**
* Retrieves the correct packet class from a given packet ID.
* <p>
@@ -371,12 +283,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>
@@ -388,12 +297,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.
@@ -411,14 +317,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);
}
}
}
@@ -14,7 +14,7 @@ import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor;
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
import com.google.common.collect.Lists;
public class ClassAnalyser {
public class ClassAnalyser {
/**
* Represents a method in ASM.
* <p>
@@ -68,7 +68,7 @@ public class ClassAnalyser {
/**
* Retrieve the associated owner class.
* @return The owner class.
* @throws ClassNotFoundException
* @throws ClassNotFoundException If the class was not found
*/
public Class<?> getOwnerClass() throws ClassNotFoundException {
return AsmMethod.class.getClassLoader().loadClass(getOwnerName().replace('/', '.'));
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -48,4 +48,10 @@ public class FieldAccessException extends RuntimeException {
public static FieldAccessException fromFormat(String message, Object... params) {
return new FieldAccessException(String.format(message, params));
}
@Override
public String toString() {
String message = getMessage();
return "FieldAccessException" + (message != null ? ": " + message : "");
}
}
@@ -270,7 +270,7 @@ public class FieldUtils {
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readField(Field field, Object target, boolean forceAccess) throws IllegalAccessException {
if (field == null)
if (field == null)
throw new IllegalArgumentException("The field must not be null");
if (forceAccess && !field.isAccessible()) {
@@ -394,6 +394,22 @@ public class FieldUtils {
writeStaticField(field, value);
}
public static void writeStaticFinalField(Class<?> clazz, String fieldName, Object value, boolean forceAccess) throws Exception {
Field field = getField(clazz, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " in " + clazz);
}
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.setAccessible(true);
field.set(null, value);
}
/**
* Write an accessible field.
*
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -93,6 +93,7 @@ public class FuzzyReflection {
/**
* Retrieve the value of the first field of the given type.
* @param <T> Type
* @param instance - the instance to retrieve from.
* @param fieldClass - type of the field to retrieve.
* @param forceAccess - whether or not to look for private and protected fields.
@@ -107,6 +108,7 @@ public class FuzzyReflection {
/**
* Retrieves the underlying class.
* @return The underlying class.
*/
public Class<?> getSource() {
return source;
@@ -117,7 +119,7 @@ public class FuzzyReflection {
* @return The singleton instance.
* @throws IllegalStateException If the class has no singleton.
*/
public Object getSingleton() {
public Object getSingleton() {
Method method = null;
Field field = null;
@@ -166,13 +168,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>
@@ -203,12 +234,12 @@ public class FuzzyReflection {
for (Method method : getMethods()) {
if (match.matcher(method.getName()).matches()) {
// Right - this is probably it.
// Right - this is probably it.
return method;
}
}
throw new IllegalArgumentException("Unable to find a method with the pattern " +
throw new IllegalArgumentException("Unable to find a method with the pattern " +
nameRegex + " in " + source.getName());
}
@@ -341,13 +372,13 @@ public class FuzzyReflection {
for (Field field : getFields()) {
if (match.matcher(field.getName()).matches()) {
// Right - this is probably it.
// Right - this is probably it.
return field;
}
}
// Looks like we're outdated. Too bad.
throw new IllegalArgumentException("Unable to find a field with the pattern " +
throw new IllegalArgumentException("Unable to find a field with the pattern " +
nameRegex + " in " + source.getName());
}
@@ -428,7 +459,7 @@ public class FuzzyReflection {
/**
* Retrieves a field by type.
* <p>
* Note that the type is matched using the full canonical representation, i.e.:
* Note that the type is matched using the full canonical representation, i.e.:
* <ul>
* <li>java.util.List</li>
* <li>net.comphenix.xp.ExperienceMod</li>
@@ -451,14 +482,14 @@ public class FuzzyReflection {
}
// Looks like we're outdated. Too bad.
throw new IllegalArgumentException("Unable to find a field with the type " +
throw new IllegalArgumentException("Unable to find a field with the type " +
typeRegex + " in " + source.getName());
}
/**
* Retrieves a field by type.
* <p>
* Note that the type is matched using the full canonical representation, i.e.:
* Note that the type is matched using the full canonical representation, i.e.:
* <ul>
* <li>java.util.List</li>
* <li>net.comphenix.xp.ExperienceMod</li>
@@ -483,7 +514,7 @@ public class FuzzyReflection {
}
// Looks like we're outdated. Too bad.
throw new IllegalArgumentException("Unable to find a field with the type " +
throw new IllegalArgumentException("Unable to find a field with the type " +
typeRegex + " in " + source.getName());
}
@@ -505,7 +536,7 @@ public class FuzzyReflection {
}
/**
* Retrieve every method as a map over names.
* Retrieve every method as a map over names.
* <p>
* Note that overloaded methods will only occur once in the resulting map.
* @param methods - every method.
@@ -600,6 +631,8 @@ public class FuzzyReflection {
}
// Prevent duplicate fields
@SafeVarargs
private static <T> Set<T> setUnion(T[]... array) {
Set<T> result = new LinkedHashSet<T>();
Loaded 100 of 341 files, more files were not shown because too many files have changed in this diff. Show more